// Main app + routing + tweaks
const { useState: useStateA, useEffect: useEffectA } = React;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"accent": "#c9a875",
"displayFont": "Cormorant Garamond",
"showAdminBar": false,
"palette": "dark"
}/*EDITMODE-END*/;
function App() {
// ---- Hash-based routing: gives every page a real URL for Google sitelinks,
// ad landing pages, and deep links (e.g. homesbyseenu.ca/#/privacy) ----
const VALID = ['home','listings','neighborhoods','about','buyer','seller','blog','contact','privacy','terms','mls','calculator'];
const readHash = () => {
const h = (window.location.hash || '').replace(/^#\/?/, '').toLowerCase();
return VALID.includes(h) ? h : 'home';
};
const [page, setPageState] = useStateA(readHash());
const setPage = (key) => {
if (key === 'home') {
// Home = base address. Strip the hash so the URL is just the domain.
if (window.location.hash) {
history.replaceState(null, '', window.location.pathname + window.location.search);
}
} else {
const target = '#/' + key;
if (window.location.hash !== target) window.location.hash = target;
}
setPageState(key);
// Always jump to the top, even when re-clicking the page you're already on.
window.scrollTo({ top: 0, behavior: 'instant' });
};
// Sync when the user uses back/forward or lands on a deep link
useEffectA(() => {
const onHash = () => setPageState(readHash());
window.addEventListener('hashchange', onHash);
return () => window.removeEventListener('hashchange', onHash);
}, []);
const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
// Reset scroll on page change
useEffectA(() => {
window.scrollTo({ top: 0, behavior: 'instant' });
}, [page]);
// Apply tweaks → CSS vars
useEffectA(() => {
const root = document.documentElement;
root.style.setProperty('--gold', tweaks.accent);
// Soft variant
const hex = tweaks.accent;
root.style.setProperty('--gold-soft', hex + '24');
root.style.setProperty('--serif', `"${tweaks.displayFont}", "EB Garamond", Georgia, serif`);
if (tweaks.palette === 'light') {
root.style.setProperty('--ink', '#f4f1ec');
root.style.setProperty('--ink-soft', '#ebe7df');
root.style.setProperty('--graphite', '#d8d2c4');
root.style.setProperty('--cream', '#1a1a1a');
root.style.setProperty('--cream-soft', '#3a3a3a');
root.style.setProperty('--muted', '#7a7a7a');
root.style.setProperty('--muted-2', '#9a9a9a');
root.style.setProperty('--hairline', 'rgba(20,20,20,0.12)');
root.style.setProperty('--hairline-strong', 'rgba(20,20,20,0.22)');
} else {
root.style.setProperty('--ink', '#0e1216');
root.style.setProperty('--ink-soft', '#141a1f');
root.style.setProperty('--graphite', '#1f262d');
root.style.setProperty('--cream', '#ece5d4');
root.style.setProperty('--cream-soft', '#d8d0bc');
root.style.setProperty('--muted', '#8a8474');
root.style.setProperty('--muted-2', '#6b6657');
root.style.setProperty('--hairline', 'rgba(236, 229, 212, 0.12)');
root.style.setProperty('--hairline-strong', 'rgba(236, 229, 212, 0.22)');
}
}, [tweaks.accent, tweaks.displayFont, tweaks.palette]);
const renderPage = () => {
switch (page) {
case 'home': return