Public Access
refactor(settings): one card per section
The name field takes its value from the page's own load, not from the user context: the context can still be empty when the form mounts.
This commit is contained in:
1 parent
6da612bebd
commit
28ff6eae52
7 files changed
+424
-321
No files matched your search
@@ -0,0 +1,81 @@
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import {ImageOff, Palette, RotateCcw} from 'lucide-react';
|
||||
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {Switch} from '@/components/ui/switch';
|
||||
import {AccentPicker, CornersPicker} from './StylePickers.jsx';
|
||||
import {usePreferences} from '../context/PreferencesContext.jsx';
|
||||
import useSaveAppearance from '../hooks/useSaveAppearance.js';
|
||||
import {coverUrl} from '../utils/games.js';
|
||||
|
||||
export default function AppearanceCard() {
|
||||
const {t} = useTranslation();
|
||||
const {appearance} = usePreferences();
|
||||
const saveAppearance = useSaveAppearance();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2"><Palette className="size-4 text-primary"/>{t('SETTINGS.APPEARANCE')}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<AccentPicker id="accent" value={appearance.accent} onChange={(accent) => saveAppearance({accent})}/>
|
||||
<CornersPicker id="corners" value={appearance.corners} onChange={(corners) => saveAppearance({corners})}/>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="wideLayout">{t('SETTINGS.WIDE_LAYOUT')}</Label>
|
||||
<p className="text-xs text-muted-foreground">{t('SETTINGS.WIDE_LAYOUT_HINT')}</p>
|
||||
</div>
|
||||
<Switch id="wideLayout" checked={appearance.wideLayout}
|
||||
onCheckedChange={(wideLayout) => saveAppearance({wideLayout})}/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="space-y-1">
|
||||
<Label id="background-label">{t('SETTINGS.BACKGROUND')}</Label>
|
||||
{!appearance.backgroundAppid && (
|
||||
<p className="text-xs text-muted-foreground">{t('SETTINGS.BACKGROUND_HINT')}</p>
|
||||
)}
|
||||
</div>
|
||||
{appearance.backgroundAppid && (
|
||||
<div className="flex items-center gap-2">
|
||||
<img src={coverUrl(appearance.backgroundAppid)} alt=""
|
||||
onError={(event) => { event.currentTarget.hidden = true; }}
|
||||
className="h-10 w-20 rounded-md object-cover"/>
|
||||
<Button type="button" variant="outline" size="sm"
|
||||
aria-describedby="background-label"
|
||||
onClick={() => saveAppearance({backgroundAppid: null})}>
|
||||
<ImageOff/>{t('SETTINGS.BACKGROUND_REMOVE')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="space-y-1">
|
||||
<Label id="banner-label" htmlFor="showBanner">{t('SETTINGS.BANNER')}</Label>
|
||||
{appearance.showBanner && !appearance.bannerAppid && (
|
||||
<p className="text-xs text-muted-foreground">{t('SETTINGS.BANNER_HINT')}</p>
|
||||
)}
|
||||
</div>
|
||||
<Switch id="showBanner" checked={appearance.showBanner}
|
||||
onCheckedChange={(showBanner) => saveAppearance({showBanner})}/>
|
||||
</div>
|
||||
{appearance.showBanner && appearance.bannerAppid && (
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<img src={coverUrl(appearance.bannerAppid)} alt=""
|
||||
onError={(event) => { event.currentTarget.hidden = true; }}
|
||||
className="h-10 w-20 rounded-md object-cover"/>
|
||||
<Button type="button" variant="outline" size="sm"
|
||||
aria-describedby="banner-label"
|
||||
onClick={() => saveAppearance({bannerAppid: null})}>
|
||||
<RotateCcw/>{t('SETTINGS.BANNER_AUTO')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user