feat: implement header/footer visibility controls for checkout and thankyou pages
- Created LayoutWrapper component to conditionally render header/footer based on route - Created MinimalHeader component (logo only) - Created MinimalFooter component (trust badges + policy links) - Created usePageVisibility hook to get visibility settings per page - Wrapped ClassicLayout with LayoutWrapper for conditional rendering - Header/footer visibility now controlled directly in React SPA - Settings: show/minimal/hide for both header and footer - Background color support for checkout and thankyou pages
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { createContext, useContext, useEffect, ReactNode } from 'react';
|
||||
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
||||
|
||||
interface ThemeColors {
|
||||
primary: string;
|
||||
@@ -14,6 +14,7 @@ interface ThemeTypography {
|
||||
heading: string;
|
||||
body: string;
|
||||
};
|
||||
scale?: number;
|
||||
}
|
||||
|
||||
interface ThemeConfig {
|
||||
@@ -28,32 +29,41 @@ interface ThemeContextValue {
|
||||
isFullSPA: boolean;
|
||||
isCheckoutOnly: boolean;
|
||||
isLaunchLayout: boolean;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextValue | null>(null);
|
||||
|
||||
// Map our predefined font pairs to presets
|
||||
const FONT_PAIR_MAP: Record<string, string> = {
|
||||
modern: 'modern',
|
||||
editorial: 'elegant',
|
||||
friendly: 'professional',
|
||||
elegant: 'elegant',
|
||||
};
|
||||
|
||||
const TYPOGRAPHY_PRESETS = {
|
||||
professional: {
|
||||
modern: {
|
||||
heading: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
body: "'Lora', Georgia, serif",
|
||||
body: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
headingWeight: 700,
|
||||
bodyWeight: 400,
|
||||
},
|
||||
modern: {
|
||||
professional: {
|
||||
heading: "'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
body: "'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
body: "'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
headingWeight: 600,
|
||||
bodyWeight: 400,
|
||||
},
|
||||
elegant: {
|
||||
heading: "'Playfair Display', Georgia, serif",
|
||||
body: "'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
body: "'Source Sans 3', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
headingWeight: 700,
|
||||
bodyWeight: 400,
|
||||
},
|
||||
tech: {
|
||||
heading: "'Space Grotesk', monospace",
|
||||
body: "'IBM Plex Mono', monospace",
|
||||
heading: "'Cormorant Garamond', Georgia, serif",
|
||||
body: "'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
||||
headingWeight: 700,
|
||||
bodyWeight: 400,
|
||||
},
|
||||
@@ -112,12 +122,62 @@ function generateColorShades(baseColor: string): Record<number, string> {
|
||||
}
|
||||
|
||||
export function ThemeProvider({
|
||||
config,
|
||||
config: initialConfig,
|
||||
children
|
||||
}: {
|
||||
config: ThemeConfig;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const [config, setConfig] = useState<ThemeConfig>(initialConfig);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// Fetch settings from API
|
||||
useEffect(() => {
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const apiRoot = (window as any).woonoowCustomer?.apiRoot || '/wp-json/woonoow/v1';
|
||||
const response = await fetch(`${apiRoot}/appearance/settings`, {
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const settings = data.data;
|
||||
|
||||
if (settings?.general) {
|
||||
const general = settings.general;
|
||||
|
||||
// Map API settings to theme config
|
||||
const mappedPreset = FONT_PAIR_MAP[general.typography?.predefined_pair] || 'modern';
|
||||
const newConfig: ThemeConfig = {
|
||||
mode: general.spa_mode || 'full',
|
||||
layout: 'modern', // Keep existing layout for now
|
||||
colors: {
|
||||
primary: general.colors?.primary || '#3B82F6',
|
||||
secondary: general.colors?.secondary || '#8B5CF6',
|
||||
accent: general.colors?.accent || '#10B981',
|
||||
background: general.colors?.background || '#ffffff',
|
||||
text: general.colors?.text || '#111827',
|
||||
},
|
||||
typography: {
|
||||
preset: mappedPreset as 'professional' | 'modern' | 'elegant' | 'tech' | 'custom',
|
||||
scale: general.typography?.scale || 1.0,
|
||||
},
|
||||
};
|
||||
|
||||
setConfig(newConfig);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch appearance settings:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSettings();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
|
||||
@@ -142,8 +202,13 @@ export function ThemeProvider({
|
||||
root.style.setProperty('--font-weight-body', typoPreset.bodyWeight.toString());
|
||||
}
|
||||
|
||||
// Load Google Fonts
|
||||
loadTypography(config.typography.preset, config.typography.customFonts);
|
||||
// Apply font scale
|
||||
if (config.typography.scale) {
|
||||
root.style.setProperty('--font-scale', config.typography.scale.toString());
|
||||
}
|
||||
|
||||
// We're using self-hosted fonts now, no need to load from Google
|
||||
// loadTypography(config.typography.preset, config.typography.customFonts);
|
||||
|
||||
// Add layout class to body
|
||||
document.body.classList.remove('layout-classic', 'layout-modern', 'layout-boutique', 'layout-launch');
|
||||
@@ -159,6 +224,7 @@ export function ThemeProvider({
|
||||
isFullSPA: config.mode === 'full',
|
||||
isCheckoutOnly: config.mode === 'checkout_only',
|
||||
isLaunchLayout: config.layout === 'launch',
|
||||
loading,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user