feat(frontend): content micro-animations — stagger, button press, toast polish

- animate-stagger utility + staggerDelay() helper; lists now rise in sequence
  (recordings grid, moderation rows, message list, media queue, dashboard tiles).
- Button gets a subtle active:scale-[0.97] press feedback.
- Toaster: toast-in slide-up, tone-accent border, rounded hover-close target.
- All motion is reduced-motion aware (killed under prefers-reduced-motion).
This commit is contained in:
asepharyana
2026-08-18 11:01:00 +07:00
parent 0cb0b82fb1
commit 217ecc1aa1
10 changed files with 74 additions and 14 deletions
@@ -40,7 +40,7 @@ export const Button = ({
return (
<Comp
className={cn(
"inline-flex items-center justify-center whitespace-nowrap transition-all duration-150 select-none",
"inline-flex items-center justify-center whitespace-nowrap transition-all duration-150 select-none active:scale-[0.97]",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-signal/60 disabled:opacity-40 disabled:pointer-events-none",
variants[variant],
sizes[size],
@@ -74,8 +74,11 @@ export function Toaster({ position = "bottom-right" }: { position?: string }) {
return (
<div
key={t.id}
className="glass pointer-events-auto flex items-start gap-3 p-3.5"
style={{ animation: "fade-up 0.18s ease" }}
className={cn(
"glass animate-toast-in pointer-events-auto flex items-start gap-3 p-3.5 transition-colors",
t.tone === "signal" && "border-signal/30",
t.tone === "vermilion" && "border-vermilion/30",
)}
>
<Icon
className={cn(
@@ -95,11 +98,12 @@ export function Toaster({ position = "bottom-right" }: { position?: string }) {
</div>
<button
type="button"
aria-label="Dismiss"
onClick={() => {
store = store.filter((x) => x.id !== t.id);
emit();
}}
className="text-ink-faint hover:text-ink"
className="rounded-md p-1 text-ink-faint transition-colors hover:bg-white/8 hover:text-ink"
>
<X className="size-3.5" />
</button>
@@ -37,6 +37,7 @@ export function MetricTile({
spark,
icon,
className,
style,
}: {
label: string;
value: React.ReactNode;
@@ -45,6 +46,7 @@ export function MetricTile({
spark?: number[];
icon?: React.ReactNode;
className?: string;
style?: React.CSSProperties;
}) {
const toneColor =
tone === "vermilion"
@@ -60,6 +62,7 @@ export function MetricTile({
"glass p-4 ring-focus transition-transform duration-200 hover:-translate-y-0.5",
className,
)}
style={style}
>
<div className="flex items-center justify-between">
<div className="eyebrow">{label}</div>