From 64cfa39b756ca30dab764e8bb76b7cc896b99053 Mon Sep 17 00:00:00 2001 From: dwindown Date: Mon, 10 Nov 2025 23:18:56 +0700 Subject: [PATCH] fix: Image upload, remove WP login branding, implement dark mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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 - 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!** --- admin-spa/src/App.tsx | 2 + admin-spa/src/components/ThemeProvider.tsx | 78 +++++++++++++ admin-spa/src/components/ThemeToggle.tsx | 46 ++++++++ admin-spa/src/components/ui/image-upload.tsx | 13 ++- admin-spa/src/main.tsx | 7 +- admin-spa/src/routes/Settings/Store.tsx | 4 +- includes/Branding.php | 113 +------------------ 7 files changed, 145 insertions(+), 118 deletions(-) create mode 100644 admin-spa/src/components/ThemeProvider.tsx create mode 100644 admin-spa/src/components/ThemeToggle.tsx diff --git a/admin-spa/src/App.tsx b/admin-spa/src/App.tsx index 9421b90..5fc672b 100644 --- a/admin-spa/src/App.tsx +++ b/admin-spa/src/App.tsx @@ -38,6 +38,7 @@ import { FAB } from '@/components/FAB'; import { useActiveSection } from '@/hooks/useActiveSection'; import { NAV_TREE_VERSION } from '@/nav/tree'; import { __ } from '@/lib/i18n'; +import { ThemeToggle } from '@/components/ThemeToggle'; function useFullscreen() { const [on, setOn] = useState(() => { @@ -362,6 +363,7 @@ function Header({ onFullscreen, fullscreen, showToggle = true, scrollContainerRe )} + {showToggle && ( + + + setTheme('light')}> + + Light + {theme === 'light' && } + + setTheme('dark')}> + + Dark + {theme === 'dark' && } + + setTheme('system')}> + + System + {theme === 'system' && } + + + + ); +} diff --git a/admin-spa/src/components/ui/image-upload.tsx b/admin-spa/src/components/ui/image-upload.tsx index 48caa12..c5271a2 100644 --- a/admin-spa/src/components/ui/image-upload.tsx +++ b/admin-spa/src/components/ui/image-upload.tsx @@ -74,24 +74,31 @@ export function ImageUpload({ const formData = new FormData(); formData.append('file', file); + // Get nonce from REST API settings + const nonce = (window as any).wpApiSettings?.nonce || + (window as any).WooNooW?.nonce || + document.querySelector('meta[name="wp-rest-nonce"]')?.getAttribute('content') || ''; + // Upload to WordPress media library const response = await fetch('/wp-json/wp/v2/media', { method: 'POST', headers: { - 'X-WP-Nonce': (window as any).wpApiSettings?.nonce || '', + 'X-WP-Nonce': nonce, }, + credentials: 'same-origin', body: formData, }); if (!response.ok) { - throw new Error('Upload failed'); + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || 'Upload failed'); } const data = await response.json(); onChange(data.source_url); } catch (error) { console.error('Upload error:', error); - alert('Failed to upload image'); + alert(error instanceof Error ? error.message : 'Failed to upload image'); } finally { setIsUploading(false); } diff --git a/admin-spa/src/main.tsx b/admin-spa/src/main.tsx index aa8fa55..4701a33 100644 --- a/admin-spa/src/main.tsx +++ b/admin-spa/src/main.tsx @@ -2,10 +2,15 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App'; +import { ThemeProvider } from './components/ThemeProvider'; const el = document.getElementById('woonoow-admin-app'); if (el) { - createRoot(el).render(); + createRoot(el).render( + + + + ); } else { console.warn('[WooNooW] Root element #woonoow-admin-app not found.'); } \ No newline at end of file diff --git a/admin-spa/src/routes/Settings/Store.tsx b/admin-spa/src/routes/Settings/Store.tsx index fdca450..0363fef 100644 --- a/admin-spa/src/routes/Settings/Store.tsx +++ b/admin-spa/src/routes/Settings/Store.tsx @@ -325,7 +325,7 @@ export default function StoreDetailsPage() { title="Brand" description="Logo, icon, and colors for your store" > - + updateSetting('storeLogo', url)} @@ -334,7 +334,7 @@ export default function StoreDetailsPage() { /> - + updateSetting('storeIcon', url)} diff --git a/includes/Branding.php b/includes/Branding.php index d280f93..b1ece54 100644 --- a/includes/Branding.php +++ b/includes/Branding.php @@ -21,12 +21,8 @@ class Branding { // Apply favicon add_action('wp_head', [__CLASS__, 'inject_favicon']); add_action('admin_head', [__CLASS__, 'inject_favicon']); - add_action('login_head', [__CLASS__, 'inject_favicon']); - // Customize login page - add_action('login_enqueue_scripts', [__CLASS__, 'customize_login_page']); - add_filter('login_headerurl', [__CLASS__, 'login_logo_url']); - add_filter('login_headertext', [__CLASS__, 'login_logo_title']); + // Note: Login page branding removed - WooNooW uses standalone SPA login } /** @@ -62,113 +58,6 @@ class Branding { } } - /** - * Customize login page - */ - public static function customize_login_page() { - $logo = get_option('woonoow_store_logo', ''); - $store_name = get_option('blogname', 'WooNooW'); - $tagline = get_option('blogdescription', ''); - $primary = get_option('woonoow_primary_color', '#3b82f6'); - - ?> - -