// tweaks-app.jsx — small bridge between TweaksPanel and the static page. // The page is canonical HTML for direct-edit; this script just toggles // theme, swaps the client name, recolors the accent, etc. const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "client": "", "greeting": "Ciao", "date": "Luglio 2026", "theme": "dark", "accent": "#3b5f4a", "showWhatsApp": true, "whatsappNumber": "+39 327 444 6400", "email": "info@albertomaddaloni.com" }/*EDITMODE-END*/; const ACCENTS = [ "#b85a2c", // terracotta (default) "#7a3f2a", // bruciato "#3b5f4a", // sage scuro "#1f3a5f", // navy notturno "#8a7a52", // ottone ]; // ── Share-link helpers ────────────────────────────────────────────────────── // "client" / "email" / "whatsappNumber" are reversed-and-Base64ed in the URL // so the bar doesn't reveal the client's name at a glance. Pure cosmetic — // the JS that decodes is public, so this is masking not encryption. Tema / // accent / toggle stay in clear text (they don't identify people and keep // the URL short). function encodeMasked(s) { try { const reversed = String(s).split('').reverse().join(''); return btoa(unescape(encodeURIComponent(reversed))); } catch (e) { return ''; } } function decodeMasked(s) { try { const reversed = decodeURIComponent(escape(atob(s))); return reversed.split('').reverse().join(''); } catch (e) { return null; } } function readUrlOverrides() { const p = new URLSearchParams(window.location.search); const out = {}; const c = p.get('c'); if (c) { const v = decodeMasked(c); if (v) out.client = v; } const em = p.get('em'); if (em) { const v = decodeMasked(em); if (v) out.email = v; } const wa = p.get('wa'); if (wa) { const v = decodeMasked(wa); if (v) out.whatsappNumber = v; } const g = p.get('g'); if (g) { const v = decodeMasked(g); if (v) out.greeting = v; } const d = p.get('d'); if (d) out.date = d; const th = p.get('th'); if (th === 'light' || th === 'dark') out.theme = th; const a = p.get('a'); if (a && /^#[0-9a-fA-F]{6}$/.test(a)) out.accent = a; const w = p.get('w'); if (w === '0' || w === '1') out.showWhatsApp = w === '1'; return out; } // Builds an URL that only includes params for values diverging from // defaults — keeps the link as short as possible. function buildShareUrl(t) { const p = new URLSearchParams(); if (t.client && t.client !== TWEAK_DEFAULTS.client) p.set('c', encodeMasked(t.client)); if (t.theme && t.theme !== TWEAK_DEFAULTS.theme) p.set('th', t.theme); if (t.accent && t.accent !== TWEAK_DEFAULTS.accent) p.set('a', t.accent); if (t.email && t.email !== TWEAK_DEFAULTS.email) p.set('em', encodeMasked(t.email)); if (t.showWhatsApp !== TWEAK_DEFAULTS.showWhatsApp) p.set('w', t.showWhatsApp ? '1' : '0'); if (t.whatsappNumber && t.whatsappNumber !== TWEAK_DEFAULTS.whatsappNumber) { p.set('wa', encodeMasked(t.whatsappNumber)); } if (t.greeting && t.greeting !== TWEAK_DEFAULTS.greeting) p.set('g', encodeMasked(t.greeting)); if (t.date && t.date !== TWEAK_DEFAULTS.date) p.set('d', t.date); const qs = p.toString(); const base = `${location.origin}${location.pathname}`; return qs ? `${base}?${qs}` : base; } function App() { // URL overrides win over the defaults baked into this file, but we read the // URL only once at mount: if the user edits in the panel, those edits aren't // clobbered by a re-read. const initial = React.useMemo( () => ({ ...TWEAK_DEFAULTS, ...readUrlOverrides() }), [], ); const [t, setTweak] = useTweaks(initial); const [copied, setCopied] = React.useState(false); // Apply theme + accent + content bindings live React.useEffect(() => { document.body.setAttribute('data-theme', t.theme || 'light'); document.documentElement.style.setProperty('--accent', t.accent || '#b85a2c'); // Greeting + client name (hero), date (frame address + signature), footer. // Greeting is a free prefix ("Ciao" default, "Gentile" etc.) joined to the // name with a plain space — reads right for formal and informal openers. // Empty name → greeting alone; empty greeting/date → fall back to defaults. const safe = (t.client || '').trim(); const greet = (t.greeting || '').trim() || TWEAK_DEFAULTS.greeting; const dateStr = (t.date || '').trim() || TWEAK_DEFAULTS.date; document.querySelectorAll('[data-bind="greeting"]').forEach((el) => { el.textContent = greet; }); document.querySelectorAll('[data-bind="client"]').forEach((el) => { el.textContent = safe ? ` ${safe}` : ''; }); document.querySelectorAll('[data-bind="date"]').forEach((el) => { el.textContent = dateStr; }); document.querySelectorAll('[data-bind="frame-address"]').forEach((el) => { el.textContent = safe ? `Per ${safe} · ${dateStr}` : dateStr; }); document.querySelectorAll('[data-bind="foot-address"]').forEach((el) => { el.textContent = safe ? `Presentazione per ${safe}` : 'Presentazione'; }); document.title = safe ? `Alberto Maddaloni — Presentazione per ${safe}` : 'Alberto Maddaloni — Presentazione'; // Contact block: email + optional whatsapp const block = document.querySelector('[data-bind="contact-block"]'); if (block) { const emailRow = block.querySelector('a[href^="mailto:"]'); if (emailRow) { emailRow.setAttribute('href', `mailto:${t.email || ''}`); const val = emailRow.querySelector('.val'); if (val) val.textContent = t.email || ''; } const waRow = block.querySelector('[data-contact="whatsapp"]'); if (waRow) { waRow.style.display = t.showWhatsApp ? '' : 'none'; const num = (t.whatsappNumber || '').trim(); const digits = num.replace(/[^\d]/g, ''); waRow.setAttribute('href', digits ? `https://wa.me/${digits}` : '#'); const val = waRow.querySelector('.val'); if (val) val.textContent = num; } } }, [t.theme, t.accent, t.client, t.greeting, t.date, t.email, t.showWhatsApp, t.whatsappNumber]); const copyShareLink = async () => { const url = buildShareUrl(t); try { await navigator.clipboard.writeText(url); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch (e) { // Clipboard API can fail in non-HTTPS or older browsers — fallback to // a prompt so the user can still grab the URL manually. window.prompt('Copia il link:', url); } }; return ( setTweak('client', v)} /> setTweak('greeting', v)} /> setTweak('date', v)} /> setTweak('theme', v)} /> setTweak('accent', v)} /> setTweak('email', v)} /> setTweak('showWhatsApp', v)} /> {t.showWhatsApp && ( setTweak('whatsappNumber', v)} /> )} ); } ReactDOM.createRoot(document.getElementById('tweaks-root')).render();