veza/apps/web/src/components/settings/appearance/AppearanceSettingsView.tsx

226 lines
8.3 KiB
TypeScript

import React, { useState } from 'react';
import { Card } from '../../ui/card';
import { Button } from '../../ui/button';
import { useTheme } from '../../../context/ThemeContext';
import { ThemeVariant } from '../../../types';
import {
Moon,
Sun,
Monitor,
Type,
Layout,
Grid,
Palette,
Check,
} from 'lucide-react';
import { useToast } from '../../../context/ToastContext';
import { Switch } from '../../ui/switch';
export const AppearanceSettingsView: React.FC = () => {
const { theme, setTheme } = useTheme();
const { addToast } = useToast();
const [density, setDensity] = useState<'comfortable' | 'compact' | 'cozy'>(
'comfortable',
);
const [fontSize, setFontSize] = useState(16);
const [accentColor, setAccentColor] = useState('cyan');
const [showSidebar, setShowSidebar] = useState(true);
const accents = [
{ id: 'cyan', hex: '#66FCF1' },
{ id: 'magenta', hex: '#8A7EA4' },
{ id: 'lime', hex: '#36E5D1' },
{ id: 'gold', hex: '#E4B314' },
{ id: 'red', hex: '#E63946' },
];
return (
<div className="space-y-8 animate-fadeIn max-w-4xl mx-auto pb-20">
{/* Header */}
<div className="flex justify-between items-end border-b border-kodo-steel/50 pb-6">
<div>
<h2 className="text-3xl font-display font-bold text-white mb-2">
INTERFACE
</h2>
<p className="text-gray-400 font-mono text-sm">
Customize your visual experience.
</p>
</div>
<Button
variant="primary"
onClick={() => addToast('Appearance settings saved', 'success')}
>
Save Changes
</Button>
</div>
{/* Theme Selection */}
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Palette className="w-5 h-5 text-kodo-cyan" /> Theme
</h3>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
{[
{
id: ThemeVariant.NEON,
label: 'Neon Dark',
icon: <Moon className="w-6 h-6" />,
},
{
id: ThemeVariant.LIGHT,
label: 'Light Mode',
icon: <Sun className="w-6 h-6" />,
},
{
id: ThemeVariant.GAMING,
label: 'High Contrast',
icon: <Monitor className="w-6 h-6" />,
},
].map((opt) => (
<div
key={opt.id}
onClick={() => setTheme(opt.id)}
className={`
cursor-pointer p-6 rounded-xl border-2 transition-all flex flex-col items-center gap-3 relative
${theme === opt.id ? 'border-kodo-cyan bg-kodo-cyan/5' : 'border-kodo-steel bg-kodo-ink hover:border-gray-500'}
`}
>
<div
className={`p-3 rounded-full ${theme === opt.id ? 'bg-kodo-cyan text-black' : 'bg-kodo-slate text-gray-400'}`}
>
{opt.icon}
</div>
<span
className={`font-bold ${theme === opt.id ? 'text-white' : 'text-gray-400'}`}
>
{opt.label}
</span>
{theme === opt.id && (
<div className="absolute top-2 right-2 text-kodo-cyan">
<Check className="w-4 h-4" />
</div>
)}
</div>
))}
</div>
</Card>
{/* Display Density */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Grid className="w-5 h-5 text-kodo-magenta" /> Density
</h3>
<div className="space-y-3">
{[
{
id: 'comfortable',
label: 'Comfortable',
desc: 'More whitespace for readability',
},
{ id: 'cozy', label: 'Cozy', desc: 'Balanced spacing' },
{ id: 'compact', label: 'Compact', desc: 'Maximum data density' },
].map((opt) => (
<div
key={opt.id}
onClick={() => setDensity(opt.id as any)}
className={`
flex items-center gap-4 p-3 rounded-lg border cursor-pointer transition-all
${density === opt.id ? 'bg-kodo-magenta/10 border-kodo-magenta' : 'bg-kodo-ink border-kodo-steel hover:bg-white/5'}
`}
>
<div
className={`w-4 h-4 rounded-full border-2 flex items-center justify-center ${density === opt.id ? 'border-kodo-magenta' : 'border-gray-500'}`}
>
{density === opt.id && (
<div className="w-2 h-2 rounded-full bg-kodo-magenta"></div>
)}
</div>
<div>
<div
className={`text-sm font-bold ${density === opt.id ? 'text-white' : 'text-gray-300'}`}
>
{opt.label}
</div>
<div className="text-xs text-gray-500">{opt.desc}</div>
</div>
</div>
))}
</div>
</Card>
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Type className="w-5 h-5 text-kodo-gold" /> Typography
</h3>
<div className="space-y-6">
<div>
<div className="flex justify-between text-sm text-gray-400 mb-2">
<span>Font Size</span>
<span>{fontSize}px</span>
</div>
<input
type="range"
min="12"
max="20"
value={fontSize}
onChange={(e) => setFontSize(Number(e.target.value))}
className="w-full h-2 bg-kodo-steel rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:bg-kodo-gold [&::-webkit-slider-thumb]:rounded-full"
/>
<div
className="mt-4 p-4 bg-kodo-ink rounded border border-kodo-steel text-gray-300"
style={{ fontSize: `${fontSize}px` }}
>
The quick brown fox jumps over the lazy dog.
</div>
</div>
</div>
</Card>
</div>
{/* Colors & Layout */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Palette className="w-5 h-5 text-kodo-lime" /> Accent Color
</h3>
<div className="flex gap-4">
{accents.map((col) => (
<div
key={col.id}
onClick={() => setAccentColor(col.id)}
className={`w-10 h-10 rounded-full cursor-pointer flex items-center justify-center transition-transform hover:scale-110 ring-2 ring-offset-2 ring-offset-kodo-void ${accentColor === col.id ? 'ring-white' : 'ring-transparent'}`}
style={{ backgroundColor: col.hex }}
>
{accentColor === col.id && (
<Check className="w-5 h-5 text-black" />
)}
</div>
))}
</div>
</Card>
<Card variant="default">
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
<Layout className="w-5 h-5 text-gray-400" /> Layout
</h3>
<div
className="flex items-center justify-between p-4 bg-kodo-ink rounded-lg border border-kodo-steel cursor-pointer hover:border-gray-500"
onClick={() => setShowSidebar(!showSidebar)}
>
<div>
<div className="text-sm font-bold text-white">Show Sidebar</div>
<div className="text-xs text-gray-400">
Toggle the main navigation sidebar
</div>
</div>
<Switch
checked={showSidebar}
onChange={() => setShowSidebar(!showSidebar)}
/>
</div>
</Card>
</div>
</div>
);
};