feat(e10): re-aim the Button variants at the paint the app actually uses, and migrate the first 15 sites

Counting the un-migrated call sites showed the primitive and the app had
drifted into two different looks: the majority of hand-rolled buttons
hover to accent (outline) and fill with card (ghost), while Button
hovered to fg and filled with surface. That split is the inconsistency
this epic exists to remove, so the primitive follows the majority rather
than the other way round -- 16 existing call sites shift slightly, ~90
hand-rolled ones stop being special.

Adds the variants the call sites prove are missing (outline-accent,
outline-danger, outline-warn, link), an icon-sm size for the p-1.5 icon
family, and a size=none so a link owns no button padding; renames
danger-outline to danger-soft so it cannot be confused with
outline-danger (red at rest vs red on hover). Two new tests lock the
link-size default and the rule that a variant never adds a second
font-weight utility -- without tailwind-merge, two font-* utilities are
decided by stylesheet order, not class order, so that is a real hazard.

Migrates AdminUsers, AuditLog, Channels, TagManager, Playlists,
PlaylistsRail and SettingsPanel (Button call sites 37 -> 52). Left alone
deliberately: conditional-paint sites, video-overlay white buttons, drag
handles, chip removers and card-click targets -- the families Button's
own docstring excludes.

3x tsc, eslint, knip, prettier and 689 vitest green; visual UAT on Users,
Access requests and Playlists at 1280x900, no console errors.
This commit is contained in:
2026-09-05 18:31:00 +02:00
parent 5bfcf5d83a
commit 29bb914a95
9 changed files with 154 additions and 86 deletions
+6 -4
View File
@@ -6,6 +6,7 @@ import { Trash2 } from "lucide-react";
import { api } from "../lib/api";
import { notify } from "../lib/notifications";
import { LS } from "../lib/storage";
import { Button } from "./ui/Button";
import { Section } from "./ui/form";
import { useConfirm } from "./ConfirmProvider";
import DataTable from "./ui/DataTable";
@@ -72,14 +73,15 @@ export default function AuditLog() {
persistKey={LS.auditTable}
controlsPosition="top"
controlsLeading={
<button
<Button
variant="outline-danger"
size="xs"
onClick={onClear}
disabled={clear.isPending}
className="inline-flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-lg border border-border text-muted hover:text-danger disabled:opacity-50 transition"
icon={<Trash2 className="w-3.5 h-3.5" />}
>
<Trash2 className="w-3.5 h-3.5" />
{t("audit.clear")}
</button>
</Button>
}
emptyText={t("audit.empty")}
/>