/* Shared site chrome + widgets. DS components come from the bundle namespace. */ const DS = window.WeddingSalonDesignSystem_69a5c8; const { Button, Icon, Card, TextInput, Select, Checkbox, TestimonialCard, Badge } = DS; const BIZ = { name: "Wedding Salon", phoneDisplay: "054-834-6620", phoneHref: "tel:+972548346620", whatsapp: "https://wa.me/972548346620", email: "latishovi@gmail.com", instagram: "@weddingsalon", }; const LANGS = ["he", "ru", "en"]; /* Language state lives on (lang + dir) and in localStorage. */ const LangCtx = React.createContext(null); function LangProvider({ page, children }) { const [lang, setLang] = React.useState(() => { try { const s = localStorage.getItem("ws-lang"); if (LANGS.includes(s)) return s; } catch (e) {} return "he"; }); const t = window.I18N[lang]; React.useEffect(() => { document.documentElement.lang = lang; document.documentElement.dir = t.dir; const m = t.meta[page]; if (m) { document.title = m[0]; const d = document.querySelector('meta[name="description"]'); if (d) d.setAttribute("content", m[1]); } try { localStorage.setItem("ws-lang", lang); } catch (e) {} }, [lang, page, t]); return {children}; } const useT = () => React.useContext(LangCtx); function LangSwitch() { const { lang, setLang, t } = useT(); return (
{LANGS.map((code, i) => ( {i > 0 && } ))}
); } const navLinks = (t) => [ { key: "home", label: t.nav.home, href: "index.html" }, { key: "about", label: t.nav.about, href: "index.html#story" }, { key: "services", label: t.nav.services, href: "index.html#services" }, { key: "portfolio", label: t.nav.portfolio, href: "index.html#portfolio" }, { key: "contact", label: t.nav.contact, href: "contact.html" }, ]; /* Scroll reveal — one observer per opted-in element. */ function Reveal({ children, delay = 0, as = "div", className = "", style }) { const ref = React.useRef(null); React.useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver( (es) => es.forEach((e) => { if (e.isIntersecting) { setTimeout(() => el.classList.add("in"), delay); io.unobserve(el); } }), { rootMargin: "0px 0px -8% 0px", threshold: 0.05 } ); io.observe(el); return () => io.disconnect(); }, [delay]); return React.createElement(as, { ref, className: "rv " + className, style }, children); } /* Stock photography (Unsplash, free license) keyed by slot id. Credit is required and renders in the slot; a user-dropped photo replaces src and hides it. */ const PHOTOS = { "home-hero": ["images/hero-dress.png"], "svc-dress": ["photo-1521467752200-3bccf80f16ed", "Thomas AE", "thomasae"], "svc-photo": ["photo-1591604466107-ec97de577aff", "Eugenia Pan'kiv", "eugenivy_now"], "home-story": ["photo-1532454781337-fc3edff34f91", "Duo Chen", "duochenphotography"], "pf-1": ["photo-1549416878-b9ca95e26903", "Maria Orlova", "orlovamaria"], "pf-2": ["photo-1502955422409-06e43fd3eff3", "Anna Vi", "anna_vi_travel"], "pf-4": ["photo-1599142296733-1c1f2073e6de", "Brittney Weng", "brittneyweng"], "pf-5": ["photo-1585241920473-b472eb9ffbae", "Jonathan Borba", "jonathanborba"], "pf-6": ["photo-1621369663005-68a558655fad", "Filipp Romanovski", "filipp_roman_photography"], "pf-7": ["flagged/photo-1578317767641-c2a23b16b814", "NIKITA SHIROKOV", "shirokov"], "contact-hero": ["photo-1492175742197-ed20dc5a6bed", "Petr Ovralov", "petrov"], "dr-hero": ["images/hero-dress.png"], "dr-intro": ["photo-1521467752200-3bccf80f16ed", "Thomas AE", "thomasae"], "dr-g1": ["photo-1622277430358-f4d134452e2e", "Asdrubal luna", "infectedluna"], "dr-g2": ["photo-1502955422409-06e43fd3eff3", "Anna Vi", "anna_vi_travel"], "dr-g3": ["photo-1621369663005-68a558655fad", "Filipp Romanovski", "filipp_roman_photography"], "dr-g4": ["photo-1591221662157-6f62de5508eb", "Cate Bligh", "catebligh"], "dr-g5": ["photo-1572322633904-ebbd90cb2f9b", "Anthony Espinosa", "thony_espi"], "dr-g6": ["photo-1569849324286-55b6c5f925e5", "Anaïs MURITH", "nanarose"], "dr-d1": ["flagged/photo-1578317767641-c2a23b16b814", "NIKITA SHIROKOV", "shirokov"], "dr-d2": ["photo-1599142296733-1c1f2073e6de", "Brittney Weng", "brittneyweng"], "dr-d3": ["photo-1549416878-b9ca95e26903", "Maria Orlova", "orlovamaria"], "dr-d4": ["photo-1532454781337-fc3edff34f91", "Duo Chen", "duochenphotography"], "dr-d5": ["photo-1585241920473-b472eb9ffbae", "Jonathan Borba", "jonathanborba"], "dr-d6": ["photo-1492175742197-ed20dc5a6bed", "Petr Ovralov", "petrov"], "ph-hero": ["photo-1622277430358-f4d134452e2e", "Asdrubal luna", "infectedluna"], "ph-intro": ["photo-1591604466107-ec97de577aff", "Eugenia Pan'kiv", "eugenivy_now"], "ph-g1": ["photo-1549416878-b9ca95e26903", "Maria Orlova", "orlovamaria"], "ph-g2": ["photo-1599142296733-1c1f2073e6de", "Brittney Weng", "brittneyweng"], "ph-g3": ["photo-1585241920473-b472eb9ffbae", "Jonathan Borba", "jonathanborba"], "ph-g4": ["photo-1502955422409-06e43fd3eff3", "Anna Vi", "anna_vi_travel"], "ph-g5": ["photo-1521467752200-3bccf80f16ed", "Thomas AE", "thomasae"], "ph-g6": ["photo-1621369663005-68a558655fad", "Filipp Romanovski", "filipp_roman_photography"], "ph-g7": ["photo-1532454781337-fc3edff34f91", "Duo Chen", "duochenphotography"], "ph-s1": ["photo-1492175742197-ed20dc5a6bed", "Petr Ovralov", "petrov"], "ph-s2": ["photo-1532454781337-fc3edff34f91", "Duo Chen", "duochenphotography"], "ph-s4": ["flagged/photo-1578317767641-c2a23b16b814", "NIKITA SHIROKOV", "shirokov"], "svc-makeup": ["photo-1636023730877-233b9237d4ec", "Alena Plotnikova", "alena_horoshaya"], "pf-3": ["photo-1709477542149-f4e0e21d590b", "LOLA AZIZADA", "kalpa_mahagamage"], "mk-hero": ["photo-1594465919760-441fe5908ab0", "Amir Seilsepour", "amiresel"], "mk-intro": ["photo-1636023730877-233b9237d4ec", "Alena Plotnikova", "alena_horoshaya"], "mk-g1": ["photo-1709477542149-f4e0e21d590b", "LOLA AZIZADA", "kalpa_mahagamage"], "mk-g2": ["photo-1709477542170-f11ee7d471a0", "LOLA AZIZADA", "kalpa_mahagamage"], "mk-g3": ["photo-1630084775816-7abb7383ded5", "Vince Mariel Conlu", "vimarco"], "mk-g4": ["photo-1512496015851-a90fb38ba796", "Jazmin Quaynor", "jazminantoinette"], "mk-g5": ["photo-1511923199659-1c16881689de", "Jake Peterson", "jake101"], "ph-s3": ["photo-1550005809-91ad75fb315f", "Olivia Bauso", "ohhbee"], "rel-makeup": ["photo-1709477542170-f11ee7d471a0", "LOLA AZIZADA", "kalpa_mahagamage"], "rel-dresses": ["photo-1521467752200-3bccf80f16ed", "Thomas AE", "thomasae"], "rel-photo": ["photo-1585241920473-b472eb9ffbae", "Jonathan Borba", "jonathanborba"], }; /* Cutout images on a blank ground read better fully visible than cropped. */ const CONTAIN = new Set(["home-hero", "dr-hero"]); function Slot({ id, placeholder, radius = 16, style }) { const p = PHOTOS[id]; const local = p && p.length === 1; const src = p ? (local ? p[0] : "https://images.unsplash.com/" + p[0] + "?auto=format&fit=crop&w=1600&q=80") : undefined; return ( ); } function SiteHeader({ active }) { const { t } = useT(); const links = navLinks(t); const [scrolled, setScrolled] = React.useState(false); const [open, setOpen] = React.useState(false); React.useEffect(() => { const on = () => setScrolled(window.scrollY > 24); on(); window.addEventListener("scroll", on, { passive: true }); return () => window.removeEventListener("scroll", on); }, []); React.useEffect(() => { document.body.style.overflow = open ? "hidden" : ""; const esc = (e) => e.key === "Escape" && setOpen(false); window.addEventListener("keydown", esc); return () => window.removeEventListener("keydown", esc); }, [open]); return (
{BIZ.name}
{open && (
{BIZ.name}
)}
); } function FooterCol({ title, items }) { return (
{title} {items.map((it) => it.href ? {it.label} : {it.label} )}
); } function SiteFooter() { const { t } = useT(); return ( ); } function WhatsAppFab() { const { t } = useT(); return ; } /* Lightbox reads the image currently shown in a slot (stock or user-dropped). */ function useLightbox() { const { t } = useT(); const [shot, setShot] = React.useState(null); React.useEffect(() => { const esc = (e) => e.key === "Escape" && setShot(null); window.addEventListener("keydown", esc); return () => window.removeEventListener("keydown", esc); }, []); const open = (e) => { const slot = e.currentTarget.querySelector("image-slot"); const img = slot && slot.shadowRoot && slot.shadowRoot.querySelector("img"); setShot({ src: img && img.getAttribute("src"), label: e.currentTarget.getAttribute("data-label") || "" }); }; const node = shot && (
setShot(null)}>
{shot.src ? {shot.label} :

{t.pf.empty}

}
); return [open, node]; } /* Full inquiry form: validation, loading, success. */ function InquiryForm({ compact = false, onDone }) { const { t, lang } = useT(); const f = t.form; const [v, setV] = React.useState({ name: "", phone: "", email: "", date: "", service: "", note: "" }); const [err, setErr] = React.useState({}); const [state, setState] = React.useState("idle"); const set = (k) => (e) => setV({ ...v, [k]: e.target.value }); /* Service pages link in with ?service=dresses|makeup|photo, optionally &dress= or &look=, which preselect the service and open the note. */ React.useEffect(() => { const q = new URLSearchParams(location.search); const idx = { dresses: 0, makeup: 1, photo: 2 }[q.get("service")]; const named = q.get("dress") || q.get("look"); setV((p) => ({ ...p, service: f.options[idx === undefined ? 0 : idx], note: named && t.dresses ? t.dresses.askPrefix + " " + named + "." : p.note, })); setErr({}); }, [lang]); const submit = (e) => { e.preventDefault(); const next = {}; if (v.name.trim().length < 2) next.name = f.errName; if (!/^[\d\s+\-()]{9,}$/.test(v.phone.trim())) next.phone = f.errPhone; if (!compact && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v.email.trim())) next.email = f.errEmail; setErr(next); if (Object.keys(next).length) return; setState("sending"); setTimeout(() => { setState("sent"); onDone && onDone(); }, 900); }; if (state === "sent") { return (

{f.okTitle}

{f.okBody}

); } return (
{!compact && }