mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-04 13:37:40 +00:00
refactor(settings): reuse DarkModeToggle for app and editor theme
This commit is contained in:
@@ -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" />
|
||||||
|
|||||||
@@ -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')}
|
||||||
|
|||||||
Reference in New Issue
Block a user