## 1. Fix Image Upload ✅ **Issue:** Image upload failing due to missing nonce **Fix:** - Better nonce detection (wpApiSettings, WooNooW, meta tag) - Added credentials: 'same-origin' - Better error handling with error messages - Clarified image size recommendations (not strict requirements) **Changes:** - Logo: "Recommended size: 200x60px (or similar ratio)" - Icon: "Recommended: 32x32px or larger square image" --- ## 2. Remove WordPress Login Page Branding ✅ **Issue:** Misunderstood - implemented WP login branding instead of SPA login **Fix:** - Removed all WordPress login page customization - Removed login_enqueue_scripts hook - Removed login_headerurl filter - Removed login_headertext filter - Removed customize_login_page() method - Removed login_logo_url() method - Removed login_logo_title() method **Note:** WooNooW uses standalone SPA login, not WordPress login page --- ## 3. Implement Dark/Light Mode ✅ ### Components Created: **ThemeProvider.tsx:** - Theme context (light, dark, system) - Automatic system theme detection - localStorage persistence (woonoow_theme) - Applies .light or .dark class to <html> - Listens for system theme changes **ThemeToggle.tsx:** - Dropdown menu with 3 options: - ☀️ Light - 🌙 Dark - 🖥️ System - Shows current selection with checkmark - Icon changes based on actual theme ### Integration: - Wrapped App with ThemeProvider in main.tsx - Added ThemeToggle to header (before fullscreen button) - Uses existing dark mode CSS variables (already configured) ### Features: - ✅ Light mode - ✅ Dark mode - ✅ System preference (auto) - ✅ Persists in localStorage - ✅ Smooth transitions - ✅ Icon updates dynamically ### CSS: - Already configured: darkMode: ["class"] in tailwind.config.js - Dark mode variables already defined in index.css - No additional CSS needed --- ## Result ✅ Image upload fixed with better error handling ✅ WordPress login branding removed (not needed) ✅ Dark/Light mode fully functional ✅ Theme toggle in header ✅ System preference support ✅ Persists across sessions **Ready to test!**
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import React, { createContext, useContext, useEffect, useState } from 'react';
|
|
|
|
type Theme = 'light' | 'dark' | 'system';
|
|
|
|
interface ThemeContextType {
|
|
theme: Theme;
|
|
setTheme: (theme: Theme) => void;
|
|
actualTheme: 'light' | 'dark';
|
|
}
|
|
|
|
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
|
|
|
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
const [theme, setThemeState] = useState<Theme>(() => {
|
|
const stored = localStorage.getItem('woonoow_theme');
|
|
return (stored as Theme) || 'system';
|
|
});
|
|
|
|
const [actualTheme, setActualTheme] = useState<'light' | 'dark'>('light');
|
|
|
|
useEffect(() => {
|
|
const root = window.document.documentElement;
|
|
|
|
// Remove previous theme classes
|
|
root.classList.remove('light', 'dark');
|
|
|
|
let effectiveTheme: 'light' | 'dark';
|
|
|
|
if (theme === 'system') {
|
|
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
? 'dark'
|
|
: 'light';
|
|
effectiveTheme = systemTheme;
|
|
} else {
|
|
effectiveTheme = theme;
|
|
}
|
|
|
|
root.classList.add(effectiveTheme);
|
|
setActualTheme(effectiveTheme);
|
|
}, [theme]);
|
|
|
|
// Listen for system theme changes
|
|
useEffect(() => {
|
|
if (theme !== 'system') return;
|
|
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
|
|
const handleChange = () => {
|
|
const root = window.document.documentElement;
|
|
root.classList.remove('light', 'dark');
|
|
const systemTheme = mediaQuery.matches ? 'dark' : 'light';
|
|
root.classList.add(systemTheme);
|
|
setActualTheme(systemTheme);
|
|
};
|
|
|
|
mediaQuery.addEventListener('change', handleChange);
|
|
return () => mediaQuery.removeEventListener('change', handleChange);
|
|
}, [theme]);
|
|
|
|
const setTheme = (newTheme: Theme) => {
|
|
localStorage.setItem('woonoow_theme', newTheme);
|
|
setThemeState(newTheme);
|
|
};
|
|
|
|
return (
|
|
<ThemeContext.Provider value={{ theme, setTheme, actualTheme }}>
|
|
{children}
|
|
</ThemeContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useTheme() {
|
|
const context = useContext(ThemeContext);
|
|
if (context === undefined) {
|
|
throw new Error('useTheme must be used within a ThemeProvider');
|
|
}
|
|
return context;
|
|
}
|