183 lines
5.3 KiB
TypeScript
183 lines
5.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
import TabNavigation from '../../components/ui/TabNavigation';
|
|
import AppearanceSettings from '../../components/settings/AppearanceSettings';
|
|
import ContentSettings from '../../components/settings/ContentSettings';
|
|
import SystemSettings from '../../components/settings/SystemSettings';
|
|
import Button from '../../components/ui/Button';
|
|
import { useTheme } from '../../lib/theme';
|
|
|
|
type FontFamily = 'serif' | 'sans' | 'mono';
|
|
type FontSize = 'small' | 'medium' | 'large' | 'extra-large';
|
|
type ReadingWidth = 'narrow' | 'medium' | 'wide';
|
|
|
|
interface Settings {
|
|
theme: 'light' | 'dark';
|
|
fontFamily: FontFamily;
|
|
fontSize: FontSize;
|
|
readingWidth: ReadingWidth;
|
|
readingSpeed: number; // words per minute
|
|
}
|
|
|
|
const defaultSettings: Settings = {
|
|
theme: 'light',
|
|
fontFamily: 'serif',
|
|
fontSize: 'medium',
|
|
readingWidth: 'medium',
|
|
readingSpeed: 200,
|
|
};
|
|
|
|
const tabs = [
|
|
{ id: 'appearance', label: 'Appearance', icon: '🎨' },
|
|
{ id: 'content', label: 'Content', icon: '🏷️' },
|
|
{ id: 'system', label: 'System', icon: '🔧' },
|
|
];
|
|
|
|
export default function SettingsContent() {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
const { theme, setTheme } = useTheme();
|
|
const [settings, setSettings] = useState<Settings>(defaultSettings);
|
|
const [saved, setSaved] = useState(false);
|
|
const [activeTab, setActiveTab] = useState('appearance');
|
|
|
|
// Initialize tab from URL parameter
|
|
useEffect(() => {
|
|
const tabFromUrl = searchParams.get('tab');
|
|
if (tabFromUrl && tabs.some(tab => tab.id === tabFromUrl)) {
|
|
setActiveTab(tabFromUrl);
|
|
}
|
|
}, [searchParams]);
|
|
|
|
// Load settings from localStorage on mount
|
|
useEffect(() => {
|
|
const savedSettings = localStorage.getItem('storycove-settings');
|
|
if (savedSettings) {
|
|
try {
|
|
const parsed = JSON.parse(savedSettings);
|
|
setSettings({ ...defaultSettings, ...parsed, theme });
|
|
} catch (error) {
|
|
console.error('Failed to parse saved settings:', error);
|
|
setSettings({ ...defaultSettings, theme });
|
|
}
|
|
} else {
|
|
setSettings({ ...defaultSettings, theme });
|
|
}
|
|
}, [theme]);
|
|
|
|
// Update URL when tab changes
|
|
const handleTabChange = (tabId: string) => {
|
|
setActiveTab(tabId);
|
|
const newUrl = `/settings?tab=${tabId}`;
|
|
router.replace(newUrl, { scroll: false });
|
|
};
|
|
|
|
// Save settings to localStorage
|
|
const saveSettings = () => {
|
|
localStorage.setItem('storycove-settings', JSON.stringify(settings));
|
|
|
|
// Apply theme change
|
|
setTheme(settings.theme);
|
|
|
|
// Apply font settings to CSS custom properties
|
|
const root = document.documentElement;
|
|
|
|
const fontFamilyMap = {
|
|
serif: 'Georgia, Times, serif',
|
|
sans: 'Inter, system-ui, sans-serif',
|
|
mono: 'Monaco, Consolas, monospace',
|
|
};
|
|
|
|
const fontSizeMap = {
|
|
small: '14px',
|
|
medium: '16px',
|
|
large: '18px',
|
|
'extra-large': '20px',
|
|
};
|
|
|
|
const readingWidthMap = {
|
|
narrow: '600px',
|
|
medium: '800px',
|
|
wide: '1000px',
|
|
};
|
|
|
|
root.style.setProperty('--reading-font-family', fontFamilyMap[settings.fontFamily]);
|
|
root.style.setProperty('--reading-font-size', fontSizeMap[settings.fontSize]);
|
|
root.style.setProperty('--reading-max-width', readingWidthMap[settings.readingWidth]);
|
|
|
|
setSaved(true);
|
|
setTimeout(() => setSaved(false), 2000);
|
|
};
|
|
|
|
const updateSetting = <K extends keyof Settings>(key: K, value: Settings[K]) => {
|
|
setSettings(prev => ({ ...prev, [key]: value }));
|
|
};
|
|
|
|
const resetToDefaults = () => {
|
|
setSettings({ ...defaultSettings, theme });
|
|
};
|
|
|
|
const renderTabContent = () => {
|
|
switch (activeTab) {
|
|
case 'appearance':
|
|
return (
|
|
<AppearanceSettings
|
|
settings={settings}
|
|
onSettingChange={updateSetting}
|
|
/>
|
|
);
|
|
case 'content':
|
|
return <ContentSettings />;
|
|
case 'system':
|
|
return <SystemSettings />;
|
|
default:
|
|
return <AppearanceSettings settings={settings} onSettingChange={updateSetting} />;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="max-w-4xl mx-auto space-y-6">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-3xl font-bold theme-header">Settings</h1>
|
|
<p className="theme-text mt-2">
|
|
Customize your StoryCove experience and manage system settings
|
|
</p>
|
|
</div>
|
|
|
|
{/* Tab Navigation */}
|
|
<TabNavigation
|
|
tabs={tabs}
|
|
activeTab={activeTab}
|
|
onTabChange={handleTabChange}
|
|
className="mb-6"
|
|
/>
|
|
|
|
{/* Tab Content */}
|
|
<div className="min-h-[400px]">
|
|
{renderTabContent()}
|
|
</div>
|
|
|
|
{/* Save Actions - Only show for Appearance tab */}
|
|
{activeTab === 'appearance' && (
|
|
<div className="flex justify-end gap-4 pt-6 border-t theme-border">
|
|
<Button
|
|
variant="ghost"
|
|
onClick={resetToDefaults}
|
|
>
|
|
Reset to Defaults
|
|
</Button>
|
|
|
|
<Button
|
|
onClick={saveSettings}
|
|
className={saved ? 'bg-green-600 hover:bg-green-700' : ''}
|
|
>
|
|
{saved ? '✓ Saved!' : 'Save Settings'}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |