Files
Momento/memento-note/app/(main)/settings/general/general-settings-client.tsx
Antigravity 1446463f04 design: apply Architectural Minimalist style to all Settings pages
- settings/layout: serif h1 title + uppercase tracking subtitle, matching Agents page
- SettingsNav: uppercase tracking-wider tabs with foreground underline on active
- All settings pages (general, ai, appearance, profile, mcp, about, data):
  remove duplicate h1 (now in layout header), replace with uppercase section label
- notes.ts: decouple history guards from global userAISettings
- note-document-info-panel: add 'Save version' button with loading feedback
2026-05-09 07:39:35 +00:00

149 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState } from 'react'
import { useLanguage } from '@/lib/i18n'
import { updateAISettings } from '@/app/actions/ai-settings'
import { toast } from 'sonner'
import { useRouter } from 'next/navigation'
import { Globe, Bell } from 'lucide-react'
interface GeneralSettingsClientProps {
initialSettings: {
preferredLanguage: string
emailNotifications: boolean
desktopNotifications: boolean
}
}
export function GeneralSettingsClient({ initialSettings }: GeneralSettingsClientProps) {
const { t, setLanguage: setContextLanguage } = useLanguage()
const router = useRouter()
const [language, setLanguage] = useState(initialSettings.preferredLanguage || 'auto')
const [emailNotifications, setEmailNotifications] = useState(initialSettings.emailNotifications ?? false)
const [desktopNotifications, setDesktopNotifications] = useState(initialSettings.desktopNotifications ?? false)
const handleLanguageChange = async (value: string) => {
setLanguage(value)
await updateAISettings({ preferredLanguage: value as any })
if (value === 'auto') {
localStorage.removeItem('user-language')
toast.success(t('settings.languageAuto') || 'Language set to Auto')
} else {
localStorage.setItem('user-language', value)
setContextLanguage(value as any)
toast.success(t('profile.languageUpdateSuccess') || 'Language updated')
}
setTimeout(() => router.refresh(), 300)
}
const handleEmailNotificationsChange = async (enabled: boolean) => {
setEmailNotifications(enabled)
await updateAISettings({ emailNotifications: enabled })
toast.success(t('settings.settingsSaved') || 'Saved')
}
const handleDesktopNotificationsChange = async (enabled: boolean) => {
setDesktopNotifications(enabled)
await updateAISettings({ desktopNotifications: enabled })
toast.success(t('settings.settingsSaved') || 'Saved')
}
return (
<div className="space-y-8">
<p className="text-[11px] font-bold uppercase tracking-[0.2em] text-muted-foreground">
{t('generalSettings.description')}
</p>
{/* 2-column card grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Language card */}
<div className="bg-card rounded-lg border border-border p-6 shadow-sm flex flex-col gap-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary shrink-0">
<Globe className="h-5 w-5" />
</div>
<div>
<h3 className="font-semibold text-foreground">{t('settings.language')}</h3>
<p className="text-sm text-muted-foreground">{t('settings.selectLanguage')}</p>
</div>
</div>
<div className="relative mt-2">
<select
value={language}
onChange={(e) => handleLanguageChange(e.target.value)}
className="w-full h-11 px-4 bg-muted border border-border rounded-lg text-foreground text-sm focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none appearance-none cursor-pointer transition-colors"
>
<option value="auto">{t('profile.autoDetect')}</option>
<option value="en">English</option>
<option value="fr">Français</option>
<option value="es">Español</option>
<option value="de">Deutsch</option>
<option value="fa">فارسی</option>
<option value="it">Italiano</option>
<option value="pt">Português</option>
<option value="ru">Русский</option>
<option value="zh"></option>
<option value="ja"></option>
<option value="ko"></option>
<option value="ar">العربية</option>
<option value="hi">ि</option>
<option value="nl">Nederlands</option>
<option value="pl">Polski</option>
</select>
<div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none text-muted-foreground">
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
</div>
</div>
</div>
{/* Notifications card */}
<div className="bg-card rounded-lg border border-border p-6 shadow-sm flex flex-col gap-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary shrink-0">
<Bell className="h-5 w-5" />
</div>
<div>
<h3 className="font-semibold text-foreground">{t('settings.notifications')}</h3>
<p className="text-sm text-muted-foreground">{t('settings.notificationsDesc')}</p>
</div>
</div>
<div className="mt-2 space-y-5">
{/* Email toggle */}
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-foreground">{t('settings.emailNotifications')}</p>
<p className="text-xs text-muted-foreground">{t('settings.emailNotificationsDesc')}</p>
</div>
<button
type="button"
role="switch"
aria-checked={emailNotifications}
onClick={() => handleEmailNotificationsChange(!emailNotifications)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary/30 ${emailNotifications ? 'bg-primary' : 'bg-muted-foreground/30'}`}
>
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${emailNotifications ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
</div>
{/* Desktop toggle */}
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-foreground">{t('settings.desktopNotifications')}</p>
<p className="text-xs text-muted-foreground">{t('settings.desktopNotificationsDesc')}</p>
</div>
<button
type="button"
role="switch"
aria-checked={desktopNotifications}
onClick={() => handleDesktopNotificationsChange(!desktopNotifications)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary/30 ${desktopNotifications ? 'bg-primary' : 'bg-muted-foreground/30'}`}
>
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${desktopNotifications ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
</div>
</div>
</div>
</div>
</div>
)
}