nexus/ui/src/components/ThemePreviewPanel.tsx

129 lines
3.8 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import type { PaletteRole } from "./ThemePaletteGrid";
const ROLE_TO_TOKEN: Record<string, string> = {
background: "--background",
surface: "--card",
overlay: "--secondary",
text: "--foreground",
"accent-1": "--primary",
"accent-2": "--accent",
"accent-3": "--muted",
};
interface ThemePreviewPanelProps {
palette: PaletteRole[];
variant: "dark" | "light";
className?: string;
}
export function ThemePreviewPanel({
palette,
variant,
className,
}: ThemePreviewPanelProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [announcement, setAnnouncement] = useState("");
useEffect(() => {
const container = containerRef.current;
if (!container || palette.length === 0) return;
palette.forEach((role) => {
const tokenName = ROLE_TO_TOKEN[role.name];
if (!tokenName) return;
const value = variant === "dark" ? role.dark.hex : role.light.hex;
container.style.setProperty(tokenName, value);
});
setAnnouncement("Palette updated");
}, [palette, variant]);
return (
<div
ref={containerRef}
className={`nexus-theme-preview relative rounded-lg border border-[var(--border,hsl(var(--border)))] overflow-hidden${className ? ` ${className}` : ""}`}
aria-label="Theme preview"
style={{ backgroundColor: "var(--background, #1e1e2e)" }}
>
{/* Visually hidden aria-live announcer */}
<div
aria-live="polite"
aria-atomic="true"
className="sr-only"
>
{announcement}
</div>
{/* Mini Nexus UI mock */}
<div className="flex h-40">
{/* Narrow sidebar strip */}
<div
className="flex flex-col items-center gap-2 py-3 px-2"
style={{
width: 48,
backgroundColor: "var(--card, #181825)",
borderRight: "1px solid var(--border, #313244)",
}}
>
<div
className="h-5 w-5 rounded"
style={{ backgroundColor: "var(--primary, #89b4fa)" }}
/>
<div
className="h-4 w-4 rounded opacity-60"
style={{ backgroundColor: "var(--muted, #313244)" }}
/>
<div
className="h-4 w-4 rounded opacity-60"
style={{ backgroundColor: "var(--muted, #313244)" }}
/>
</div>
{/* Main content area */}
<div
className="flex-1 p-3"
style={{ backgroundColor: "var(--background, #1e1e2e)" }}
>
<Card
className="p-3 h-full"
style={{
backgroundColor: "var(--card, #181825)",
color: "var(--foreground, #cdd6f4)",
border: "1px solid var(--border, #313244)",
}}
>
<div className="flex flex-col gap-2 h-full">
<div
className="h-3 w-3/4 rounded"
style={{ backgroundColor: "var(--foreground, #cdd6f4)", opacity: 0.7 }}
/>
<div
className="h-2 w-full rounded"
style={{ backgroundColor: "var(--muted, #313244)" }}
/>
<div
className="h-2 w-2/3 rounded"
style={{ backgroundColor: "var(--muted, #313244)" }}
/>
<div className="mt-auto">
<Button
size="xs"
style={{
backgroundColor: "var(--primary, #89b4fa)",
color: "var(--primary-foreground, #1e1e2e)",
}}
className="border-0"
>
Action
</Button>
</div>
</div>
</Card>
</div>
</div>
</div>
);
}