feat(frontend): slice 2 — migrate 11 shared components to shadcn/Tailwind

Web UI rework. Shared-components slice (drift prevention):
- Migrate SectionCard, SelectionRailCard, TabbedCard, MetricCard,
  DiskSpaceCard, HoverEditButton, DialogFooter, ConfirmDialog,
  LibraryOverview, NowPlaying, SessionActivityPanel off @mui
- HoverEditButton: MUI IconButton + EditOutlined -> Button + lucide Pencil
- Status mapping uses the success Badge variant (chart-2) for healthy
- Exported APIs preserved so consuming pages still compile (no page edits)
- 11 behavioral Vitest component tests added

Gate: build + lint + test green.
This commit is contained in:
Developer
2026-06-17 12:33:47 +00:00
parent dd778d8850
commit 109e74db41
23 changed files with 830 additions and 469 deletions
+41 -16
View File
@@ -1,5 +1,5 @@
import type { ReactNode } from "react";
import { Box, Button, DialogActions } from "@mui/material";
import { Button } from "@/components/ui/button";
interface DialogFooterProps {
onCancel: () => void;
@@ -14,6 +14,28 @@ interface DialogFooterProps {
secondaryAction?: ReactNode;
}
/**
* Resolve the legacy MUI color/variant props onto a shadcn Button variant so
* the exported API stays unchanged for consuming pages (ConfirmDialog here,
* plus Dashboard/Settings/Actions in later slices).
*/
function resolveConfirmVariant(
color: DialogFooterProps["confirmColor"],
variant: DialogFooterProps["confirmVariant"],
): "default" | "outline" | "ghost" | "destructive" {
if (color === "error") return "destructive";
if (variant === "outlined") return "outline";
if (variant === "text") return "ghost";
return "default";
}
/**
* Dialog action row: cancel + optional secondary action + confirm.
*
* Renders a horizontal Button row (`flex flex-row items-center gap-2`).
* Preserves cancel/confirm/secondary-action props and the busy/disabled label
* contract (renders `confirmBusyLabel` when provided, else `confirmLabel`).
*/
export function DialogFooter({
onCancel,
cancelLabel = "Cancel",
@@ -27,20 +49,23 @@ export function DialogFooter({
secondaryAction,
}: DialogFooterProps) {
return (
<DialogActions sx={{ px: 3, py: 2 }}>
<Button onClick={onCancel}>{cancelLabel}</Button>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
{secondaryAction}
<Button
variant={confirmVariant}
color={confirmColor}
disabled={confirmDisabled}
startIcon={confirmStartIcon}
onClick={onConfirm}
>
{confirmBusyLabel ?? confirmLabel}
</Button>
</Box>
</DialogActions>
<div className="flex flex-row flex-wrap items-center justify-end gap-2">
<Button variant="ghost" onClick={onCancel}>
{cancelLabel}
</Button>
{secondaryAction ? (
<div className="flex flex-row items-center gap-2">
{secondaryAction}
</div>
) : null}
<Button
variant={resolveConfirmVariant(confirmColor, confirmVariant)}
disabled={confirmDisabled}
onClick={onConfirm}
>
{confirmStartIcon}
{confirmBusyLabel ?? confirmLabel}
</Button>
</div>
);
}