mirror of
https://github.com/ThisTine/Snip.git
synced 2026-10-18 02:51:38 +07:00
feat: redesign UI and UX around design-engineering principles
- Ink-first palette, drop gradients/glow; tabular numbers
- Home: form stays put, results stack below and auto-copy; paste shortens instantly
- Hold-to-delete replaces the delete confirm modal
- Copy buttons morph to a check instead of toasting
- Motion: CSS press feedback, custom ease-out, origin-aware menu, faster exits,
no animation on frequent/keyboard actions, reduced-motion respected
- Fix: scheme-less URLs ("example.com") were blocked by native validation
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
e2327207e5
commit
2e1133e39c
25 files changed
+753
-814
No files matched your search
+11
-19
@@ -1,4 +1,3 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useState } from "react";
|
||||
import type { DayCount } from "../lib/types";
|
||||
import { weekdayLabel } from "../lib/format";
|
||||
@@ -8,6 +7,8 @@ interface Props {
|
||||
height?: number;
|
||||
}
|
||||
|
||||
// ponytail: no grow-in animation — this renders on every dashboard page view,
|
||||
// and motion seen tens of times a day just reads as lag.
|
||||
export function BarChart({ data, height = 84 }: Props) {
|
||||
const [hover, setHover] = useState<number | null>(null);
|
||||
const max = Math.max(1, ...data.map((d) => d.count));
|
||||
@@ -20,28 +21,19 @@ export function BarChart({ data, height = 84 }: Props) {
|
||||
return (
|
||||
<div
|
||||
key={d.date}
|
||||
className="group relative flex h-full flex-1 flex-col items-center justify-end gap-1.5"
|
||||
className="relative flex h-full flex-1 flex-col items-center justify-end gap-1.5"
|
||||
onMouseEnter={() => setHover(i)}
|
||||
onMouseLeave={() => setHover(null)}
|
||||
>
|
||||
<motion.div
|
||||
initial={false}
|
||||
animate={{ opacity: active ? 1 : 0, y: active ? 0 : 4 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
className="pointer-events-none absolute -top-1 z-10 -translate-y-full whitespace-nowrap rounded-md bg-[var(--ink)] px-2 py-1 text-[11px] font-medium text-[var(--bg)]"
|
||||
>
|
||||
{d.count} clicks
|
||||
</motion.div>
|
||||
|
||||
{active && (
|
||||
<div className="pointer-events-none absolute -top-1 z-10 -translate-y-full whitespace-nowrap rounded-md bg-[var(--ink)] px-2 py-1 text-[11px] font-medium tabular-nums text-[var(--bg)]">
|
||||
{d.count} {d.count === 1 ? "click" : "clicks"}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex w-full flex-1 items-end">
|
||||
<motion.div
|
||||
initial={{ height: 0 }}
|
||||
animate={{ height: `${Math.max(ratio * 100, 4)}%` }}
|
||||
transition={{ duration: 0.4, ease: "easeOut", delay: i * 0.04 }}
|
||||
className={`w-full rounded-sm transition-colors ${
|
||||
active ? "bg-[var(--ink)]" : "bg-[var(--ring)]"
|
||||
}`}
|
||||
style={{ minHeight: 3 }}
|
||||
<div
|
||||
className={`w-full rounded-[3px] ${active ? "bg-[var(--ink)]" : "bg-[var(--ring)]"}`}
|
||||
style={{ height: `${Math.max(ratio * 100, 4)}%`, minHeight: 3 }}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-[10px] text-muted">{weekdayLabel(d.date)}</span>
|
||||
|
||||
Reference in new issue
Block a user