diff --git a/src/app/profile/components/ProfilePanelSkeleton.tsx b/src/app/profile/components/ProfilePanelSkeleton.tsx
index cdfb50a9..d68cf16e 100644
--- a/src/app/profile/components/ProfilePanelSkeleton.tsx
+++ b/src/app/profile/components/ProfilePanelSkeleton.tsx
@@ -5,16 +5,16 @@ interface ProfilePanelSkeletonProps {
export default function ProfilePanelSkeleton({ label }: ProfilePanelSkeletonProps) {
return (
);
diff --git a/src/app/profile/components/ProfileTabs.tsx b/src/app/profile/components/ProfileTabs.tsx
index 63d5bf65..29970d06 100644
--- a/src/app/profile/components/ProfileTabs.tsx
+++ b/src/app/profile/components/ProfileTabs.tsx
@@ -47,8 +47,10 @@ const ProfileTabButton = memo(function ProfileTabButton({
aria-controls={`${tab.id}-panel`}
tabIndex={isActive ? 0 : -1}
onClick={handleClick}
- className={`rounded-lg px-4 py-2 font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${
- isActive ? 'bg-blue-500 text-white' : 'bg-white text-gray-700 hover:bg-gray-100'
+ className={`rounded-lg px-4 py-2 font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 ${
+ isActive
+ ? 'bg-blue-500 text-white'
+ : 'bg-white text-gray-700 hover:bg-gray-100 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700'
}`}
>
{tab.label}
diff --git a/src/app/profile/components/SettingsPanel.tsx b/src/app/profile/components/SettingsPanel.tsx
index 9382d2fc..6781ee36 100644
--- a/src/app/profile/components/SettingsPanel.tsx
+++ b/src/app/profile/components/SettingsPanel.tsx
@@ -1,11 +1,12 @@
'use client';
-import { memo, useCallback, useState } from 'react';
+import { memo, useCallback, useEffect, useState } from 'react';
+import { useTheme } from '@/lib/theme-provider';
import type { PreferenceOption } from '../profile-data';
import { settingsPreferences } from '../profile-data';
-const defaultSettings = Object.fromEntries(
- settingsPreferences.map((preference) => [preference.id, preference.enabled]),
+const NON_THEME_DEFAULTS = Object.fromEntries(
+ settingsPreferences.filter((p) => p.id !== 'dark-mode').map((p) => [p.id, p.enabled]),
) as Record
;
interface PreferenceSwitchProps {
@@ -26,8 +27,8 @@ const PreferenceSwitch = memo(function PreferenceSwitch({
return (
-
{preference.label}
-
+
{preference.label}
+
{preference.description}
@@ -41,37 +42,51 @@ const PreferenceSwitch = memo(function PreferenceSwitch({
aria-describedby={`${preference.id}-description`}
className="peer sr-only"
/>
-
+
);
});
function SettingsPanel() {
- const [settings, setSettings] = useState>(defaultSettings);
+ const { resolvedTheme, setTheme } = useTheme();
+ const [settings, setSettings] = useState>({
+ ...NON_THEME_DEFAULTS,
+ 'dark-mode': resolvedTheme === 'dark',
+ });
- const handleToggle = useCallback((id: string) => {
- setSettings((currentSettings) => ({
- ...currentSettings,
- [id]: !currentSettings[id],
- }));
- }, []);
+ // Keep the dark-mode toggle in sync if theme changes externally
+ useEffect(() => {
+ setSettings((prev) => ({ ...prev, 'dark-mode': resolvedTheme === 'dark' }));
+ }, [resolvedTheme]);
+
+ const handleToggle = useCallback(
+ (id: string) => {
+ if (id === 'dark-mode') {
+ const next = resolvedTheme === 'dark' ? 'light' : 'dark';
+ setTheme(next);
+ return;
+ }
+ setSettings((current) => ({ ...current, [id]: !current[id] }));
+ },
+ [resolvedTheme, setTheme],
+ );
return (
- Settings
+ Settings
{settingsPreferences.map((preference) => (
))}
diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx
index 14b1aa7b..cdf57b39 100644
--- a/src/app/profile/page.tsx
+++ b/src/app/profile/page.tsx
@@ -4,7 +4,7 @@ import { profileUser } from './profile-data';
export default function Profile() {
return (
-
+
diff --git a/src/components/profile/PreferencesSection.tsx b/src/components/profile/PreferencesSection.tsx
index bd9ab63d..698050a4 100644
--- a/src/components/profile/PreferencesSection.tsx
+++ b/src/components/profile/PreferencesSection.tsx
@@ -1,82 +1,91 @@
'use client';
-import { memo } from 'react';
+import { memo, useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
+import { useTheme } from '@/lib/theme-provider';
+import type { Theme } from '@/lib/theme-provider';
function PreferencesSection() {
- const { register } = useFormContext();
+ const { register, watch, setValue } = useFormContext();
+ const { theme, setTheme } = useTheme();
+
+ // Sync the form field with the live theme context on mount
+ useEffect(() => {
+ setValue('theme', theme);
+ }, [theme, setValue]);
+
+ // When the form radio changes, propagate to ThemeContext
+ const watchedTheme = watch('theme') as Theme;
+ useEffect(() => {
+ if (watchedTheme && watchedTheme !== theme) {
+ setTheme(watchedTheme);
+ }
+ }, [watchedTheme, theme, setTheme]);
return (
-
Display Settings
+
+ Display Settings
+
+
-
Performance
+
+ Performance
+