feat: tema ayarları Appwrite user prefs ile kalıcı hale getirildi

- saveThemePrefsAction: account.updatePrefs ile mevcut prefs merge edilir
- Dashboard layout'ta account.getPrefs ile prefs server-side yüklenir
- PrefsInitializer: mount'ta dark/light, renk teması, radius, sidebar config Appwrite'dan uygulanır
- ThemeCustomizer: renk/tweakcn/radius değişikliği anında Appwrite'a kaydedilir; dark/light toggle useEffect ile izlenir
- Sayfa yenileme ve farklı cihazda giriş sonrasında ayarlar korunur
This commit is contained in:
kovakmedya
2026-05-07 22:26:40 +03:00
parent 78f50755ed
commit 997cc393af
5 changed files with 136 additions and 19 deletions
@@ -0,0 +1,51 @@
"use client";
import { useEffect, useRef } from "react";
import { useSidebarConfig } from "@/contexts/sidebar-context";
import { useTheme } from "@/hooks/use-theme";
import { useThemeManager } from "@/hooks/use-theme-manager";
import { tweakcnThemes } from "@/config/theme-data";
import type { ThemePrefs } from "@/lib/appwrite/theme-prefs-actions";
export function PrefsInitializer({ prefs }: { prefs: ThemePrefs }) {
const { setTheme } = useTheme();
const { updateConfig } = useSidebarConfig();
const { applyTheme, applyTweakcnTheme, applyRadius } = useThemeManager();
const applied = useRef(false);
useEffect(() => {
if (applied.current) return;
applied.current = true;
if (prefs.theme) setTheme(prefs.theme);
const isDark =
prefs.theme === "dark" ||
(prefs.theme !== "light" &&
typeof window !== "undefined" &&
window.matchMedia("(prefers-color-scheme: dark)").matches);
if (prefs.radius) applyRadius(prefs.radius);
if (prefs.colorTheme) {
applyTheme(prefs.colorTheme, isDark);
}
if (prefs.tweakcnTheme) {
const preset = tweakcnThemes.find((t) => t.value === prefs.tweakcnTheme)?.preset;
if (preset) applyTweakcnTheme(preset, isDark);
}
if (prefs.sidebarVariant || prefs.sidebarCollapsible || prefs.sidebarSide) {
updateConfig({
...(prefs.sidebarVariant && { variant: prefs.sidebarVariant }),
...(prefs.sidebarCollapsible && { collapsible: prefs.sidebarCollapsible }),
...(prefs.sidebarSide && { side: prefs.sidebarSide }),
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
}