Create ThemeToggle.tsx
This commit is contained in:
parent
1cbc9d7b8e
commit
04d2238bfe
1 changed files with 115 additions and 0 deletions
115
src/components/dashboard/universal/ThemeToggle.tsx
Normal file
115
src/components/dashboard/universal/ThemeToggle.tsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { getCurrentTheme, toggleTheme } from '../../../utils/themeUtils';
|
||||
import { ThemeService } from '../../../scripts/database/ThemeService';
|
||||
import { Update } from '../../../scripts/pocketbase/Update';
|
||||
import { Authentication } from '../../../scripts/pocketbase/Authentication';
|
||||
import { Collections } from '../../../schemas/pocketbase/schema';
|
||||
|
||||
export default function ThemeToggle() {
|
||||
const [theme, setTheme] = useState<'light' | 'dark'>(getCurrentTheme());
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const auth = Authentication.getInstance();
|
||||
const update = Update.getInstance();
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize theme from IndexedDB
|
||||
const loadTheme = async () => {
|
||||
try {
|
||||
const themeService = ThemeService.getInstance();
|
||||
const settings = await themeService.getThemeSettings();
|
||||
setTheme(settings.theme);
|
||||
} catch (error) {
|
||||
console.error('Error loading theme:', error);
|
||||
}
|
||||
};
|
||||
|
||||
loadTheme();
|
||||
|
||||
// Add event listener for theme changes
|
||||
const handleThemeChange = () => {
|
||||
setTheme(getCurrentTheme());
|
||||
};
|
||||
|
||||
window.addEventListener('themechange', handleThemeChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('themechange', handleThemeChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleToggle = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
// Toggle theme in IndexedDB
|
||||
await toggleTheme();
|
||||
const newTheme = getCurrentTheme();
|
||||
setTheme(newTheme);
|
||||
|
||||
// Also update user preferences in PocketBase if user is authenticated
|
||||
const user = auth.getCurrentUser();
|
||||
if (user) {
|
||||
try {
|
||||
// Get current display preferences
|
||||
let displayPreferences = { theme: newTheme, fontSize: 'medium' };
|
||||
|
||||
if (user.display_preferences && typeof user.display_preferences === 'string') {
|
||||
try {
|
||||
const userPrefs = JSON.parse(user.display_preferences);
|
||||
displayPreferences = {
|
||||
...userPrefs,
|
||||
theme: newTheme
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('Error parsing display preferences:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Update user record
|
||||
await update.updateFields(
|
||||
Collections.USERS,
|
||||
user.id,
|
||||
{
|
||||
display_preferences: JSON.stringify(displayPreferences)
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error updating user preferences:', error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error toggling theme:', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="dropdown dropdown-end">
|
||||
<button
|
||||
onClick={handleToggle}
|
||||
className={`btn btn-circle btn-sm ${isLoading ? 'loading' : ''}`}
|
||||
aria-label={`Switch to ${theme === 'light' ? 'dark' : 'light'} theme`}
|
||||
title={`Switch to ${theme === 'light' ? 'dark' : 'light'} theme (Light mode is experimental)`}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{!isLoading && (
|
||||
theme === 'light' ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
)
|
||||
)}
|
||||
</button>
|
||||
<div className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52 mt-2 text-xs">
|
||||
<div className="p-2">
|
||||
<p className="font-bold text-warning mb-1">Warning:</p>
|
||||
<p>Light mode is experimental and not fully supported yet. Some UI elements may not display correctly.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue