'use client'; import { useState, useRef, useEffect } from 'react'; import { useThemeStore } from '@/stores/theme-store'; import { SettingsSection, SettingItem } from './settings-section'; import { cn } from '@/lib/utils'; import { Upload, Trash2, Check, Palette } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { toast } from '@/stores/toast-store'; import type { InstalledTheme } from '@/lib/plugin-types'; import { usePolicyStore } from '@/stores/policy-store'; export function ThemesSettings() { const { installedThemes, activeThemeId, installTheme, uninstallTheme, activateTheme } = useThemeStore(); const [isUploading, setIsUploading] = useState(false); const fileInputRef = useRef(null); const { isFeatureEnabled, isThemeDisabled, getThemePolicy } = usePolicyStore(); const canUpload = isFeatureEnabled('userThemesEnabled'); const themePolicy = getThemePolicy(); // Filter out themes disabled by admin policy const visibleThemes = installedThemes.filter( theme => !isThemeDisabled(theme.id, !!theme.builtIn) ); // If the active theme was disabled by admin, fall back to default useEffect(() => { if (activeThemeId) { const activeTheme = installedThemes.find(t => t.id === activeThemeId); if (activeTheme && isThemeDisabled(activeThemeId, !!activeTheme.builtIn)) { activateTheme(null); } } }, [activeThemeId, installedThemes, isThemeDisabled, activateTheme]); const handleUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setIsUploading(true); try { const result = await installTheme(file); if (result.success) { toast.success('Theme installed'); if (result.warnings?.length) { toast.warning('Theme warnings', { message: result.warnings.join('\n') }); } } else { toast.error('Theme installation failed', { message: result.error }); } } catch (err) { toast.error('Theme installation failed', { message: err instanceof Error ? err.message : 'Unknown error' }); } finally { setIsUploading(false); // Reset file input if (fileInputRef.current) fileInputRef.current.value = ''; } }; const handleActivate = (id: string | null) => { activateTheme(id); toast.success(id ? 'Theme activated' : 'Default theme restored'); }; const handleUninstall = (theme: InstalledTheme) => { if (theme.builtIn) return; uninstallTheme(theme.id); toast.success('Theme removed'); }; return ( {/* Theme Grid */}
{/* Default theme card */} handleActivate(null)} /> {/* Installed themes */} {visibleThemes.map(theme => ( handleActivate(theme.id)} onRemove={!theme.builtIn ? () => handleUninstall(theme) : undefined} /> ))}
{/* Upload */} {canUpload && ( )}
); } // ─── Theme Card ────────────────────────────────────────────── interface ThemeCardProps { name: string; author: string; preview?: string; isActive: boolean; isBuiltIn: boolean; isDefault?: boolean; variants?: ('light' | 'dark')[]; onActivate: () => void; onRemove?: () => void; } function ThemeCard({ name, author, preview, isActive, isDefault, variants, onActivate, onRemove }: ThemeCardProps) { return ( )} ); }