feat: add settings dialog with theme selection

This commit is contained in:
Your Name
2026-02-15 19:13:13 +02:00
parent 5b3bf2b058
commit e9318df6f6
2 changed files with 107 additions and 2 deletions

View File

@@ -1,19 +1,37 @@
import { useEffect } from "react";
import { useState, useEffect, useCallback } from "react";
import { useAppStore } from "@/stores/app-store";
import { AppShell } from "@/components/layout/AppShell";
import { BoardList } from "@/components/boards/BoardList";
import { BoardView } from "@/components/board/BoardView";
import { CommandPalette } from "@/components/command-palette/CommandPalette";
import { SettingsDialog } from "@/components/settings/SettingsDialog";
export default function App() {
const initialized = useAppStore((s) => s.initialized);
const init = useAppStore((s) => s.init);
const view = useAppStore((s) => s.view);
const [settingsOpen, setSettingsOpen] = useState(false);
useEffect(() => {
init();
}, [init]);
// Listen for custom event to open settings from TopBar or command palette
useEffect(() => {
function handleOpenSettings() {
setSettingsOpen(true);
}
document.addEventListener("open-settings-dialog", handleOpenSettings);
return () => {
document.removeEventListener("open-settings-dialog", handleOpenSettings);
};
}, []);
const handleOpenSettings = useCallback(() => {
setSettingsOpen(true);
}, []);
if (!initialized) {
return (
<div className="flex h-screen items-center justify-center bg-pylon-bg">
@@ -29,7 +47,8 @@ export default function App() {
<AppShell>
{view.type === "board-list" ? <BoardList /> : <BoardView />}
</AppShell>
<CommandPalette onOpenSettings={() => {}} />
<CommandPalette onOpenSettings={handleOpenSettings} />
<SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} />
</>
);
}

View 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>
);
}