refactor(settings): reuse DarkModeToggle for app and editor theme

This commit is contained in:
Haileyesus
2026-02-20 09:18:16 +03:00
parent 40c20c9215
commit e47b2702fe
2 changed files with 42 additions and 19 deletions

View File

@@ -1,24 +1,41 @@
import { Moon, Sun } from 'lucide-react'; import { Moon, Sun } from 'lucide-react';
import { useTheme } from '../contexts/ThemeContext'; import { useTheme } from '../contexts/ThemeContext';
function DarkModeToggle() { type DarkModeToggleProps = {
checked?: boolean;
onToggle?: (nextValue: boolean) => void;
ariaLabel?: string;
};
function DarkModeToggle({ checked, onToggle, ariaLabel = 'Toggle dark mode' }: DarkModeToggleProps) {
const { isDarkMode, toggleDarkMode } = useTheme(); const { isDarkMode, toggleDarkMode } = useTheme();
const isControlled = typeof checked === 'boolean' && typeof onToggle === 'function';
const isEnabled = isControlled ? checked : isDarkMode;
const handleToggle = () => {
if (isControlled) {
onToggle(!isEnabled);
return;
}
toggleDarkMode();
};
return ( return (
<button <button
onClick={toggleDarkMode} onClick={handleToggle}
className="relative inline-flex h-8 w-14 items-center rounded-full bg-gray-200 dark:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900" className="relative inline-flex h-8 w-14 items-center rounded-full bg-gray-200 dark:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900"
role="switch" role="switch"
aria-checked={isDarkMode} aria-checked={isEnabled}
aria-label="Toggle dark mode" aria-label={ariaLabel}
> >
<span className="sr-only">Toggle dark mode</span> <span className="sr-only">{ariaLabel}</span>
<span <span
className={`${ className={`${
isDarkMode ? 'translate-x-7' : 'translate-x-1' isEnabled ? 'translate-x-7' : 'translate-x-1'
} h-6 w-6 transform rounded-full bg-white shadow-lg transition-transform duration-200 flex items-center justify-center`} } h-6 w-6 transform rounded-full bg-white shadow-lg transition-transform duration-200 flex items-center justify-center`}
> >
{isDarkMode ? ( {isEnabled ? (
<Moon className="h-3.5 w-3.5 text-gray-700" /> <Moon className="h-3.5 w-3.5 text-gray-700" />
) : ( ) : (
<Sun className="h-3.5 w-3.5 text-yellow-500" /> <Sun className="h-3.5 w-3.5 text-yellow-500" />

View File

@@ -1,4 +1,3 @@
import { Moon, Sun } from 'lucide-react';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import DarkModeToggle from '../../../DarkModeToggle'; import DarkModeToggle from '../../../DarkModeToggle';
@@ -73,6 +72,7 @@ export default function AppearanceSettingsTab({
onCodeEditorFontSizeChange, onCodeEditorFontSizeChange,
}: AppearanceSettingsTabProps) { }: AppearanceSettingsTabProps) {
const { t } = useTranslation('settings'); const { t } = useTranslation('settings');
const codeEditorThemeLabel = t('appearanceSettings.codeEditor.theme.label');
return ( return (
<div className="space-y-6 md:space-y-8"> <div className="space-y-6 md:space-y-8">
@@ -85,7 +85,7 @@ export default function AppearanceSettingsTab({
{t('appearanceSettings.darkMode.description')} {t('appearanceSettings.darkMode.description')}
</div> </div>
</div> </div>
<DarkModeToggle /> <DarkModeToggle ariaLabel={t('appearanceSettings.darkMode.label')} />
</div> </div>
</div> </div>
</div> </div>
@@ -120,15 +120,21 @@ export default function AppearanceSettingsTab({
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-lg font-semibold text-foreground">{t('appearanceSettings.codeEditor.title')}</h3> <h3 className="text-lg font-semibold text-foreground">{t('appearanceSettings.codeEditor.title')}</h3>
<ToggleCard <div className="bg-gray-50 dark:bg-gray-900/50 border border-gray-200 dark:border-gray-700 rounded-lg p-4">
label={t('appearanceSettings.codeEditor.theme.label')} <div className="flex items-center justify-between">
description={t('appearanceSettings.codeEditor.theme.description')} <div>
<div className="font-medium text-foreground">{codeEditorThemeLabel}</div>
<div className="text-sm text-muted-foreground">
{t('appearanceSettings.codeEditor.theme.description')}
</div>
</div>
<DarkModeToggle
checked={codeEditorSettings.theme === 'dark'} checked={codeEditorSettings.theme === 'dark'}
onChange={(enabled) => onCodeEditorThemeChange(enabled ? 'dark' : 'light')} onToggle={(enabled) => onCodeEditorThemeChange(enabled ? 'dark' : 'light')}
onIcon={<Moon className="w-3.5 h-3.5 text-gray-700" />} ariaLabel={codeEditorThemeLabel}
offIcon={<Sun className="w-3.5 h-3.5 text-yellow-500" />}
ariaLabel={t('appearanceSettings.codeEditor.theme.label')}
/> />
</div>
</div>
<ToggleCard <ToggleCard
label={t('appearanceSettings.codeEditor.wordWrap.label')} label={t('appearanceSettings.codeEditor.wordWrap.label')}