// Shared layout: top nav + footer. // Exposes and , plus useTweaks proxy that just calls global setTweak. const { useState, useEffect, useRef } = React; function YouTubeGlyph({ size = 18 }) { return ( ); } function LinkedInGlyph({ size = 16 }) { return ( ); } const NAV_ITEMS = [ { labelKey: "nav.home", href: "index.html#top", key: "home", children: [ { labelKey: "nav.aboutUs", href: "about.html" }, ], }, { labelKey: "nav.services", href: "services.html", key: "services" }, { labelKey: "nav.courses", href: "courses.html", key: "courses" }, { labelKey: "nav.booksTemplates", href: "books-templates.html", key: "books-templates" }, { labelKey: "nav.resources", href: "resources.html", key: "resources", children: [ { labelKey: "nav.freeDownloads", href: "free-downloads.html" }, { labelKey: "nav.articles", href: "articles.html" }, { labelKey: "nav.youtube", href: SITE.ytChannel(), external: true }, ], }, { labelKey: "nav.pricing", href: "enroll.html", key: "pricing" }, ]; function LangSwitcher() { const cur = window.CURRENT_LANG || "en"; const langs = window.SUPPORTED_LANGS || ["en"]; return (
{langs.map((lng, i) => ( {i > 0 && /} ))}
); } function SiteNav({ active }) { return ( ); } function ContactForm({ id }) { const { useState, useEffect } = React; const [status, setStatus] = useState(""); useEffect(() => { if (window.location.hash === "#" + (id || "contact")) { const el = document.getElementById(id || "contact"); if (el) setTimeout(() => el.scrollIntoView({ behavior: "smooth" }), 200); } }, []); async function handleSubmit(e) { e.preventDefault(); const f = e.target; setStatus("sending"); try { const res = await fetch("contact.php", { method: "POST", body: new FormData(f) }); const data = await res.json(); if (data.ok) { setStatus("sent"); f.reset(); } else setStatus("error"); } catch (err) { setStatus("error"); } } return (
{t("contact.eyebrow")}

{t("contact.title")}

{t("contact.sub")}

{status === "sent" &&

{t("contact.success")}

} {status === "error" &&

{t("contact.error")}

}
); } function SiteFooter() { return ( ); } // Re-render lucide icons on each render pass. function useLucideIcons(deps) { useEffect(() => { if (window.lucide && window.lucide.createIcons) { window.lucide.createIcons(); } }, deps); } // Apply tweak-driven body classes (theme + density) function useTweakBodyClasses({ themeColor, density }) { useEffect(() => { const body = document.body; body.classList.remove("theme-graphite", "theme-emerald", "theme-gold"); if (themeColor && themeColor !== "navy") body.classList.add(`theme-${themeColor}`); body.classList.toggle("density-compact", density === "compact"); }, [themeColor, density]); } window.SiteNav = SiteNav; window.SiteFooter = SiteFooter; window.ContactForm = ContactForm; window.useLucideIcons = useLucideIcons; window.useTweakBodyClasses = useTweakBodyClasses; window.YouTubeGlyph = YouTubeGlyph; window.LinkedInGlyph = LinkedInGlyph;