'use client'; /* * The ONLY React subtree subscribed to useColorScheme(). When the user picks a mode: * 1. setMode(...) writes MUI's mode * 2. the resolved scheme lands on * 3. CSS custom properties resolve to new values → browser repaints * 4. React re-renders ONLY this component (which segment reads as selected) * Nothing above it in the tree is touched. */ import { FunctionComponent } from 'react'; import { Stack, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material'; import { useColorScheme } from '@mui/material/styles'; import { useTranslations } from 'next-intl'; import AppIcon from '@/components/common/AppIcon'; type ThemeMode = 'light' | 'dark' | 'system'; const MODES: ReadonlyArray<{ mode: ThemeMode; icon: string; key: string }> = [ { mode: 'light', icon: 'light_mode', key: 'theme_light' }, { mode: 'dark', icon: 'dark_mode', key: 'theme_dark' }, { mode: 'system', icon: 'system_mode', key: 'theme_system' }, ]; /** * The app's one appearance control: a three-way segmented choice — روشن / تیره / سیستم. * * It replaced an on/off `Switch`, which was wrong twice over. A switch is a **boolean**, so it * could not express "follow my phone" — yet `system` is the app's actual default (`ThemeProvider` * `defaultMode`), which left the control silently lying about the current state on a first visit. * And a lone switch beside a label reads like a feature being enabled rather than a look being * chosen. Three labelled segments say what each option does and which one is live. * * This is the one place `mode` is the right source rather than `colorScheme`: `mode` is the user's * **choice** (and can be `'system'`), `colorScheme` is only the resolved result. The `?? 'system'` * fallback is hydration-safe — MUI reports `mode` as `undefined` until it mounts, and the server, * the first client render, and the pre-mount state all agree on the same default. * @component ThemeModeSetting */ const ThemeModeSetting: FunctionComponent = () => { const { mode, setMode } = useColorScheme(); const t = useTranslations('common'); return ( { // `exclusive` emits null when the active segment is tapped again — keep the choice. if (next) setMode(next); }} aria-label={t('appearance')} sx={{ '& .MuiToggleButton-root': { gap: 0.75, paddingBlock: 0.75, borderRadius: 'var(--bal-radius-sm)' } }} > {MODES.map((option) => ( ))} ); }; export default ThemeModeSetting;