feat: add settings dialog with theme selection
This commit is contained in:
86
src/components/settings/SettingsDialog.tsx
Normal file
86
src/components/settings/SettingsDialog.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { Sun, Moon, Monitor } from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAppStore } from "@/stores/app-store";
|
||||
import type { AppSettings } from "@/types/settings";
|
||||
|
||||
interface SettingsDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const THEME_OPTIONS: {
|
||||
value: AppSettings["theme"];
|
||||
label: string;
|
||||
icon: typeof Sun;
|
||||
}[] = [
|
||||
{ value: "light", label: "Light", icon: Sun },
|
||||
{ value: "dark", label: "Dark", icon: Moon },
|
||||
{ value: "system", label: "System", icon: Monitor },
|
||||
];
|
||||
|
||||
export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
|
||||
const theme = useAppStore((s) => s.settings.theme);
|
||||
const setTheme = useAppStore((s) => s.setTheme);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="bg-pylon-surface sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="font-heading text-pylon-text">
|
||||
Settings
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-pylon-text-secondary">
|
||||
Configure your OpenPylon preferences.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="flex flex-col gap-5">
|
||||
{/* Theme section */}
|
||||
<div>
|
||||
<label className="mb-2 block font-mono text-xs font-semibold uppercase tracking-widest text-pylon-text-secondary">
|
||||
Theme
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
{THEME_OPTIONS.map(({ value, label, icon: Icon }) => (
|
||||
<Button
|
||||
key={value}
|
||||
type="button"
|
||||
variant={theme === value ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => setTheme(value)}
|
||||
className="flex-1 gap-2"
|
||||
>
|
||||
<Icon className="size-4" />
|
||||
{label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* About section */}
|
||||
<div>
|
||||
<label className="mb-2 block font-mono text-xs font-semibold uppercase tracking-widest text-pylon-text-secondary">
|
||||
About
|
||||
</label>
|
||||
<div className="space-y-1 text-sm text-pylon-text">
|
||||
<p className="font-semibold">OpenPylon v0.1.0</p>
|
||||
<p className="text-pylon-text-secondary">
|
||||
Local-first Kanban board
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user