fix(web): preset cards use the design-system animated Card (motion + material)
The preset options were raw <button>s — flat, no motion/material — unlike the rest of the console. They now render as the `interactive` AnimatedCard (motion hover + specular material, consistent with every other card), keyboard-accessible (role=button + Enter/ Space), with a 2px primary ring for the active one and a proper disabled state for gaming-rig. web tsc + vite build + biome-lint green; deployed on .21. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ import { Badge } from "@/components/ui/badge";
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
import { m } from "@/paraglide/messages";
|
import { m } from "@/paraglide/messages";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -162,20 +163,30 @@ const DisplayForm: FC<{
|
|||||||
const summary = id === "custom" ? m.display_custom_desc() : p?.summary;
|
const summary = id === "custom" ? m.display_custom_desc() : p?.summary;
|
||||||
const selected = preset === id;
|
const selected = preset === id;
|
||||||
const soon = DISABLED_PRESETS.has(id);
|
const soon = DISABLED_PRESETS.has(id);
|
||||||
const cls = [
|
const disabled = busy || soon;
|
||||||
"flex h-full flex-col rounded-lg border p-4 text-left transition-colors",
|
const pick = () => {
|
||||||
selected
|
if (!disabled) pickPreset(id);
|
||||||
? "border-primary ring-1 ring-primary"
|
};
|
||||||
: "hover:border-primary/40 hover:bg-muted/50",
|
|
||||||
soon ? "opacity-60" : "",
|
|
||||||
].join(" ");
|
|
||||||
return (
|
return (
|
||||||
<button
|
<Card
|
||||||
key={id}
|
key={id}
|
||||||
type="button"
|
interactive
|
||||||
disabled={busy || soon}
|
role="button"
|
||||||
onClick={() => pickPreset(id)}
|
tabIndex={disabled ? -1 : 0}
|
||||||
className={cls}
|
aria-pressed={selected}
|
||||||
|
aria-disabled={disabled || undefined}
|
||||||
|
onClick={pick}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" || e.key === " ") {
|
||||||
|
e.preventDefault();
|
||||||
|
pick();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"flex h-full flex-col p-4",
|
||||||
|
disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer",
|
||||||
|
selected && "ring-2 ring-primary",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<span className="text-base font-semibold">
|
<span className="text-base font-semibold">
|
||||||
@@ -201,7 +212,7 @@ const DisplayForm: FC<{
|
|||||||
<Badge variant="outline">{tr(IDENTITY_LABEL, fields.identity)}</Badge>
|
<Badge variant="outline">{tr(IDENTITY_LABEL, fields.identity)}</Badge>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</button>
|
</Card>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user