/* global React */ // ============================================ // A_LIZ HAIRDRESSER — Home page // ============================================ const { SERVICES, PARTNERS, REVIEWS, GALLERY } = window.AL_DATA; const { useLang, useT, useRoute, useReveal, useTilt, useCountUp, Icon, CtaStrip, WA_LINK, BrandLogo, usePageSEO } = window; const { useState, useEffect, useRef, useMemo, useCallback } = React; // ========== PETALS ========== function Petals({ count = 18 }) { // Pre-compute petal placements so they're stable across renders const petals = React.useMemo( () => Array.from({ length: count }).map((_, i) => { const left = Math.random() * 100; const delay = -Math.random() * 18; const fall = 16 + Math.random() * 14; const sway = 4 + Math.random() * 5; const scale = 0.6 + Math.random() * 0.9; const op = 0.12 + Math.random() * 0.22; return { left, delay, fall, sway, scale, op, key: i }; }), [count] ); return (
{petals.map((p) => ( ))}
); } // ========== FLOW DIVIDER ========== function FlowDivider() { return ( ); } // ========== HERO ========== function Hero() { const t = useT(); const { lang } = useLang(); const { go } = useRoute(); const stageRef = useRef(null); const [slide, setSlide] = useState(0); const [prevSlide, setPrevSlide] = useState(null); const slideIdxRef = useRef(0); slideIdxRef.current = slide; const goToSlide = useCallback((next) => { if (next === slideIdxRef.current) return; setPrevSlide(slideIdxRef.current); setSlide(next); setTimeout(() => setPrevSlide(null), 980); }, []); const slidesData = [ { src: "assets/img/hero-2.webp", label: "SALON", title: "Behind the chair" }, { src: "assets/img/style-3.webp", label: "RENK", title: "Honey highlights" }, { src: "assets/img/style-1.webp", label: "FÖN", title: "Soft volume wave" }, { src: "assets/img/style-6.webp", label: "OMBRÉ", title: "Caramel gradient" }, ]; // Hero marquee: rAF ile kaydir useEffect(() => { const el = document.querySelector('.marquee-track'); if (!el) return; if (el.getAnimations) el.getAnimations().forEach(a => a.cancel()); let offset = 0, lastTs = null, paused = false, raf; const step = (ts) => { if (lastTs !== null && !paused) { const dt = Math.min(ts - lastTs, 50); const total = el.scrollWidth / 2; if (total > 0) { offset -= (total / 42000) * dt; if (offset < -total) offset += total; el.style.cssText = `transform: translateX(${offset}px) !important;`; } } lastTs = ts; raf = requestAnimationFrame(step); }; raf = requestAnimationFrame(step); const p = () => { paused = true; }; const r = () => { paused = false; lastTs = null; }; el.addEventListener('mouseenter', p); el.addEventListener('mouseleave', r); return () => { cancelAnimationFrame(raf); el.removeEventListener('mouseenter', p); el.removeEventListener('mouseleave', r); el.style.transform = ''; }; }, []); // Slide carousel useEffect(() => { const tm = setInterval(() => { const next = (slideIdxRef.current + 1) % slidesData.length; goToSlide(next); }, 5800); return () => clearInterval(tm); }, [slidesData.length, goToSlide]); // Mouse parallax tilt useEffect(() => { const el = stageRef.current; if (!el) return; const onMove = (e) => { const rect = el.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width - 0.5; const y = (e.clientY - rect.top) / rect.height - 0.5; el.style.transform = `rotateX(${-y * 6}deg) rotateY(${x * 6}deg) translateZ(0)`; }; const onLeave = () => { el.style.transform = `rotateX(0) rotateY(0) translateZ(0)`; }; const parent = el.parentElement; parent.addEventListener("mousemove", onMove); parent.addEventListener("mouseleave", onLeave); return () => { parent.removeEventListener("mousemove", onMove); parent.removeEventListener("mouseleave", onLeave); }; }, []); // Hero phrase tokens per lang (5 spans) const phraseMap = { tr: ["Boğaz'ın", "yakınında", "seçkin bir", "lüks", "salon."], en: ["Quiet", "luxury,", "by the", "Bosphorus", "salon."], ar: ["هدوء", "الفخامة", "على ضفاف", "البوسفور", "."], ru: ["Тихая", "роскошь", "у", "Босфора", "."], it: ["Lusso", "silenzioso", "sul", "Bosforo", "."], de: ["Stille", "Eleganz", "am", "Bosporus", "."], fr: ["Le luxe", "discret,", "au bord du", "Bosphore", "."], es: ["Lujo", "silencioso", "junto al", "Bósforo", "."], }; const phrase = phraseMap[lang] || phraseMap.tr; return (
{/* ── TOP: Full-width cinematic image carousel ── */}
{slidesData.map((s, i) => ( {`A_Liz ))}
{slidesData.map((_, i) => ( goToSlide(i)} /> ))}
{/* ── BOTTOM: Text content on clean background ── */}
{t("hero_eyebrow")}

{phrase[0]}{" "} {phrase[1]}{" "} {phrase[2]}{" "} {phrase[3]}{" "} {phrase[4]}

{t("hero_lede")}

{t("hero_meta_1_k")} {t("hero_meta_1_v")}
{t("hero_meta_2_k")} {t("hero_meta_2_v")}
{t("hero_meta_3_k")} {t("hero_meta_3_v")}
{/* ── Brand marquee ── */}
{[1, 2].map((dup) => (
))}
); } // Tiltable service card function ServiceCard({ svc, idx, lang }) { const tilt = useTilt({ max: 6, scale: 1.03 }); const { go } = useRoute(); return ( go('services')}>
{String(idx + 1).padStart(2, "0")} / 14

{svc.names[lang] || svc.names.tr}

{lang !== "en" &&
{svc.names.en}
}
); } // ========== SERVICES (home preview) ========== function ServicesPreview() { const t = useT(); const { lang } = useLang(); const { go } = useRoute(); const ref = useReveal(); const [isMobile, setIsMobile] = useState(false); useEffect(() => { const check = () => setIsMobile(window.innerWidth <= 640); check(); window.addEventListener('resize', check); return () => window.removeEventListener('resize', check); }, []); // Mobile: show 4, Desktop: show 8 const showing = SERVICES.slice(0, isMobile ? 4 : 8); return (
{t("svc_eyebrow")}

{t("svc_title")}

{t("svc_lede")}

go('services')}> {t("cta_view_all")} ({SERVICES.length})
{showing.map((svc, i) => ( ))}
{/* Mobile only: "Tüm Hizmetler" CTA */} {isMobile && (
go('services')}> {t("cta_view_all")} ({SERVICES.length})
)}
); } // ========== BEFORE / AFTER ========== function BeforeAfter() { const t = useT(); const { lang } = useLang(); const { go } = useRoute(); const ref = useReveal(); const sliderRef = useRef(null); const [pos, setPos] = useState(50); const [pairIdx, setPairIdx] = useState(0); const pairs = [ { before: "assets/img/style-6.webp", after: "assets/img/style-8.webp", cat: { tr: "Renk", en: "Colour", ar: "صبغة", ru: "Цвет", it: "Colore", de: "Farbe", fr: "Couleur", es: "Color" }, label: { tr: "Koyu → Bakır Kızıl", en: "Dark → Copper Red", ar: "غامق → نحاسي", ru: "Тёмный → Медный", it: "Scuro → Ramato", de: "Dunkel → Kupferrot", fr: "Foncé → Cuivré", es: "Oscuro → Cobrizo" }, }, { before: "assets/img/style-4.webp", after: "assets/img/style-1.webp", cat: { tr: "Kesim", en: "Cut", ar: "قص", ru: "Стрижка", it: "Taglio", de: "Schnitt", fr: "Coupe", es: "Corte" }, label: { tr: "Uzun → Soft Bob", en: "Long → Soft Bob", ar: "طويل → بوب ناعم", ru: "Длинный → Софт Боб", it: "Lungo → Soft Bob", de: "Lang → Soft Bob", fr: "Long → Soft Bob", es: "Largo → Soft Bob" }, }, { before: "https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?w=600&h=750&fit=crop&crop=faces,top", after: "https://images.unsplash.com/photo-1487412947147-5cebf100ffc2?w=600&h=750&fit=crop&crop=faces,top", cat: { tr: "Makyaj", en: "Makeup", ar: "مكياج", ru: "Макияж", it: "Trucco", de: "Makeup", fr: "Maquillage", es: "Maquillaje" }, label: { tr: "Doğal → Editorial", en: "Natural → Editorial", ar: "طبيعي → تحريري", ru: "Натуральный → Editorial", it: "Naturale → Editorial", de: "Natürlich → Editorial", fr: "Naturel → Éditorial", es: "Natural → Editorial" }, }, { before: "assets/img/style-4.webp", after: "assets/img/style-7.webp", cat: { tr: "Ombré", en: "Ombré", ar: "أومبري", ru: "Омбре", it: "Ombré", de: "Ombré", fr: "Ombré", es: "Ombré" }, label: { tr: "Tek Ton → Caramel", en: "Solid → Caramel", ar: "لون واحد → كراميل", ru: "Один тон → Карамель", it: "Uniforme → Caramello", de: "Einfarbig → Karamell", fr: "Uni → Caramel", es: "Liso → Caramelo" }, }, { before: "https://images.pexels.com/photos/3997388/pexels-photo-3997388.jpeg?auto=compress&cs=tinysrgb&w=600&h=750&fit=crop", after: "https://images.pexels.com/photos/704815/pexels-photo-704815.jpeg?auto=compress&cs=tinysrgb&w=600&h=750&fit=crop", cat: { tr: "Tırnak", en: "Nails", ar: "أظافر", ru: "Ногти", it: "Unghie", de: "Nägel", fr: "Ongles", es: "Uñas" }, label: { tr: "Klasik → Couture", en: "Classic → Couture", ar: "كلاسيكي → كوتور", ru: "Классика → Couture", it: "Classico → Couture", de: "Klassisch → Couture", fr: "Classique → Couture", es: "Clásico → Couture" }, }, ]; const current = pairs[pairIdx]; const move = (clientX) => { if (!sliderRef.current) return; const rect = sliderRef.current.getBoundingClientRect(); const x = clientX - rect.left; const p = Math.max(0, Math.min(100, (x / rect.width) * 100)); setPos(p); }; const onMouseMove = (e) => { if (e.buttons === 1) move(e.clientX); }; const onMouseDown = (e) => { move(e.clientX); }; const onTouchMove = (e) => { if (e.touches[0]) move(e.touches[0].clientX); }; // Switching pair: keep handle position, just swap images const changePair = (idx) => { setPairIdx(idx); setPos(50); }; return (
{t("ga_eyebrow")}

{t("ga_title")}

{t("svc_lede")}

{pairs.map((p, i) => ( ))}
go('gallery')}> {t("cta_view_all")}
Before hair transformation at A_Liz Hairdresser Istanbul After hair transformation at A_Liz Hairdresser Istanbul
Before
After
{current.cat[lang] || current.cat.tr} {current.label[lang] || current.label.tr}
); } // ========== RESULTS (Hakiki Sonuçlar) — web only ========== function Results() { const t = useT(); const { lang } = useLang(); const ref = useReveal(); const results = window.AL_DATA?.RESULTS_GALLERY || GALLERY.slice(0, 6); return (
{t("rv_eyebrow")}

Hakiki Sonuçlar

{results.map((item, i) => ( { e.preventDefault(); window.AL_NAV('gallery'); }}> {`A_Liz
{item.t || item.name?.[lang] || item.name?.en || ""}
))}

Sözsüz testimonial — sonuçlar kendisi için konuşuyor

{ e.preventDefault(); window.AL_NAV('gallery'); }}> Tüm Sonuçları Gör
); } // ========== PARTNERS ========== function Partners() { const t = useT(); const ref = useReveal(); const brands = ["schwarzkopf", "loreal", "olaplex", "kerastase", "wella", "rallis"]; return (
{t("pt_eyebrow")}
{brands.map((b) => )}
); } // ========== SCROLLING SHOWCASE (alternating marquee) ========== function Showcase() { const t = useT(); // Force autoplay across all browsers — solves Safari/iOS/Chrome edge cases useEffect(() => { const videos = document.querySelectorAll('.showcase-video'); const tryPlay = (v) => { v.muted = true; const p = v.play(); if (p && p.catch) p.catch(() => {}); }; videos.forEach(v => { v.muted = true; v.playsInline = true; v.setAttribute('webkit-playsinline', ''); tryPlay(v); v.addEventListener('canplay', () => tryPlay(v)); v.addEventListener('loadeddata', () => tryPlay(v)); }); // Retry on first user gesture (iOS Low Power Mode fallback) const onGesture = () => videos.forEach(tryPlay); window.addEventListener('touchstart', onGesture, { once: true, passive: true }); window.addEventListener('click', onGesture, { once: true }); // Pause when off-screen to save CPU/battery const obs = new IntersectionObserver(entries => { entries.forEach(e => { if (e.isIntersecting) tryPlay(e.target); else e.target.pause(); }); }, { threshold: 0.1 }); videos.forEach(v => obs.observe(v)); return () => { window.removeEventListener('touchstart', onGesture); window.removeEventListener('click', onGesture); obs.disconnect(); }; }, []); return (
{t("sc_eyebrow")}

{t("sc_title")}

{/* Video Promo Block */}
); } // ========== INSTAGRAM ========== const IG_PROFILE = "https://www.instagram.com/a_lizhairdresser"; function InstagramFeed() { const t = useT(); const { lang } = useLang(); const ref = useReveal(); const copy = { sub: { tr: "Istanbul'dan anlık kareler.", en: "Live moments from Istanbul.", ar: "لحظات حية من إسطنبول.", ru: "Живые моменты из Стамбула.", de: "Livebilder aus Istanbul.", fr: "Moments en direct d'Istanbul.", it: "Momenti live da Istanbul.", es: "Momentos en vivo desde Istanbul." }, followers: { tr: "Takipçi", en: "Followers", ar: "متابع", ru: "Подписчиков", it: "Follower", de: "Follower", fr: "Abonnés", es: "Seguidores" }, posts: { tr: "Gönderi", en: "Posts", ar: "منشور", ru: "Постов", it: "Post", de: "Beiträge", fr: "Posts", es: "Posts" }, cta: { tr: "Takip Et", en: "Follow", ar: "تابعنا", ru: "Подписаться", it: "Seguici", de: "Folgen", fr: "Suivre", es: "Seguir" }, }; const L = (o) => o[lang] || o.en; return (
{/* ── MOBILE: Stories Ring Layout ── */}
A_Liz Hairdresser
@a_lizhairdresser
A_Liz Hairdresser · Istanbul
120+ {L(copy.posts)}
4.800+ {L(copy.followers)}
4.9★ Google
{L(copy.cta)}

{L(copy.sub)}

{/* ── WEB & TABLET: Existing Pro Layout ── */}
{/* Top row: eyebrow + handle */}
{t("ig_eyebrow")} @a_lizhairdresser
{/* Divider */}
{/* Middle: stats + tagline */}
4.800+ {L(copy.followers)}
120+ {L(copy.posts)}
4.9 ★ Google

{L(copy.sub)}

{/* Divider */}
{/* Bottom: CTA */}
{L(copy.cta)} · @a_lizhairdresser Istanbul · Sultanahmet · 2018
{/* end shell */}
); } // ========== LOCATION / MAP ========== function Location() { const t = useT(); const { go } = useRoute(); const ref = useReveal(); return (
{t("loc_eyebrow")}

{t("loc_title")}

{t("loc_address_k")} {t("loc_address_v")} {t("loc_address_sub")}
{t("loc_hours_k")} {t("loc_hours_v")} {t("loc_hours_sub")}
{t("loc_phone_k")} {t("loc_phone_v")}
{t("loc_email_k")} {t("loc_email_v")}
go('appointment')}> {t("cta_book")}