- Implemented a keyboard shortcuts button in the navigation rail. - Added a setting to toggle the visibility of toolbar labels in appearance settings. - Updated the email context menu to streamline actions for archiving, deleting, and marking emails as read/unread. - Enhanced the email viewer with improved spam handling and read state toggling. - Updated localization files to include new strings for keyboard shortcuts and toolbar labels.
147 lines
5.9 KiB
TypeScript
147 lines
5.9 KiB
TypeScript
"use client";
|
|
|
|
import { useTranslations } from 'next-intl';
|
|
import { useThemeStore } from '@/stores/theme-store';
|
|
import { useSettingsStore, type ToolbarPosition, type Density } from '@/stores/settings-store';
|
|
import { LanguageSwitcher } from '@/components/ui/language-switcher';
|
|
import { SettingsSection, SettingItem, RadioGroup, ToggleSwitch } from './settings-section';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
const DENSITY_PREVIEW: Record<Density, { py: string; gap: string; showAvatar: boolean; showPreview: boolean }> = {
|
|
'extra-compact': { py: 'py-0.5', gap: 'gap-1.5', showAvatar: false, showPreview: false },
|
|
compact: { py: 'py-1', gap: 'gap-2', showAvatar: true, showPreview: false },
|
|
regular: { py: 'py-2.5', gap: 'gap-3', showAvatar: true, showPreview: true },
|
|
comfortable: { py: 'py-4', gap: 'gap-4', showAvatar: true, showPreview: true },
|
|
};
|
|
|
|
function DensityPreview({ density }: { density: Density }) {
|
|
const cfg = DENSITY_PREVIEW[density];
|
|
const rows = [
|
|
{ unread: true, sender: 'Alice Johnson', subject: 'Project update — Q1 roadmap', preview: 'Here are the latest numbers from…' },
|
|
{ unread: false, sender: 'Bob Smith', subject: 'Re: Meeting notes', preview: 'Thanks, will review and get back...' },
|
|
{ unread: true, sender: 'Carol Lee', subject: 'Invoice #4092', preview: 'Please find attached the invoice…' },
|
|
];
|
|
|
|
return (
|
|
<div className="mt-3 rounded-lg border border-border overflow-hidden bg-background text-xs select-none">
|
|
{rows.map((row, i) => (
|
|
<div
|
|
key={i}
|
|
className={cn(
|
|
"flex items-center px-3 border-b border-border last:border-b-0",
|
|
cfg.py,
|
|
cfg.gap
|
|
)}
|
|
>
|
|
{cfg.showAvatar && (
|
|
<div className={cn(
|
|
"flex-shrink-0 rounded-full bg-muted",
|
|
density === 'comfortable' ? "w-8 h-8" : "w-6 h-6"
|
|
)} />
|
|
)}
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center justify-between gap-2">
|
|
<span className={cn("truncate", row.unread ? "font-semibold text-foreground" : "text-muted-foreground")}>
|
|
{row.sender}
|
|
</span>
|
|
<span className="text-[10px] text-muted-foreground flex-shrink-0 tabular-nums">12:00</span>
|
|
</div>
|
|
<div className={cn("truncate", row.unread ? "font-medium text-foreground" : "text-foreground/80")}>
|
|
{row.subject}
|
|
</div>
|
|
{cfg.showPreview && (
|
|
<div className="truncate text-muted-foreground/70">{row.preview}</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AppearanceSettings() {
|
|
const t = useTranslations('settings.appearance');
|
|
const { theme, setTheme } = useThemeStore();
|
|
const { fontSize, density, animationsEnabled, toolbarPosition, showToolbarLabels, updateSetting } = useSettingsStore();
|
|
|
|
return (
|
|
<SettingsSection title={t('title')} description={t('description')}>
|
|
{/* Theme */}
|
|
<SettingItem label={t('theme.label')} description={t('theme.description')}>
|
|
<RadioGroup
|
|
value={theme}
|
|
onChange={(value) => setTheme(value as 'light' | 'dark' | 'system')}
|
|
options={[
|
|
{ value: 'light', label: t('theme.light') },
|
|
{ value: 'dark', label: t('theme.dark') },
|
|
{ value: 'system', label: t('theme.system') },
|
|
]}
|
|
/>
|
|
</SettingItem>
|
|
|
|
{/* Language */}
|
|
<SettingItem label={t('language.label')} description={t('language.description')}>
|
|
<LanguageSwitcher />
|
|
</SettingItem>
|
|
|
|
{/* Font Size */}
|
|
<SettingItem label={t('font_size.label')} description={t('font_size.description')}>
|
|
<RadioGroup
|
|
value={fontSize}
|
|
onChange={(value) => updateSetting('fontSize', value as 'small' | 'medium' | 'large')}
|
|
options={[
|
|
{ value: 'small', label: t('font_size.small') },
|
|
{ value: 'medium', label: t('font_size.medium') },
|
|
{ value: 'large', label: t('font_size.large') },
|
|
]}
|
|
/>
|
|
</SettingItem>
|
|
|
|
{/* Density */}
|
|
<SettingItem label={t('list_density.label')} description={t('list_density.description')}>
|
|
<RadioGroup
|
|
value={density}
|
|
onChange={(value) =>
|
|
updateSetting('density', value as Density)
|
|
}
|
|
options={[
|
|
{ value: 'extra-compact', label: t('list_density.extra_compact') },
|
|
{ value: 'compact', label: t('list_density.compact') },
|
|
{ value: 'regular', label: t('list_density.regular') },
|
|
{ value: 'comfortable', label: t('list_density.comfortable') },
|
|
]}
|
|
/>
|
|
<DensityPreview density={density} />
|
|
</SettingItem>
|
|
|
|
{/* Toolbar Position */}
|
|
<SettingItem label={t('toolbar_position.label')} description={t('toolbar_position.description')}>
|
|
<RadioGroup
|
|
value={toolbarPosition}
|
|
onChange={(value) => updateSetting('toolbarPosition', value as ToolbarPosition)}
|
|
options={[
|
|
{ value: 'top', label: t('toolbar_position.top') },
|
|
{ value: 'below-subject', label: t('toolbar_position.below_subject') },
|
|
]}
|
|
/>
|
|
</SettingItem>
|
|
|
|
{/* Toolbar Labels */}
|
|
<SettingItem label={t('toolbar_labels.label')} description={t('toolbar_labels.description')}>
|
|
<ToggleSwitch
|
|
checked={showToolbarLabels}
|
|
onChange={(checked) => updateSetting('showToolbarLabels', checked)}
|
|
/>
|
|
</SettingItem>
|
|
|
|
{/* Animations */}
|
|
<SettingItem label={t('animations.label')} description={t('animations.description')}>
|
|
<ToggleSwitch
|
|
checked={animationsEnabled}
|
|
onChange={(checked) => updateSetting('animationsEnabled', checked)}
|
|
/>
|
|
</SettingItem>
|
|
</SettingsSection>
|
|
);
|
|
}
|