"use client";
import { useState, useCallback } from "react";
import type { ReactElement } from "react";
import Link from "next/link";
import { useTheme } from "@/providers/ThemeProvider";
import { getAllThemes, type ThemeDefinition } from "@/themes";
import { apiPatch } from "@/lib/api/client";
function ThemeCard({
theme,
isActive,
onSelect,
}: {
theme: ThemeDefinition;
isActive: boolean;
onSelect: () => void;
}): ReactElement {
const [hovered, setHovered] = useState(false);
return (
);
}
function SystemThemeCard({
isActive,
onSelect,
}: {
isActive: boolean;
onSelect: () => void;
}): ReactElement {
const [hovered, setHovered] = useState(false);
return (
);
}
export default function AppearanceSettingsPage(): ReactElement {
const { theme: preference, setTheme: setLocalTheme } = useTheme();
const [saving, setSaving] = useState(false);
const allThemes = getAllThemes();
const handleThemeSelect = useCallback(
async (themeId: string) => {
setLocalTheme(themeId);
setSaving(true);
try {
await apiPatch("/users/me/preferences", { theme: themeId });
} catch {
// Theme is still applied locally even if API save fails
} finally {
setSaving(false);
}
},
[setLocalTheme]
);
return (
{/* Breadcrumb */}
Settings
/
Appearance
{/* Page header */}
Appearance
Choose a theme for the Mosaic interface
{saving && (
Saving...
)}
{/* Theme grid */}
{/* System option first */}
void handleThemeSelect("system")}
/>
{/* All registered themes */}
{allThemes.map((t) => (
void handleThemeSelect(t.id)}
/>
))}
);
}