Refine admin PWA dark theme controls
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-02-04 13:50:59 +01:00
parent 239f55f9c5
commit 66c7131d79
22 changed files with 999 additions and 110 deletions

View File

@@ -1,12 +1,13 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ChevronRight, CreditCard, FileText, HelpCircle, User, X } from 'lucide-react';
import { XStack, YStack, SizableText as Text, ListItem, YGroup, Switch, Separator } from 'tamagui';
import { ChevronRight, CreditCard, FileText, HelpCircle, Moon, Sun, User, X } from 'lucide-react';
import { XStack, YStack, SizableText as Text, ListItem, YGroup, Separator } from 'tamagui';
import { Pressable } from '@tamagui/react-native-web-lite';
import { ToggleGroup } from '@tamagui/toggle-group';
import { useAppearance } from '@/hooks/use-appearance';
import { ADMIN_BILLING_PATH, ADMIN_DATA_EXPORTS_PATH, ADMIN_FAQ_PATH, ADMIN_PROFILE_ACCOUNT_PATH, adminPath } from '../../constants';
import { useAdminTheme } from '../theme';
import { useAdminTheme, withAlpha } from '../theme';
import { MobileSelect } from './FormControls';
type UserMenuSheetProps = {
@@ -30,7 +31,9 @@ export function UserMenuSheet({ open, onClose, user, isMember, navigate }: UserM
setLanguage(i18n.language?.startsWith('en') ? 'en' : 'de');
}, [i18n.language]);
const isDark = resolved === 'dark';
const themeValue: 'light' | 'dark' = (appearance === 'system' ? resolved : appearance) ?? 'light';
const activeToggleBg = theme.accentSoft ?? withAlpha(theme.primary, 0.18);
const activeToggleBorder = withAlpha(theme.primary, 0.45);
const handleNavigate = (path: string) => {
onClose();
@@ -239,14 +242,46 @@ export function UserMenuSheet({ open, onClose, user, isMember, navigate }: UserM
</XStack>
}
iconAfter={
<Switch
size="$2"
checked={isDark}
onCheckedChange={(next: boolean) => updateAppearance(next ? 'dark' : 'light')}
aria-label={t('mobileProfile.theme', 'Dark Mode')}
<ToggleGroup
type="single"
value={themeValue}
onValueChange={(next: string) => {
if (next === 'light' || next === 'dark') {
updateAppearance(next);
}
}}
disableDeactivation
orientation="horizontal"
flexDirection="row"
gap="$1.5"
>
<Switch.Thumb />
</Switch>
{([
{ key: 'light', label: t('mobileProfile.themeLight', 'Light'), icon: Sun },
{ key: 'dark', label: t('mobileProfile.themeDark', 'Dark'), icon: Moon },
] as const).map((option) => {
const active = option.key === themeValue;
const Icon = option.icon;
return (
<ToggleGroup.Item
key={option.key}
value={option.key}
borderRadius="$pill"
borderWidth={1}
borderColor={active ? activeToggleBorder : theme.border}
backgroundColor={active ? activeToggleBg : 'transparent'}
paddingHorizontal="$2.5"
paddingVertical="$1.5"
>
<XStack alignItems="center" gap="$1.5">
<Icon size={14} color={active ? theme.textStrong : theme.muted} />
<Text fontSize="$xs" fontWeight={active ? '700' : '600'} color={active ? theme.textStrong : theme.muted}>
{option.label}
</Text>
</XStack>
</ToggleGroup.Item>
);
})}
</ToggleGroup>
}
/>
</YGroup.Item>