Files
famapp/src/components/theme-picker.tsx
T

209 lines
5.9 KiB
TypeScript

"use client";
import {
PALETTES,
THEME_MODES,
FONT_PAIRS,
DENSITIES,
DASH_LAYOUTS,
CAL_VIEWS,
NAV_STYLES,
} from "@/modules/_core/themes";
import type {
Palette,
ThemeMode,
FontPair,
Density,
DashLayout,
CalView,
NavStyle,
} from "@/modules/_core/themes";
import { useTheme } from "@/hooks/use-theme";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
interface Props {
initialPalette?: Palette;
initialMode?: ThemeMode;
initialFontPair?: FontPair;
initialDensity?: Density;
initialDashLayout?: DashLayout;
initialCalView?: CalView;
initialNavStyle?: NavStyle;
signedIn?: boolean;
}
export function ThemePicker({
initialPalette = "clay",
initialMode = "system",
initialFontPair = "serif-sans",
initialDensity = "regular",
initialDashLayout = "classic",
initialCalView = "month",
initialNavStyle = "rail-desktop",
signedIn = false,
}: Props) {
const t = useTheme(
{
palette: initialPalette,
mode: initialMode,
fontPair: initialFontPair,
density: initialDensity,
dashLayout: initialDashLayout,
calView: initialCalView,
navStyle: initialNavStyle,
},
signedIn,
);
return (
<div className="space-y-5">
<div className="space-y-1.5">
<Label>Theme</Label>
<Select value={t.palette} onValueChange={(v) => t.setPalette(v as Palette)}>
<SelectTrigger className="w-56">
<div className="flex items-center gap-2 min-w-0">
<span
className="inline-block w-5 h-4 rounded-sm shrink-0 overflow-hidden border-[0.5px]"
style={{
background: `linear-gradient(to bottom, ${
PALETTES.find((p) => p.id === t.palette)?.paper ?? "#fff"
} 55%, ${PALETTES.find((p) => p.id === t.palette)?.hex ?? "#888"} 55%)`,
borderColor: "var(--hair-2)",
}}
/>
<SelectValue />
</div>
</SelectTrigger>
<SelectContent>
{PALETTES.map((p) => (
<SelectItem key={p.id} value={p.id}>
<div className="flex items-center justify-between gap-6 w-40">
<span>{p.label}</span>
<span
className="inline-block w-5 h-4 rounded-sm shrink-0 overflow-hidden border-[0.5px]"
style={{
background: `linear-gradient(to bottom, ${p.paper} 55%, ${p.hex} 55%)`,
borderColor: "var(--hair-2)",
}}
/>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-1.5">
<Label>Mode</Label>
<div className="flex gap-1">
{THEME_MODES.map((m) => (
<Button
key={m.id}
variant="outline"
size="sm"
className={cn(t.mode === m.id && "bg-primary text-primary-foreground")}
onClick={() => t.setMode(m.id)}
>
{m.label}
</Button>
))}
</div>
</div>
<div className="space-y-1.5">
<Label>Type pairing</Label>
<Select value={t.fontPair} onValueChange={(v) => t.setFontPair(v as FontPair)}>
<SelectTrigger className="w-72">
<SelectValue />
</SelectTrigger>
<SelectContent>
{FONT_PAIRS.map((f) => (
<SelectItem key={f.id} value={f.id}>
{f.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-1.5">
<Label>Density</Label>
<div className="flex gap-1">
{DENSITIES.map((d) => (
<Button
key={d.id}
variant="outline"
size="sm"
className={cn(t.density === d.id && "bg-primary text-primary-foreground")}
onClick={() => t.setDensity(d.id)}
>
{d.label}
</Button>
))}
</div>
</div>
<div className="space-y-1.5">
<Label>Dashboard layout</Label>
<Select value={t.dashLayout} onValueChange={(v) => t.setDashLayout(v as DashLayout)}>
<SelectTrigger className="w-72">
<SelectValue />
</SelectTrigger>
<SelectContent>
{DASH_LAYOUTS.map((d) => (
<SelectItem key={d.id} value={d.id}>
{d.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-1.5">
<Label>Calendar default</Label>
<div className="flex gap-1">
{CAL_VIEWS.map((c) => (
<Button
key={c.id}
variant="outline"
size="sm"
className={cn(t.calView === c.id && "bg-primary text-primary-foreground")}
onClick={() => t.setCalView(c.id)}
>
{c.label}
</Button>
))}
</div>
</div>
<div className="space-y-1.5">
<Label>Navigation</Label>
<Select value={t.navStyle} onValueChange={(v) => t.setNavStyle(v as NavStyle)}>
<SelectTrigger className="w-72">
<SelectValue />
</SelectTrigger>
<SelectContent>
{NAV_STYLES.map((n) => (
<SelectItem key={n.id} value={n.id}>
{n.label}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-xs text-muted-foreground">
Mobile (under 760px) always uses bottom nav + FAB.
</p>
</div>
</div>
);
}