feat/fix: improve responsive constraints & add live ThemeListener
This commit is contained in:
parent
2da6522be4
commit
762200d20b
9 changed files with 192 additions and 3 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ThemeListener } from './components/layout/ThemeListener';
|
||||||
import React, { lazy, Suspense } from 'react';
|
import React, { lazy, Suspense } from 'react';
|
||||||
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
|
@ -28,7 +29,8 @@ export default function App() {
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ScrollToTop />
|
<ScrollToTop />
|
||||||
<Suspense fallback={<div className="min-h-screen bg-white flex items-center justify-center font-mono text-[10px] uppercase tracking-widest text-tech-muted animate-pulse">loading_module...</div>}>
|
<Suspense fallback={<div className="overflow-x-hidden min-h-screen bg-white flex items-center justify-center font-mono text-[10px] uppercase tracking-widest text-tech-muted animate-pulse">
|
||||||
|
<ThemeListener />loading_module...</div>}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to="/pt" replace />} />
|
<Route path="/" element={<Navigate to="/pt" replace />} />
|
||||||
|
|
||||||
|
|
|
||||||
50
Template-01/src/components/layout/ThemeListener.tsx
Normal file
50
Template-01/src/components/layout/ThemeListener.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export function ThemeListener() {
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMessage = (event: MessageEvent) => {
|
||||||
|
// Allow messages from any origin since preview is generic
|
||||||
|
if (event.data?.type === 'UPDATE_APPEARANCE') {
|
||||||
|
const settings = event.data.settings;
|
||||||
|
if (!settings) return;
|
||||||
|
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
// Update Primary Color
|
||||||
|
if (settings.primaryColor) {
|
||||||
|
root.style.setProperty('--color-brand-primary', settings.primaryColor);
|
||||||
|
root.style.setProperty('--color-brand-blue', settings.primaryColor);
|
||||||
|
root.style.setProperty('--color-brand-gold', settings.primaryColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Background Color
|
||||||
|
if (settings.backgroundColor) {
|
||||||
|
root.style.setProperty('--color-brand-bg', settings.backgroundColor);
|
||||||
|
document.body.style.backgroundColor = settings.backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Font Family
|
||||||
|
if (settings.fontFamily) {
|
||||||
|
const fontLink = document.getElementById('dynamic-font') as HTMLLinkElement;
|
||||||
|
const fontName = settings.fontFamily.replace(/ /g, '+');
|
||||||
|
if (fontLink) {
|
||||||
|
fontLink.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@300;400;500;600;700&display=swap`;
|
||||||
|
} else {
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.id = 'dynamic-font';
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@300;400;500;600;700&display=swap`;
|
||||||
|
document.head.appendChild(link);
|
||||||
|
}
|
||||||
|
root.style.setProperty('--font-sans', `"${settings.fontFamily}", sans-serif`);
|
||||||
|
document.body.style.fontFamily = `"${settings.fontFamily}", sans-serif`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('message', handleMessage);
|
||||||
|
return () => window.removeEventListener('message', handleMessage);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -105,3 +105,14 @@
|
||||||
@apply inline-flex items-center justify-center px-4 py-2 bg-tech-text text-white rounded font-mono text-xs font-bold uppercase tracking-widest transition-all hover:bg-slate-800 active:scale-95 shadow-sm;
|
@apply inline-flex items-center justify-center px-4 py-2 bg-tech-text text-white rounded font-mono text-xs font-bold uppercase tracking-widest transition-all hover:bg-slate-800 active:scale-95 shadow-sm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ThemeListener } from './components/layout/ThemeListener';
|
||||||
import React, { lazy, Suspense } from 'react';
|
import React, { lazy, Suspense } from 'react';
|
||||||
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
|
@ -28,7 +29,8 @@ export default function App() {
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ScrollToTop />
|
<ScrollToTop />
|
||||||
<Suspense fallback={<div className="min-h-screen bg-black flex items-center justify-center font-mono text-[10px] font-black uppercase tracking-[0.5em] text-tech-primary animate-pulse italic">VANTA_KERN_INIT...</div>}>
|
<Suspense fallback={<div className="overflow-x-hidden min-h-screen bg-black flex items-center justify-center font-mono text-[10px] font-black uppercase tracking-[0.5em] text-tech-primary animate-pulse italic">
|
||||||
|
<ThemeListener />VANTA_KERN_INIT...</div>}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to="/pt" replace />} />
|
<Route path="/" element={<Navigate to="/pt" replace />} />
|
||||||
|
|
||||||
|
|
|
||||||
50
Template-02/src/components/layout/ThemeListener.tsx
Normal file
50
Template-02/src/components/layout/ThemeListener.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export function ThemeListener() {
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMessage = (event: MessageEvent) => {
|
||||||
|
// Allow messages from any origin since preview is generic
|
||||||
|
if (event.data?.type === 'UPDATE_APPEARANCE') {
|
||||||
|
const settings = event.data.settings;
|
||||||
|
if (!settings) return;
|
||||||
|
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
// Update Primary Color
|
||||||
|
if (settings.primaryColor) {
|
||||||
|
root.style.setProperty('--color-brand-primary', settings.primaryColor);
|
||||||
|
root.style.setProperty('--color-brand-blue', settings.primaryColor);
|
||||||
|
root.style.setProperty('--color-brand-gold', settings.primaryColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Background Color
|
||||||
|
if (settings.backgroundColor) {
|
||||||
|
root.style.setProperty('--color-brand-bg', settings.backgroundColor);
|
||||||
|
document.body.style.backgroundColor = settings.backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Font Family
|
||||||
|
if (settings.fontFamily) {
|
||||||
|
const fontLink = document.getElementById('dynamic-font') as HTMLLinkElement;
|
||||||
|
const fontName = settings.fontFamily.replace(/ /g, '+');
|
||||||
|
if (fontLink) {
|
||||||
|
fontLink.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@300;400;500;600;700&display=swap`;
|
||||||
|
} else {
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.id = 'dynamic-font';
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@300;400;500;600;700&display=swap`;
|
||||||
|
document.head.appendChild(link);
|
||||||
|
}
|
||||||
|
root.style.setProperty('--font-sans', `"${settings.fontFamily}", sans-serif`);
|
||||||
|
document.body.style.fontFamily = `"${settings.fontFamily}", sans-serif`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('message', handleMessage);
|
||||||
|
return () => window.removeEventListener('message', handleMessage);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -137,3 +137,14 @@
|
||||||
@apply border-l-4 border-tech-primary pl-8 py-2 my-10 italic text-white bg-tech-primary/5 rounded-r-lg;
|
@apply border-l-4 border-tech-primary pl-8 py-2 my-10 italic text-white bg-tech-primary/5 rounded-r-lg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ThemeListener } from './components/layout/ThemeListener';
|
||||||
import React, { lazy, Suspense } from 'react';
|
import React, { lazy, Suspense } from 'react';
|
||||||
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
import { BrowserRouter, Routes, Route, Navigate, useParams } from 'react-router-dom';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
|
@ -31,7 +32,8 @@ export default function App() {
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ScrollToTop />
|
<ScrollToTop />
|
||||||
<Suspense fallback={<div className="min-h-screen bg-black flex items-center justify-center font-mono text-[10px] font-black uppercase tracking-[0.5em] text-tech-primary animate-pulse italic">VANTA_KERN_INIT...</div>}>
|
<Suspense fallback={<div className="overflow-x-hidden min-h-screen bg-black flex items-center justify-center font-mono text-[10px] font-black uppercase tracking-[0.5em] text-tech-primary animate-pulse italic">
|
||||||
|
<ThemeListener />VANTA_KERN_INIT...</div>}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to="/pt" replace />} />
|
<Route path="/" element={<Navigate to="/pt" replace />} />
|
||||||
|
|
||||||
|
|
|
||||||
50
Template-03/src/components/layout/ThemeListener.tsx
Normal file
50
Template-03/src/components/layout/ThemeListener.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export function ThemeListener() {
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMessage = (event: MessageEvent) => {
|
||||||
|
// Allow messages from any origin since preview is generic
|
||||||
|
if (event.data?.type === 'UPDATE_APPEARANCE') {
|
||||||
|
const settings = event.data.settings;
|
||||||
|
if (!settings) return;
|
||||||
|
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
// Update Primary Color
|
||||||
|
if (settings.primaryColor) {
|
||||||
|
root.style.setProperty('--color-brand-primary', settings.primaryColor);
|
||||||
|
root.style.setProperty('--color-brand-blue', settings.primaryColor);
|
||||||
|
root.style.setProperty('--color-brand-gold', settings.primaryColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Background Color
|
||||||
|
if (settings.backgroundColor) {
|
||||||
|
root.style.setProperty('--color-brand-bg', settings.backgroundColor);
|
||||||
|
document.body.style.backgroundColor = settings.backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Font Family
|
||||||
|
if (settings.fontFamily) {
|
||||||
|
const fontLink = document.getElementById('dynamic-font') as HTMLLinkElement;
|
||||||
|
const fontName = settings.fontFamily.replace(/ /g, '+');
|
||||||
|
if (fontLink) {
|
||||||
|
fontLink.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@300;400;500;600;700&display=swap`;
|
||||||
|
} else {
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.id = 'dynamic-font';
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@300;400;500;600;700&display=swap`;
|
||||||
|
document.head.appendChild(link);
|
||||||
|
}
|
||||||
|
root.style.setProperty('--font-sans', `"${settings.fontFamily}", sans-serif`);
|
||||||
|
document.body.style.fontFamily = `"${settings.fontFamily}", sans-serif`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('message', handleMessage);
|
||||||
|
return () => window.removeEventListener('message', handleMessage);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -69,3 +69,14 @@
|
||||||
@apply bg-gray-100 text-brand-primary px-1.5 py-0.5 rounded text-[0.9em];
|
@apply bg-gray-100 text-brand-primary px-1.5 py-0.5 rounded text-[0.9em];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue