/* ========================================================== الحسين فود — JS المتجر (ملف واحد — يتلصق كله في «JavaScript مخصص» في سلة) الأقسام: 1) الفوتر 3) كارت الواتساب فوق الفوتر 4) الأقسام بعد السلايدر 7) آراء العملاء بالخريطة 9) كارت واتساب الأسئلة الشائعة 10) ظهور بنرات الأقسام 11) نعومة الهيدر 12) صفحة المنتج 13) لمسات الرئيسية أي عنصر جديد يتضاف كقسم جديد في آخر الملف. ========================================================== */ /* ---------- 1) الفوتر: بيتبني مرة واحدة مكان فوتر الثيم (القايمة والدفع والسجل من لوحة سلة) ---------- */ (function () { 'use strict'; var HF = { logo: 'https://cdn.files.salla.network/other/224742367/0e6a9e0d-2169-4ad9-b191-4061210ba5fb-original.webp', description: 'كل اللي يحتاجه مطبخك من عطارة وبهارات وأعشاب طبيعية، نختاره لك بعناية ويوصلك لين باب البيت.', linksTitle: 'روابط مهمة', sbc: 'https://eauthenticate.saudibusiness.gov.sa/certificate-details/0000194575', contacts: [ { icon: 'sicon-whatsapp2', label: '+966502399222', href: 'https://wa.me/966502399222' }, { icon: 'sicon-iphone', label: '+966502399222', href: 'tel:+966502399222' }, { icon: 'sicon-mail', label: 'alhussainfood7@gmail.com', href: 'mailto:alhussainfood7@gmail.com' } ], social: [ { icon: 'sicon-instagram', name: 'instagram', href: 'https://www.instagram.com/alhussain.food' }, { icon: 'sicon-snapchat', name: 'snapchat', href: 'https://www.snapchat.com/add/alhussain.food' }, { icon: 'sicon-tiktok', name: 'tiktok', href: 'https://www.tiktok.com/@alhussain.food' } ] }; function storeName() { try { return window.salla.config.get('store.name') || document.title; } catch (e) { return document.title; } } function template() { var home = (window.salla && salla.url && salla.url.get) ? salla.url.get('') : '/'; var contacts = HF.contacts.map(function (c) { return '' + '' + c.label + ''; }).join(''); var social = HF.social.map(function (s) { return '
  • '; }).join(''); return '' + '' + '
    ' + '' + '
    ' + '' + '

    ' + HF.description + '

    ' + '
    ' + '
    ' + '' + '
    ' + '
    ' + '
    ' + contacts + '
    ' + '' + '
    ' + '
    ' + '

    جميع الحقوق محفوظة | ' + new Date().getFullYear() + ' ' + storeName() + '

    ' + '' + '
    '; } function mount() { if (document.querySelector('footer.hf')) return; var footer = document.createElement('footer'); footer.className = 'hf'; footer.innerHTML = template(); var old = document.querySelector('footer.store-footer'); if (old) old.replaceWith(footer); else (document.querySelector('.app-inner') || document.body).appendChild(footer); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount, { once: true }); else mount(); })(); /* ---------- 3) كارت الواتساب فوق الفوتر (المحتوى باللهجة السعودية) ---------- */ (function () { 'use strict'; var CTA = { title: 'تبي كميات جملة أو عندك طلب خاص؟', text: 'راسلنا على الواتساب ونضبط لك طلبك بأحسن سعر', button: 'راسلنا واتساب', href: 'https://wa.me/966502399222?text=%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%20%D8%B9%D9%84%D9%8A%D9%83%D9%85%D8%8C%20%D8%B9%D9%86%D8%AF%D9%8A%20%D8%B7%D9%84%D8%A8%20%D8%AE%D8%A7%D8%B5%20/%20%D9%83%D9%85%D9%8A%D8%A7%D8%AA%20%D8%AC%D9%85%D9%84%D8%A9%20%D9%88%D8%A3%D8%A8%D9%8A%20%D8%A3%D8%B3%D8%AA%D9%81%D8%B3%D8%B1' }; function mount() { var footer = document.querySelector('footer.hf'); if (!footer || footer.querySelector('.hf__cta')) return; var card = document.createElement('div'); card.className = 'hf__cta'; card.innerHTML = '

    ' + CTA.title + '

    ' + CTA.text + '

    ' + '' + CTA.button + ''; footer.classList.add('hf--cta'); footer.prepend(card); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount, { once: true }); else mount(); })(); /* ---------- 4) الأقسام بعد السلايدر: نفس منطق كروت PEPHUB. الصور على سيرفر سلة، والعدد مكتوب هنا يدوي ---------- */ (function () { 'use strict'; const clamp = (v) => Math.min(1, Math.max(0, v)); const ease = (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2); const settle = (k) => 1 + 1.6 * Math.pow(k - 1, 3) + 0.6 * Math.pow(k - 1, 2); const AUTO_MS = 3000; const HOLD_MS = 6000; const TAU = 0.1; // قصور السكرول const POS_TAU = 0.28; // قصور الشريط // بالنسبة لطول الشاشة: الكروت بتبدأ قبل التثبيت بـLEAD وبتاخد C من السكرول، وبعدها وقفة X + H (نفس مقاطع PEPHUB) const LEAD = 0.25; const FORCE_SEC = 0.6; // السحب قبل ما الظهور يخلص بيكمّله في الوقت ده const C = 0.55; const X = 0.12; const H = 0.08; const IMG = 'https://cdn.files.salla.network/theme/224742367/'; const ICONS = { spices: '', herbs: '', tea: '', pantry: '', care: '', trend: '' }; const CATS = [ { key: 'spices', en: 'Spices & Seasonings', label: 'البهارات والتوابل', count: '76 منتج', href: '/البهارات-والتوابل/c1507217547', d: 'a1d5639e-c130-40a5-91dc-17ba3e7c31d4', t: 'aee4c19c-2a68-4ab7-8d0e-560ece537361', m: '8b54254c-6461-47bf-bdbf-20cec0395adf' }, { key: 'herbs', en: 'Herbs & Apothecary', label: 'الأعشاب والعطارة', count: '74 منتج', href: '/الأعشاب-والعطارة/c93953685', d: '7891e44e-fa17-4ea6-99b1-47d9b571f68e', t: '17ec4b7c-2abf-47a7-a669-e74beaa56791', m: 'f4a751e1-ea46-4386-8a1b-cfb50b251e2f' }, { key: 'tea', en: 'Tea & Coffee', label: 'الشاي والقهوة', count: '71 منتج', href: '/الشاي-والقهوة/c1466350998', d: '70d0473d-cd33-4b57-9116-181afea96c71', t: 'fd77e8fc-5ffd-47f7-b424-89389b4a5c8c', m: '36c56c07-3b0d-44ff-9a0b-ab3f906d4c74' }, { key: 'pantry', en: 'Home Pantry', label: 'مؤونة البيت', count: '63 منتج', href: '/مؤونة-البيت/c558095511', d: '819c0b8f-fb8a-472d-b5b6-c695a632be51', t: '0150a1a3-c2dc-4633-bf12-e4311ce1166e', m: 'b76f5102-497d-4a8b-83c4-3ff805389917' }, { key: 'care', en: 'Care & Beauty', label: 'العناية والجمال', count: '51 منتج', href: '/العناية-والجمال/c1291131537', d: 'f5163a4e-9b28-4a45-b661-638e7bfced8a', t: 'e7c22a2f-ef24-48e5-9548-f79aab2944bf', m: '796c7b25-0d82-40ab-b617-6cceb05ff6b8' }, { key: 'trend', en: 'Trending', label: 'الترند', count: '3 منتجات', href: '/الترند/c517093778', d: 'ea179370-3e90-44de-b03c-6fde62d357c7', t: '8048a28c-ebfb-4ef4-b83d-5308152578f2', m: 'c62a6b60-afb4-4ed4-8e6b-75fb6b9fcea2' } ]; const TRUST = [ { title: 'شحن مجاني', sub: 'للطلبات فوق 499 ر.س', icon: '' }, { title: 'دفع آمن', sub: 'مدى وأبل باي وSTC Pay', icon: '' }, { title: 'الدفع عند الاستلام', sub: 'ادفع لين يوصلك طلبك', icon: '' }, { title: 'متجر موثق', sub: 'لدى منصة الأعمال السعودية', icon: '' } ]; const trustItem = (t) => `
  • ${t.title}${t.sub}
  • `; const src = (id) => `${IMG}${id}-original.webp`; const esc = (s) => s.replace(/&/g, '&'); const card = (c, i) => `
  • ${esc(c.en)}${c.label} ${c.count}
  • `; const markup = `
      ${TRUST.map(trustItem).join('')}${TRUST.map(trustItem).join('').replace(/
    • الأقسام
    `; function setup(section) { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; const row = section.querySelector('.hf-cats__row'); const box = section.querySelector('.hf-cats__cards'); if (!row || !box) return; section.classList.add('is-live'); const stage = section.querySelector('.hf-cats__stage'); const ask = section.querySelector('.hf-cats__ask'); const hud = section.querySelector('.hf-cats__hud'); const bar = section.querySelector('.hf-cats__bar i'); const hudNow = section.querySelector('[data-now]'); const hudName = section.querySelector('[data-name]'); const items = [...row.children]; const cards = items.map((li) => li.querySelector('.hf-cats__card')); const names = cards.map((c) => c.querySelector('.hf-cats__en').textContent.trim()); const rtl = getComputedStyle(row).direction === 'rtl'; // كل قيمة بتتكتب بس لو اتغيرت const written = new WeakMap(); const put = (el, prop, value) => { let mem = written.get(el); if (!mem) written.set(el, (mem = {})); if (mem[prop] === value) return; mem[prop] = value; el.style[prop] = value; }; const flag = (el, name, on) => el.classList.toggle(name, on); let vh = stage.clientHeight; let total = 0; let max = 0; let top = 0; let target = 0; let current = 0; let pos = 0; let posTarget = 0; let last = 0; let running = false; let active = -1; let cardsOn = false; let hovering = false; let holdUntil = 0; let autoTimer = 0; let touch = null; let drag = null; let dragged = false; let forced = 0; // الظهور اللي كمّله السحب، فوق حساب السكرول let forcing = false; let lastC = 0; const stops = () => Math.max(1, cards.length - 1); const clampPos = (v) => Math.max(0, Math.min(max, v)); const snap = (v) => { if (!max) return 0; const step = max / stops(); return clampPos(Math.round(v / step) * step); }; // RTL: الكارت الجاي على الشمال، فالصباع رايح يمين = قدام const dPos = (dx) => dx * (rtl ? 1 : -1); const hold = () => { holdUntil = performance.now() + HOLD_MS; }; const scheduleAuto = () => { clearTimeout(autoTimer); if (!cardsOn || !max) return; autoTimer = setTimeout(() => { if (cardsOn && !hovering && !touch && !drag && !document.hidden && performance.now() >= holdUntil) { const step = max / stops(); const next = Math.round(posTarget / step) + 1; posTarget = next > stops() ? 0 : clampPos(next * step); kick(); } scheduleAuto(); }, AUTO_MS); }; const measure = () => { vh = stage.clientHeight; total = vh + vh * (C - LEAD + X + H); section.style.height = `${total}px`; max = Math.max(0, row.scrollWidth - document.documentElement.clientWidth); pos = clampPos(pos); posTarget = clampPos(posTarget); top = section.getBoundingClientRect().top + window.scrollY; target = window.scrollY - top; if (!running) current = target; apply(); }; const apply = () => { if (current < -vh) { forced = 0; forcing = false; } const c = Math.max(clamp((current + vh * LEAD) / (vh * C)), forced); lastC = c; const ce = ease(c); const h = max > 0 ? clamp(pos / max) : 0; const shown = ce > 0.6 && current < total - vh * 0.25; if (shown !== cardsOn) { cardsOn = shown; if (shown) scheduleAuto(); else clearTimeout(autoTimer); } flag(hud, 'is-on', ce > 0.7); flag(ask, 'is-on', ce > 0.45); items.forEach((li, i) => { const k = clamp(c * 1.6 - i * 0.12); const f = settle(k); put(li, 'transform', `translate3d(0,${((1 - f) * 0.8 * vh).toFixed(1)}px,0) rotate(${((1 - f) * -7).toFixed(2)}deg)`); }); put(row, 'transform', `translate3d(${(rtl ? -(1 - h) * max : -h * max).toFixed(1)}px,0,0)`); put(bar, 'transform', `scaleX(${h.toFixed(4)})`); const idx = ce > 0.6 ? Math.round(h * (cards.length - 1)) : -1; if (idx !== active) { if (active >= 0) items[active].classList.remove('is-active'); if (idx >= 0) { items[idx].classList.add('is-active'); hudNow.textContent = String(idx + 1).padStart(2, '0'); hudName.textContent = names[idx]; if (active >= 0 && hudNow.animate) { hudNow.animate([{ opacity: 0, transform: 'translateY(6px)' }, { opacity: 1, transform: 'none' }], { duration: 380, easing: 'cubic-bezier(.22,1,.36,1)' }); } } active = idx; } }; const loop = (now) => { const dt = Math.min(0.05, (now - last) / 1000 || 0.016); last = now; const gap = target - current; const maxLag = vh * 1.2; if (Math.abs(gap) > maxLag) current = target - Math.sign(gap) * maxLag; current += (target - current) * (1 - Math.exp(-dt / TAU)); if (Math.abs(target - current) < 0.3) current = target; if (forcing) { forced = Math.min(1, forced + dt / FORCE_SEC); if (forced === 1) forcing = false; } if (pos !== posTarget) { pos += (posTarget - pos) * (1 - Math.exp(-dt / POS_TAU)); if (Math.abs(posTarget - pos) < 0.4) pos = posTarget; } apply(); if (current !== target || pos !== posTarget || forcing) requestAnimationFrame(loop); else running = false; }; const kick = () => { if (running) return; running = true; last = performance.now(); requestAnimationFrame(loop); }; let idleTimer = 0; window.addEventListener('scroll', () => { target = window.scrollY - top; flag(section, 'is-scrolling', true); clearTimeout(idleTimer); idleTimer = setTimeout(() => flag(section, 'is-scrolling', false), 180); kick(); }, { passive: true }); let lastW = 0; window.addEventListener('resize', () => { if (window.innerWidth === lastW) return; // شريط العنوان في الموبايل بيغيّر الارتفاع بس lastW = window.innerWidth; measure(); }); lastW = window.innerWidth; // السلايدر اللي فوق طوله بيتغير لما صوره تحمّل، فمكان السكشن لازم يتقاس تاني let queued = 0; new ResizeObserver(() => { if (queued) return; queued = requestAnimationFrame(() => { queued = 0; measure(); }); }).observe(document.body); document.addEventListener('visibilitychange', kick); // الصور بتتجهز بدري عشان ما تتفكّش في نص الحركة new IntersectionObserver((entries, io) => { if (!entries[0].isIntersecting) return; io.disconnect(); row.querySelectorAll('img').forEach((img) => { img.loading = 'eager'; if (img.decode) img.decode().catch(() => {}); }); }, { rootMargin: '1200px 0px' }).observe(section); // لمعة الكارت مع الماوس (مرة في الفريم) cards.forEach((card) => { let pending = null; card.addEventListener('pointermove', (event) => { if (!pending) { requestAnimationFrame(() => { const b = card.getBoundingClientRect(); card.style.setProperty('--gx', `${(pending.clientX - b.left).toFixed(0)}px`); card.style.setProperty('--gy', `${(pending.clientY - b.top).toFixed(0)}px`); pending = null; }); } pending = event; }); }); // أي سحب بالعرض بيكمّل ظهور الكروت لو لسه ما خلصش، والكروت بتتسحب معاه في نفس اللحظة const finishReveal = () => { if (lastC >= 1 || forcing) return; forced = lastC; forcing = true; kick(); }; // السحب: لما يسيب بيكمّل بسرعته شوية ويقف على أقرب كارت const moveTo = (value) => { pos = posTarget = clampPos(value); kick(); }; const fling = (samples) => { const a = samples[0]; const b = samples[samples.length - 1]; const v = dPos(((b[1] - a[1]) / Math.max(16, b[0] - a[0])) * 16.7); posTarget = snap(pos + v * 14); hold(); kick(); }; box.addEventListener('pointerenter', (e) => { if (e.pointerType === 'mouse') hovering = true; }); box.addEventListener('pointerleave', (e) => { if (e.pointerType === 'mouse') hovering = false; }); stage.addEventListener('touchstart', (e) => { const p = e.touches[0]; touch = { x: p.clientX, y: p.clientY, last: p.clientX, axis: null, samples: [[e.timeStamp, p.clientX]] }; hold(); }, { passive: true }); stage.addEventListener('touchmove', (e) => { if (!touch || e.touches.length > 1) return; const p = e.touches[0]; if (!touch.axis) { const dx = p.clientX - touch.x; const dy = p.clientY - touch.y; if (Math.abs(dx) < 8 && Math.abs(dy) < 8) return; touch.axis = Math.abs(dx) > Math.abs(dy) * 1.2 ? 'x' : 'y'; touch.last = p.clientX; } if (touch.axis !== 'x') return; e.preventDefault(); finishReveal(); const step = p.clientX - touch.last; touch.last = p.clientX; touch.samples.push([e.timeStamp, p.clientX]); if (touch.samples.length > 6) touch.samples.shift(); moveTo(pos + dPos(step)); }, { passive: false }); const endTouch = () => { const done = touch; touch = null; if (done && done.axis === 'x') fling(done.samples); }; stage.addEventListener('touchend', endTouch, { passive: true }); stage.addEventListener('touchcancel', endTouch, { passive: true }); // التاتش باد بالعرض. العجلة العادية رأسي: الصفحة بتنزل عادي let wheelSnap = 0; stage.addEventListener('wheel', (e) => { if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return; e.preventDefault(); finishReveal(); moveTo(pos + dPos(-e.deltaX)); hold(); clearTimeout(wheelSnap); wheelSnap = setTimeout(() => { posTarget = snap(pos); kick(); }, 160); }, { passive: false }); // السحب بالماوس، والضغطة اللي آخر السحب ما بتفتحش الكارت stage.addEventListener('pointerdown', (e) => { if (e.pointerType !== 'mouse' || e.button !== 0) return; drag = { x: e.clientX, last: e.clientX, id: e.pointerId, moved: false, samples: [[e.timeStamp, e.clientX]] }; }); window.addEventListener('pointermove', (e) => { if (!drag || e.pointerId !== drag.id) return; if (!drag.moved) { if (Math.abs(e.clientX - drag.x) < 6) return; drag.moved = true; drag.last = e.clientX; stage.classList.add('is-dragging'); finishReveal(); } e.preventDefault(); const step = e.clientX - drag.last; drag.last = e.clientX; drag.samples.push([e.timeStamp, e.clientX]); if (drag.samples.length > 6) drag.samples.shift(); moveTo(pos + dPos(step)); }); const endDrag = () => { if (!drag) return; const { moved, samples } = drag; drag = null; stage.classList.remove('is-dragging'); if (!moved) return; dragged = true; setTimeout(() => { dragged = false; }, 0); fling(samples); }; window.addEventListener('pointerup', endDrag); window.addEventListener('pointercancel', endDrag); box.addEventListener('click', (e) => { if (!dragged) return; dragged = false; e.preventDefault(); e.stopPropagation(); }, true); box.addEventListener('dragstart', (e) => e.preventDefault()); // الكيبورد: الكارت اللي خد الفوكس الشريط بيروحله cards.forEach((link, i) => link.addEventListener('focus', () => { if (!link.matches(':focus-visible')) return; hold(); posTarget = clampPos((max / stops()) * i); kick(); })); measure(); } // بعد السلايدر في الصفحة الرئيسية بس function mount() { if (!document.body.classList.contains('index') || document.querySelector('[data-hf-cats]')) return; const anchor = document.querySelector('section[component-id="2014055276"]') || document.querySelector('#main-content > section'); if (!anchor) return; anchor.insertAdjacentHTML('afterend', markup); setup(anchor.nextElementSibling); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount, { once: true }); else mount(); })(); /* ---------- 7) آراء العملاء بخريطة السعودية 3D (منقول من موقع سمر بنفس الحركة، بألوان الحسين) ---------- يمين: خريطة المملكة مجسمة بـ three.js (بتتحمّل بس لما الزائر يقرب من السكشن)، والـSVG هو الشكل لو WebGL مش شغال. شمال: عمودين كروت تقييمات، واحد طالع وواحد نازل. على الجوال: الخريطة فوق وصفّين بيتحركوا بالعرض. التقييمات من صفحات منتجات زد القديمة (كلها 5 نجوم). */ (function () { 'use strict'; var REVIEWS = [ { q: 'جودة ممتازة، سعر مناسب، مطابق للوصف، تغليف جيد', n: 'يوسف', p: 'بن لقمتي باشنفر 5 كغ' }, { q: 'افضل سعر واسرع توصيل، شكرا', n: 'عميل الحسين', p: 'بن هرري باشنفر 10 كغ' }, { q: 'بحثت عنه طويلا والحمدلله حصلته', n: 'إسماعيل', p: 'أقراص سبيرولينا عضوية' }, { q: 'أسعار مناسبة', n: 'عمر', p: 'بن هرري باشنفر 10 كغ' }, { q: 'افضل انواع الكاكاو', n: 'إسماعيل', p: 'كاكاو بودرة خام عضوية' }, { q: 'جودة ممتازة', n: 'عميل الحسين', p: 'بن لقمتي باشنفر 5 كغ' }, { q: 'ممتاز', n: 'إسماعيل', p: 'ماء زهر البابونج' } ]; var TITLE = 'آراء عملائنـــا'; var THREE_URL = 'https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.min.js'; var MAP_SVG = ''; var KSA_RINGS = [[[0.3258,-0.2734],[0.3146,-0.2751],[0.3038,-0.2767],[0.2916,-0.2785],[0.2769,-0.2806],[0.2654,-0.2823],[0.2486,-0.2848],[0.2336,-0.287],[0.2194,-0.2891],[0.2053,-0.2912],[0.1933,-0.293],[0.1861,-0.295],[0.1777,-0.2995],[0.1648,-0.3064],[0.1516,-0.3135],[0.1448,-0.3171],[0.1376,-0.3265],[0.134,-0.3312],[0.1274,-0.3398],[0.1225,-0.3463],[0.1166,-0.354],[0.114,-0.3609],[0.11,-0.3715],[0.1066,-0.3742],[0.101,-0.3777],[0.0958,-0.3801],[0.0879,-0.3798],[0.0833,-0.3733],[0.0785,-0.3663],[0.0761,-0.3635],[0.0739,-0.3634],[0.0659,-0.3643],[0.0562,-0.3653],[0.0448,-0.3642],[0.0317,-0.3629],[0.0193,-0.3616],[0.0132,-0.3607],[0.0051,-0.3562],[0.0031,-0.3553],[0.0009,-0.3551],[-0.0087,-0.355],[-0.0182,-0.3549],[-0.0277,-0.3563],[-0.0368,-0.3558],[-0.0463,-0.3566],[-0.0496,-0.3583],[-0.0533,-0.3582],[-0.0556,-0.3598],[-0.0576,-0.3605],[-0.06,-0.3592],[-0.063,-0.3595],[-0.0673,-0.3583],[-0.0702,-0.3554],[-0.0728,-0.3528],[-0.0756,-0.3514],[-0.0787,-0.3505],[-0.0814,-0.3505],[-0.0848,-0.3521],[-0.0869,-0.3536],[-0.0922,-0.3587],[-0.0924,-0.3605],[-0.09,-0.3635],[-0.0907,-0.3649],[-0.0938,-0.3667],[-0.0948,-0.3715],[-0.0952,-0.3741],[-0.0957,-0.3804],[-0.0943,-0.3853],[-0.0925,-0.3872],[-0.0924,-0.3893],[-0.0934,-0.3935],[-0.0963,-0.3949],[-0.0984,-0.3989],[-0.0996,-0.4008],[-0.1019,-0.4029],[-0.1108,-0.4101],[-0.1112,-0.4059],[-0.1141,-0.3998],[-0.1143,-0.3954],[-0.1156,-0.3911],[-0.118,-0.3877],[-0.1225,-0.3842],[-0.1229,-0.3795],[-0.1262,-0.3748],[-0.1306,-0.371],[-0.133,-0.364],[-0.1348,-0.3547],[-0.1463,-0.3425],[-0.1607,-0.3313],[-0.1651,-0.3249],[-0.1722,-0.312],[-0.1758,-0.3017],[-0.1855,-0.29],[-0.1859,-0.2855],[-0.1873,-0.2799],[-0.1895,-0.2738],[-0.1909,-0.269],[-0.2005,-0.2477],[-0.2036,-0.2443],[-0.2063,-0.2396],[-0.207,-0.2359],[-0.2078,-0.2339],[-0.2146,-0.2304],[-0.221,-0.2215],[-0.2401,-0.2073],[-0.2494,-0.2059],[-0.2569,-0.2009],[-0.2623,-0.1942],[-0.2681,-0.1828],[-0.2784,-0.1705],[-0.287,-0.153],[-0.2843,-0.1466],[-0.2845,-0.1421],[-0.2872,-0.1345],[-0.2901,-0.1287],[-0.2921,-0.1232],[-0.2905,-0.1153],[-0.2899,-0.1065],[-0.2882,-0.1018],[-0.2869,-0.0966],[-0.2885,-0.0862],[-0.2914,-0.0807],[-0.2911,-0.077],[-0.2944,-0.0751],[-0.2971,-0.0711],[-0.2943,-0.0711],[-0.2993,-0.0656],[-0.3012,-0.0625],[-0.3031,-0.0549],[-0.3055,-0.0491],[-0.3133,-0.0359],[-0.317,-0.0279],[-0.3253,-0.0176],[-0.3344,-0.0099],[-0.3401,-0.0064],[-0.3429,-0.0033],[-0.3476,-0.0032],[-0.3527,0.0014],[-0.3563,0.0015],[-0.3608,0.0023],[-0.3661,0.011],[-0.3705,0.0191],[-0.378,0.0298],[-0.3761,0.0326],[-0.374,0.0371],[-0.375,0.043],[-0.3762,0.047],[-0.3795,0.0543],[-0.3904,0.0725],[-0.3933,0.0752],[-0.3979,0.0783],[-0.4008,0.0862],[-0.4021,0.0932],[-0.4095,0.0967],[-0.4223,0.1222],[-0.4297,0.1311],[-0.4327,0.1371],[-0.4412,0.1469],[-0.4455,0.1567],[-0.4541,0.1658],[-0.4616,0.1815],[-0.4732,0.1972],[-0.478,0.1999],[-0.4899,0.201],[-0.495,0.2021],[-0.4996,0.1987],[-0.5,0.2031],[-0.4968,0.2091],[-0.4922,0.2218],[-0.4913,0.2328],[-0.4841,0.2658],[-0.474,0.2641],[-0.4656,0.2627],[-0.4534,0.2607],[-0.4408,0.2586],[-0.4334,0.2573],[-0.4309,0.2578],[-0.4207,0.2659],[-0.4115,0.2732],[-0.406,0.2821],[-0.4007,0.2907],[-0.3983,0.2925],[-0.3901,0.2941],[-0.3771,0.2967],[-0.3643,0.2992],[-0.3633,0.3001],[-0.3603,0.307],[-0.3565,0.3158],[-0.3557,0.3167],[-0.3548,0.3176],[-0.3456,0.3225],[-0.34,0.3255],[-0.348,0.3343],[-0.3554,0.3426],[-0.3638,0.3519],[-0.3709,0.3592],[-0.3816,0.37],[-0.3886,0.3771],[-0.3764,0.3805],[-0.3632,0.3841],[-0.3498,0.3878],[-0.3338,0.3922],[-0.3212,0.3957],[-0.3025,0.4008],[-0.2933,0.4033],[-0.2916,0.404],[-0.2846,0.4101],[-0.274,0.4084],[-0.258,0.4058],[-0.2426,0.4033],[-0.2264,0.4004],[-0.2212,0.398],[-0.2055,0.3893],[-0.1953,0.3836],[-0.1834,0.377],[-0.1685,0.3687],[-0.1583,0.363],[-0.1453,0.3557],[-0.1351,0.3474],[-0.1222,0.3368],[-0.108,0.3252],[-0.0963,0.3162],[-0.0803,0.3038],[-0.0644,0.2916],[-0.0489,0.2796],[-0.0365,0.2701],[-0.0208,0.2579],[-0.0196,0.2575],[-0.0037,0.2561],[0.0176,0.2542],[0.0391,0.2524],[0.0584,0.2507],[0.0667,0.2524],[0.0759,0.2513],[0.0882,0.2498],[0.0956,0.2488],[0.1096,0.2469],[0.1138,0.239],[0.1153,0.2334],[0.1167,0.228],[0.1209,0.2231],[0.1305,0.2232],[0.1389,0.2233],[0.1494,0.2235],[0.1576,0.2236],[0.1603,0.2187],[0.1614,0.2138],[0.1664,0.2022],[0.1734,0.1932],[0.175,0.1899],[0.1762,0.185],[0.175,0.1831],[0.1745,0.181],[0.1797,0.176],[0.1883,0.1718],[0.1916,0.1708],[0.1954,0.1689],[0.1925,0.1661],[0.1975,0.1594],[0.2034,0.1527],[0.2097,0.1512],[0.2182,0.141],[0.231,0.1344],[0.2388,0.1257],[0.2381,0.1255],[0.2358,0.1264],[0.233,0.1276],[0.2321,0.1265],[0.2322,0.1229],[0.233,0.1186],[0.237,0.1149],[0.2405,0.1123],[0.2419,0.1073],[0.2391,0.0964],[0.2381,0.0965],[0.2363,0.0974],[0.2343,0.0976],[0.2332,0.097],[0.2356,0.0892],[0.2379,0.0832],[0.2407,0.0785],[0.2431,0.0716],[0.2451,0.0686],[0.2533,0.0613],[0.2559,0.0551],[0.2582,0.0437],[0.2634,0.0373],[0.2662,0.0323],[0.27,0.0282],[0.2724,0.0225],[0.2759,0.0181],[0.2776,0.017],[0.2803,0.0165],[0.2837,0.0165],[0.2877,0.0176],[0.292,0.0187],[0.2954,0.0165],[0.2988,0.0168],[0.2992,0.0147],[0.2969,0.0119],[0.294,0.0048],[0.2981,0.0037],[0.3019,0.0031],[0.3047,0.002],[0.3063,0.002],[0.3063,0.0005],[0.3065,-0.0062],[0.3074,-0.0088],[0.3092,-0.0111],[0.3118,-0.0145],[0.3144,-0.0179],[0.317,-0.0213],[0.3197,-0.0247],[0.3223,-0.0281],[0.3249,-0.0316],[0.3275,-0.035],[0.3301,-0.0384],[0.3327,-0.0418],[0.3354,-0.0452],[0.338,-0.0486],[0.3406,-0.052],[0.3432,-0.0554],[0.3458,-0.0588],[0.3484,-0.0623],[0.3511,-0.0657],[0.3532,-0.0685],[0.3572,-0.069],[0.3585,-0.0692],[0.3621,-0.0697],[0.3677,-0.0704],[0.375,-0.0714],[0.3835,-0.0725],[0.3931,-0.0738],[0.4034,-0.0752],[0.414,-0.0766],[0.4245,-0.078],[0.4348,-0.0794],[0.4444,-0.0807],[0.453,-0.0818],[0.4602,-0.0828],[0.4658,-0.0835],[0.4694,-0.084],[0.4707,-0.0842],[0.4745,-0.0847],[0.4752,-0.0846],[0.4784,-0.0804],[0.4818,-0.0863],[0.4847,-0.0912],[0.4887,-0.0979],[0.4929,-0.105],[0.497,-0.1119],[0.5,-0.117],[0.4984,-0.1222],[0.4967,-0.128],[0.4949,-0.1338],[0.4932,-0.1395],[0.4914,-0.1453],[0.4897,-0.151],[0.488,-0.1568],[0.4862,-0.1626],[0.4845,-0.1683],[0.4827,-0.1741],[0.481,-0.1799],[0.4792,-0.1856],[0.4775,-0.1914],[0.4758,-0.1972],[0.474,-0.2029],[0.4723,-0.2087],[0.4705,-0.2144],[0.4684,-0.2214],[0.4634,-0.2232],[0.4552,-0.2262],[0.447,-0.2292],[0.4388,-0.2322],[0.4307,-0.2352],[0.4225,-0.2382],[0.4143,-0.2411],[0.4061,-0.2441],[0.3979,-0.2471],[0.3897,-0.2501],[0.3816,-0.2531],[0.3734,-0.2561],[0.3652,-0.2591],[0.357,-0.262],[0.3488,-0.265],[0.3406,-0.268],[0.3325,-0.271]],[[-0.1494,-0.3922],[-0.1457,-0.3925],[-0.1472,-0.3908],[-0.1476,-0.39],[-0.146,-0.3876],[-0.1407,-0.3925],[-0.1409,-0.3984],[-0.1413,-0.3997],[-0.1427,-0.3985],[-0.1437,-0.3972],[-0.1439,-0.3959],[-0.1454,-0.3945],[-0.1505,-0.3954],[-0.1537,-0.3938],[-0.1582,-0.3889],[-0.1595,-0.3853],[-0.1576,-0.3846],[-0.1556,-0.3829],[-0.1543,-0.3801],[-0.1554,-0.3772],[-0.1527,-0.3777],[-0.1513,-0.3807],[-0.151,-0.3875],[-0.1506,-0.3889],[-0.1513,-0.3904]]]; var KSA_REGIONS = [[[-0.0217,0.0688],[-0.0186,0.0736],[-0.0214,0.091],[-0.0358,0.1113],[-0.035,0.125],[-0.0137,0.1426],[-0.0157,0.1495],[-0.0238,0.1549]],[[-0.0475,0.0697],[-0.0374,0.0684]],[[-0.0998,0.0226],[-0.0949,0.0276],[-0.0962,0.0372],[-0.0871,0.0478],[-0.067,0.0538],[-0.0542,0.0677],[-0.0475,0.0697]],[[-0.0374,0.0684],[-0.026,0.0692]],[[-0.136,0.028],[-0.1159,0.0227]],[[-0.1442,0.0189],[-0.136,0.028]],[[-0.0319,0.1469],[-0.0422,0.1482],[-0.0588,0.1603]],[[-0.0588,0.1603],[-0.0849,0.1478],[-0.0926,0.1371],[-0.1108,0.1277],[-0.1234,0.1178],[-0.1321,0.1053],[-0.1364,0.1042]],[[-0.0238,0.1549],[-0.0319,0.1469]],[[-0.1376,0.1043],[-0.142,0.0986],[-0.143,0.0879]],[[-0.1498,0.0899],[-0.154,0.0856],[-0.152,0.0762],[-0.1769,0.0671]],[[-0.1801,0.2409],[-0.1621,0.2368]],[[-0.2088,0.2349],[-0.1801,0.2409]],[[-0.15,0.2387],[-0.1303,0.2341],[-0.121,0.2247],[-0.1153,0.2227]],[[-0.1621,0.2368],[-0.15,0.2387]],[[-0.1044,0.2265],[-0.1013,0.2255],[-0.0998,0.2178],[-0.0945,0.2151]],[[-0.1153,0.2227],[-0.1044,0.2265]],[[-0.0672,0.217],[-0.0492,0.187],[-0.0287,0.1821],[-0.0157,0.1704]],[[-0.0787,0.2118],[-0.0672,0.217]],[[-0.0898,0.2156],[-0.0787,0.2118]],[[-0.0238,0.1549],[-0.0232,0.1638],[-0.0157,0.1704]],[[-0.3245,0.3454],[-0.3321,0.3479],[-0.3449,0.3636],[-0.3454,0.3709],[-0.3397,0.3908]],[[-0.3033,0.3474],[-0.3245,0.3454]],[[-0.2887,0.3495],[-0.2502,0.3447],[-0.2356,0.3378],[-0.2096,0.3372]],[[-0.3033,0.3474],[-0.2887,0.3495]],[[-0.2021,0.3376],[-0.1879,0.3286],[-0.1711,0.3255],[-0.164,0.3141],[-0.1533,0.3048],[-0.1605,0.2976],[-0.2065,0.2691],[-0.2101,0.2463],[-0.2181,0.2378]],[[-0.2211,0.2385],[-0.2841,0.2111],[-0.2915,0.2041]],[[0.0068,-0.2599],[0.1244,-0.2456]],[[-0.0291,-0.2465],[-0.0099,-0.2579],[0.0068,-0.2599]],[[-0.0066,0.171],[-0.009,0.1755],[-0.0073,0.1818],[0.004,0.1962],[0.0236,0.2308],[0.032,0.239],[0.0618,0.2514]],[[-0.0066,0.171],[-0.0,0.166],[0.0056,0.1553],[0.0268,0.1461],[0.0373,0.1361],[0.0524,0.1338],[0.0716,0.1228]],[[0.0787,0.124],[0.092,0.1125],[0.1101,0.1039],[0.1126,0.0282],[0.1433,0.0011],[0.1503,-0.0129],[0.1508,-0.0309],[0.1244,-0.2456]],[[0.1094,-0.3725],[0.1244,-0.2456]],[[-0.0291,-0.2465],[-0.0486,-0.2281],[-0.0567,-0.2156],[-0.051,-0.192],[-0.0695,-0.1703]],[[-0.1631,-0.2317],[-0.1563,-0.2119],[-0.1475,-0.2042],[-0.1495,-0.1966],[-0.1473,-0.1886]],[[-0.1543,-0.3085],[-0.152,-0.3099],[-0.1527,-0.3205],[-0.1506,-0.323]],[[-0.1474,-0.3225],[-0.1399,-0.3298],[-0.1288,-0.3313],[-0.1179,-0.343]],[[-0.1066,-0.3253],[-0.085,-0.3522]],[[-0.1179,-0.343],[-0.1127,-0.3301],[-0.1066,-0.3253]],[[-0.0291,-0.2465],[-0.0297,-0.256],[-0.0366,-0.2632],[-0.0362,-0.2809],[-0.0498,-0.2881],[-0.0704,-0.3137],[-0.0709,-0.3545]],[[-0.1442,0.0189],[-0.1498,0.0237],[-0.1548,0.0391],[-0.1655,0.0445],[-0.1657,0.0628],[-0.1769,0.0671]],[[-0.1442,0.0189],[-0.1487,0.0082],[-0.1495,-0.0156]],[[-0.2509,0.1088],[-0.2544,0.1112],[-0.2515,0.1197],[-0.2527,0.1254]],[[-0.2407,0.0554],[-0.2464,0.0611],[-0.2485,0.0872],[-0.2458,0.1062],[-0.2486,0.1093]],[[-0.1769,0.0671],[-0.1943,0.0703]],[[-0.1943,0.0703],[-0.2055,0.069],[-0.2132,0.0614],[-0.2187,0.06]],[[-0.2243,0.0602],[-0.2407,0.0554]],[[-0.1251,-0.069],[-0.132,-0.0649],[-0.1437,-0.0305],[-0.1494,-0.0248],[-0.1495,-0.0156]],[[-0.0953,-0.09],[-0.1016,-0.0856],[-0.1016,-0.0723],[-0.1178,-0.0689]],[[-0.0695,-0.1703],[-0.0827,-0.1492],[-0.081,-0.1275],[-0.0771,-0.1193],[-0.0782,-0.0909],[-0.0875,-0.0882]],[[-0.1713,-0.1914],[-0.1806,-0.1815]],[[-0.1806,-0.1815],[-0.1852,-0.185],[-0.1842,-0.1954],[-0.1898,-0.2074],[-0.2004,-0.2111],[-0.2059,-0.2178],[-0.1987,-0.2236],[-0.1973,-0.2441],[-0.1837,-0.2543]],[[-0.1521,-0.1857],[-0.1713,-0.1914]],[[-0.1837,-0.2543],[-0.1792,-0.2515],[-0.1747,-0.2366],[-0.1706,-0.2326]],[[-0.1597,-0.309],[-0.168,-0.319]],[[-0.159,-0.2307],[-0.1552,-0.2347],[-0.1568,-0.2448],[-0.1541,-0.2533],[-0.1561,-0.2596],[-0.16,-0.2618]],[[-0.1772,-0.2638],[-0.1779,-0.2795],[-0.174,-0.2844]],[[-0.1688,-0.2843],[-0.1614,-0.2877],[-0.1579,-0.2995],[-0.1597,-0.309]],[[-0.085,-0.1776],[-0.0695,-0.1703]],[[-0.1378,-0.2032],[-0.1049,-0.1796],[-0.0907,-0.1761]],[[-0.1473,-0.1886],[-0.1378,-0.2032]],[[-0.1557,-0.0146],[-0.1613,-0.0169],[-0.16,-0.027],[-0.1622,-0.0316],[-0.1828,-0.044],[-0.1753,-0.0543],[-0.1856,-0.0601],[-0.2146,-0.0871]],[[-0.2801,-0.0566],[-0.2962,-0.0416]],[[-0.2962,-0.0416],[-0.3084,-0.0431]],[[-0.2359,-0.0915],[-0.2407,-0.0895],[-0.2415,-0.0788],[-0.2494,-0.0743],[-0.2462,-0.0609],[-0.2501,-0.057]],[[-0.2501,-0.057],[-0.2683,-0.0614]],[[-0.223,-0.0847],[-0.2359,-0.0915]],[[-0.2527,0.1254],[-0.2461,0.14],[-0.2361,0.153],[-0.2472,0.1611],[-0.2529,0.1825],[-0.2568,0.1874],[-0.2708,0.1976],[-0.2915,0.2041]],[[-0.4109,0.2245],[-0.4147,0.2257],[-0.4285,0.2425],[-0.4411,0.2466]],[[-0.4411,0.2466],[-0.464,0.2437],[-0.4713,0.2402]],[[-0.4713,0.2402],[-0.4836,0.2418]],[[-0.3235,0.2072],[-0.3359,0.2087],[-0.3465,0.2142],[-0.3499,0.2214],[-0.3501,0.2385],[-0.3525,0.2405]],[[-0.3525,0.2405],[-0.3677,0.2249]],[[-0.3677,0.2249],[-0.3898,0.2289]],[[-0.3898,0.2289],[-0.4109,0.2245]],[[-0.2961,0.2062],[-0.3064,0.2025]],[[-0.3227,0.1323],[-0.3298,0.145],[-0.3419,0.1482],[-0.351,0.1638]],[[-0.351,0.1638],[-0.3629,0.1585]],[[-0.3629,0.1585],[-0.3749,0.1631]],[[-0.3749,0.1631],[-0.396,0.1553],[-0.3951,0.1522]],[[-0.3911,0.1528],[-0.3866,0.1463],[-0.3865,0.1294],[-0.3741,0.1208],[-0.3787,0.1087],[-0.3737,0.0953]],[[-0.2818,0.1262],[-0.2994,0.1344],[-0.3038,0.1395]],[[-0.3141,0.1373],[-0.3227,0.1323]],[[-0.2573,0.1292],[-0.2818,0.1262]],[[-0.3702,0.0972],[-0.3596,0.0914],[-0.3492,0.078],[-0.3449,0.0653],[-0.338,0.0625],[-0.339,0.0325],[-0.3441,0.0278]],[[-0.3496,0.0284],[-0.3603,0.022]]]; var KSA_CITIES = {"riyadh":[0.0758,0.0229],"jeddah":[-0.2823,-0.1438],"madinah":[-0.2623,0.0114],"dammam":[0.2366,0.1131],"abha":[-0.1248,-0.314]}; // الرياض الأول: الأقواس بتطلع منها var AVATAR = ''; function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); } function card(r) { return '
    ' + '
    ' + '
    «' + esc(r.q) + '»
    ' + '
    ' + AVATAR + '' + esc(r.n) + '' + esc(r.p) + '
    ' + '
    '; } // كل عمود فيه القايمة مرتين، فالحركة بمقدار قايمة واحدة بتلف من غير قطع. function column(list, dir) { var html = list.map(card).join(''); return '
    ' + html + '
    '; } function build() { var up = REVIEWS.filter(function (_, i) { return i % 2 === 0; }); var down = REVIEWS.filter(function (_, i) { return i % 2 === 1; }); var el = document.createElement('section'); el.className = 'hfv'; el.setAttribute('aria-labelledby', 'hfv-title'); el.innerHTML = '
    ' + // نفس عنوان أقسام الثيم بالظبط (الخط والمقاس والزخرفة اللي تحته). '
    ' + '

    ' + TITLE + '

    ' + '' + '
    ' + '
    ' + '' + '
    ' + column(up, 'up') + column(down, 'down') + '
    ' + '
    ' + '
    '; return el; } /* ---- الخريطة 3D: نفس SaudiMap بتاعة سمر، بكانفاس خاص بيها بدل المسرح المشترك ---- */ var DEPTH = 0.055, TOP = DEPTH + 0.011, BASE_TILT = -0.66, BASE_TURN = 0.1, CAM = 1000; var GOLD = '#E9C77E', LIGHT = '#FFF3D6'; function toCanvas(x, y, size) { return [(x + 0.5) * size, (0.5 - y) * size]; } function easeOut(t) { return 1 - Math.pow(1 - t, 3); } function topTexture(T) { var size = 1536, c = document.createElement('canvas'); c.width = c.height = size; var ctx = c.getContext('2d'); var g = ctx.createLinearGradient(0, 0, size, size); g.addColorStop(0, '#2c6b52'); g.addColorStop(0.5, '#1F4D3A'); g.addColorStop(1, '#153628'); ctx.fillStyle = g; ctx.fillRect(0, 0, size, size); var p = toCanvas(0.02, 0.02, size); var glow = ctx.createRadialGradient(p[0], p[1], 0, p[0], p[1], size * 0.45); glow.addColorStop(0, 'rgba(255, 243, 214, 0.16)'); glow.addColorStop(1, 'rgba(255, 243, 214, 0)'); ctx.fillStyle = glow; ctx.fillRect(0, 0, size, size); ctx.fillStyle = 'rgba(233, 199, 126, 0.2)'; var step = size / 64; for (var y = step / 2; y < size; y += step) { for (var x = step / 2; x < size; x += step) { ctx.beginPath(); ctx.arc(x, y, 1.5, 0, Math.PI * 2); ctx.fill(); } } ctx.strokeStyle = 'rgba(233, 199, 126, 0.45)'; ctx.lineWidth = 2.2; ctx.lineJoin = 'round'; ctx.lineCap = 'round'; ctx.setLineDash([10, 7]); KSA_REGIONS.forEach(function (line) { ctx.beginPath(); line.forEach(function (pt, i) { var q = toCanvas(pt[0], pt[1], size); if (i === 0) ctx.moveTo(q[0], q[1]); else ctx.lineTo(q[0], q[1]); }); ctx.stroke(); }); var t = new T.CanvasTexture(c); t.colorSpace = T.SRGBColorSpace; t.offset.set(0.5, 0.5); t.anisotropy = 8; return t; } function shadowTexture(T) { var size = 256, c = document.createElement('canvas'); c.width = c.height = size; var ctx = c.getContext('2d'); var g = ctx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2); g.addColorStop(0, 'rgba(18, 38, 29, 0.5)'); g.addColorStop(0.6, 'rgba(18, 38, 29, 0.16)'); g.addColorStop(1, 'rgba(18, 38, 29, 0)'); ctx.fillStyle = g; ctx.fillRect(0, 0, size, size); return new T.CanvasTexture(c); } function startMap(T, section) { var box = section.querySelector('.hfv__map'); var canvas = document.createElement('canvas'); canvas.className = 'hfv__gl'; box.appendChild(canvas); var renderer = new T.WebGLRenderer({ canvas: canvas, antialias: true, alpha: true, powerPreference: 'high-performance' }); renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)); renderer.outputColorSpace = T.SRGBColorSpace; var scene = new T.Scene(); var camera = new T.PerspectiveCamera(50, 1, 10, CAM * 4); camera.position.z = CAM; var group = new T.Group(), slab = new T.Group(); var caps = new T.MeshStandardMaterial({ map: topTexture(T), roughness: 0.58, metalness: 0.05 }); var sides = new T.MeshStandardMaterial({ color: '#143426', roughness: 0.75, metalness: 0.08 }); var shapes = KSA_RINGS.map(function (ring) { return new T.Shape(ring.map(function (p) { return new T.Vector2(p[0], p[1]); })); }); var geometry = new T.ExtrudeGeometry(shapes, { depth: DEPTH, bevelEnabled: true, bevelThickness: 0.011, bevelSize: 0.006, bevelSegments: 3, curveSegments: 1 }); slab.add(new T.Mesh(geometry, [caps, sides])); var rimMat = new T.LineBasicMaterial({ color: GOLD, transparent: true, opacity: 0.7 }); KSA_RINGS.forEach(function (ring) { var pts = ring.map(function (p) { return new T.Vector3(p[0], p[1], TOP + 0.001); }); slab.add(new T.LineLoop(new T.BufferGeometry().setFromPoints(pts), rimMat)); }); group.add(slab); var shadow = new T.Mesh(new T.PlaneGeometry(1.3, 1.15), new T.MeshBasicMaterial({ map: shadowTexture(T), transparent: true, depthWrite: false })); shadow.position.set(0.02, -0.05, -0.09); group.add(shadow); // منارات المدن: راس منوّر على شعاع، وحلقة بتتنفّس حواليه. var cities = Object.keys(KSA_CITIES).map(function (k) { return KSA_CITIES[k]; }); var beacons = [], arcs = []; var headGeo = new T.SphereGeometry(0.009, 16, 12); var headMat = new T.MeshBasicMaterial({ color: LIGHT }); cities.forEach(function (c, i) { var hub = i === 0, height = hub ? 0.12 : 0.085; var beam = new T.Mesh(new T.ConeGeometry(hub ? 0.012 : 0.009, height, 20, 1, true), new T.MeshBasicMaterial({ color: GOLD, transparent: true, opacity: 0.38, depthWrite: false })); beam.rotation.x = Math.PI / 2; beam.position.set(c[0], c[1], TOP + height / 2); group.add(beam); var head = new T.Mesh(headGeo, headMat); head.scale.setScalar(hub ? 1.35 : 1); head.position.set(c[0], c[1], TOP + height); group.add(head); var ring = new T.Mesh(new T.RingGeometry(0.012, 0.016, 40), new T.MeshBasicMaterial({ color: GOLD, transparent: true, depthWrite: false })); ring.position.set(c[0], c[1], TOP + 0.002); group.add(ring); beacons.push({ head: head, headScale: hub ? 1.35 : 1, ring: ring, beam: beam, phase: i * 0.29 }); }); // أقواس من الرياض، وعلى كل قوس نقطة نور ماشية. var from = new T.Vector3(cities[0][0], cities[0][1], TOP + 0.12); cities.slice(1).forEach(function (c, i) { var to = new T.Vector3(c[0], c[1], TOP + 0.085); var mid = from.clone().add(to).multiplyScalar(0.5); mid.z += from.distanceTo(to) * 0.55; var curve = new T.QuadraticBezierCurve3(from, mid, to); var count = 64; var line = new T.Line(new T.BufferGeometry().setFromPoints(curve.getPoints(count - 1)), new T.LineBasicMaterial({ color: GOLD, transparent: true, opacity: 0.55 })); line.geometry.setDrawRange(0, 0); group.add(line); var spark = new T.Mesh(new T.SphereGeometry(0.007, 12, 10), new T.MeshBasicMaterial({ color: LIGHT, transparent: true, blending: T.AdditiveBlending, depthWrite: false })); group.add(spark); arcs.push({ line: line, curve: curve, spark: spark, count: count, phase: i * 0.23, speed: 0.22 + (i % 2) * 0.05 }); }); var hemi = new T.HemisphereLight(LIGHT, '#10241b', 1.25); var sun = new T.DirectionalLight('#ffffff', 1.75); sun.position.set(-600, 900, 1200); scene.add(hemi, sun, group); group.rotation.set(BASE_TILT, 0, BASE_TURN); // يميل ناحية الماوس وهو فوق السكشن. var tilt = { x: 0, y: 0, tx: 0, ty: 0 }; section.addEventListener('pointermove', function (e) { tilt.tx = (e.clientX / window.innerWidth - 0.5) * 0.5; tilt.ty = (e.clientY / window.innerHeight - 0.5) * 0.3; }); section.addEventListener('pointerleave', function () { tilt.tx = 0; tilt.ty = 0; }); var boxW = 0; function resize() { var w = canvas.clientWidth, h = canvas.clientHeight; if (!w || !h) return; renderer.setSize(w, h, false); camera.aspect = w / h; camera.fov = 2 * Math.atan(h / 2 / CAM) * (180 / Math.PI); // وحدة = بكسل عند z=0 camera.updateProjectionMatrix(); boxW = box.clientWidth; } resize(); if (window.ResizeObserver) new ResizeObserver(resize).observe(box); else window.addEventListener('resize', resize); var reveal = 0, seen = false, last = 0, raf = 0, visible = false; function frame(now) { raf = 0; var time = now / 1000, dt = last ? Math.min(0.1, time - last) : 0.016; last = time; var rect = box.getBoundingClientRect(), vh = window.innerHeight; var offset = (rect.top + rect.height / 2 - vh / 2) / vh; if (!seen && Math.abs(offset) < 0.45) seen = true; if (seen && reveal < 1) reveal = Math.min(1, reveal + dt / 2.4); var rise = easeOut(Math.min(1, reveal / 0.55)); var draw = easeOut(Math.max(0, (reveal - 0.35) / 0.65)); var size = boxW * 0.94; group.scale.setScalar(size); slab.scale.z = 0.08 + 0.92 * rise; var ease = 1 - Math.exp(-dt * 3); tilt.x += (tilt.tx - tilt.x) * ease; tilt.y += (tilt.ty - tilt.y) * ease; group.position.set(0, Math.sin(time * 0.9) * size * 0.012, 0); group.rotation.x = BASE_TILT + tilt.y + Math.sin(time * 0.6) * 0.02; group.rotation.y = tilt.x; group.rotation.z = BASE_TURN - offset * 0.18; beacons.forEach(function (b) { b.head.scale.setScalar(b.headScale * rise); var t = (time * 0.55 + b.phase) % 1; b.ring.scale.setScalar(1 + t * 2.4); b.ring.material.opacity = 0.85 * (1 - t) * rise; b.beam.scale.y = rise; b.beam.material.opacity = (0.3 + Math.sin(time * 2 + b.phase * 6) * 0.08) * rise; }); arcs.forEach(function (a) { a.line.geometry.setDrawRange(0, Math.floor(a.count * draw)); var t = (time * a.speed + a.phase) % 1; a.spark.position.copy(a.curve.getPoint(t)); a.spark.material.opacity = Math.sin(Math.PI * t) * (draw > 0.98 ? 1 : 0); }); renderer.render(scene, camera); if (visible) raf = requestAnimationFrame(frame); } // الرسم شغال بس والسكشن ظاهر. new IntersectionObserver(function (entries) { visible = entries[0].isIntersecting; if (visible && !raf) { last = 0; raf = requestAnimationFrame(frame); } }, { rootMargin: '10% 0px' }).observe(section); section.classList.add('is-live'); } function hasWebGL2() { try { return !!document.createElement('canvas').getContext('webgl2'); } catch (e) { return false; } } function init() { if (!document.body.classList.contains('index') || document.querySelector('.hfv')) return; var blocks = document.querySelectorAll('section.s-block'); var anchor = blocks[blocks.length - 1]; if (!anchor || !anchor.parentNode) return; var section = build(); anchor.parentNode.insertBefore(section, anchor.nextSibling); // الأعمدة بتقف وهي برا الشاشة، وكمان لما الماوس فوقها. var cols = section.querySelector('.hfv__cols'); new IntersectionObserver(function (entries) { cols.classList.toggle('is-paused', !entries[0].isIntersecting); }, { rootMargin: '10% 0px' }).observe(cols); // three.js بيتحمّل لما الزائر يقرب من السكشن بس. if (!hasWebGL2()) return; var io = new IntersectionObserver(function (entries) { if (!entries[0].isIntersecting) return; io.disconnect(); new Function('u', 'return import(u)')(THREE_URL).then(function (T) { try { startMap(T, section); } catch (e) { /* الخريطة الـSVG بتفضل ظاهرة */ } }, function () {}); }, { rootMargin: '600px 0px' }); io.observe(section); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true }); else init(); })(); /* ---------- 9) الأسئلة الشائعة: كارت «ما لقيت جواب سؤالك؟» بزرار واتساب فوق صورة العنصر ---------- */ (function () { 'use strict'; var WA = 'https://wa.me/966502399222?text=' + encodeURIComponent('السلام عليكم، عندي سؤال'); function init() { document.querySelectorAll('.s-block--common_questions .saji-common-questions__media').forEach(function (media) { if (media.querySelector('.hfq-cta')) return; var cta = document.createElement('div'); cta.className = 'hfq-cta'; cta.innerHTML = 'ما لقيت جواب سؤالك؟' + 'راسلنا على الواتساب ونرد عليك' + 'راسلنا واتساب'; media.appendChild(cta); }); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true }); else init(); })(); /* ---------- 10) بنرات الأقسام المدمجة: ظهور ناعم لما البنر يدخل الشاشة ---------- */ (function () { 'use strict'; if (!('IntersectionObserver' in window)) return; document.documentElement.classList.add('hf-blend-js'); function init() { var all = document.querySelectorAll('section.s-block--default-home-slider'); var io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (!e.isIntersecting) return; e.target.classList.add('hf-in'); io.unobserve(e.target); }); }, { rootMargin: '0px 0px -12% 0px' }); for (var i = 1; i < all.length; i++) io.observe(all[i]); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true }); else init(); })(); /* ---------- 11) الهيدر: الثيم بيقلل طول الفراغ مكان الهيدر فجأة فالمحتوى بينط. هنا الفراغ بيفضل بالطول الأصلي، والهيدر بينزل لمكانه بنعومة ---------- */ (function () { 'use strict'; function init() { var header = document.querySelector('#header[data-saji-scroll-nav]'); if (!header) return; var root = document.documentElement; var flowTop = 0; var wasSticky = header.classList.contains('is-saji-sticky'); function measure() { if (header.classList.contains('is-saji-sticky')) return; var menu = header.querySelector('.saji-header-menu--below'); root.style.setProperty('--hf-header-h', header.offsetHeight + 'px'); if (menu) root.style.setProperty('--hf-menu-h', menu.offsetHeight + 'px'); flowTop = header.getBoundingClientRect().top + window.scrollY; root.classList.add('hf-header-ready'); } new MutationObserver(function () { var sticky = header.classList.contains('is-saji-sticky'); if (sticky === wasSticky) return; wasSticky = sticky; if (sticky) { root.style.setProperty('--hf-enter', Math.max(0, flowTop - window.scrollY) + 'px'); header.classList.add('hf-sticky-enter'); } else { header.classList.remove('hf-sticky-enter'); measure(); } }).observe(header, { attributes: true, attributeFilter: ['class'] }); header.addEventListener('animationend', function (e) { if (e.target === header) header.classList.remove('hf-sticky-enter'); }); window.addEventListener('resize', measure, { passive: true }); window.addEventListener('load', measure, { once: true }); measure(); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true }); else init(); })(); /* ---------- 12) صفحة المنتج: «مسرح» المنتج (نور وذرات وإمالة 3D)، قصة المنتج من الوصف، شريط شراء ثابت، والصورة بتطير للسلة. المحتوى كله من سلة ---------- */ (function () { 'use strict'; // نصوص ثابتة يقدر صاحب المتجر يغيّرها من هنا var CONFIG = { whatsapp: '966502399222', trust: [ { icon: 'truck', title: 'توصيل لكل المدن', sub: 'لين باب بيتك' }, { icon: 'back', title: 'استرجاع سهل', sub: 'خلال 7 أيام من الاستلام' }, { icon: 'leaf', title: 'خبرة 40 سنة', sub: 'في العطارة والبهارات' }, { icon: 'chat', title: 'عندك سؤال؟', sub: 'راسلنا واتساب', wa: true } ], marquee: ['مختار لك بعناية', 'خبرة أكثر من 40 سنة', 'نوصّل لين باب البيت', 'استرجاع خلال 7 أيام'], storyEyebrow: 'قصة المنتج', firstPart: 'عن المنتج', buyNote: 'نجهّز طلبك ونشحنه بأسرع وقت' }; var ICONS = { truck: '', back: '', leaf: '', chat: '' }; var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; var canHover = window.matchMedia && window.matchMedia('(hover: hover) and (pointer: fine)').matches; function $(s, r) { return (r || document).querySelector(s); } function $$(s, r) { return Array.prototype.slice.call((r || document).querySelectorAll(s)); } function trim(s) { return (s || '').replace(/^\s+|\s+$/g, ''); } function make(tag, cls, text) { var e = document.createElement(tag); if (cls) e.className = cls; if (text) e.textContent = text; return e; } function svg(name) { return ''; } function pad(n) { return (n < 10 ? '0' : '') + n; } function init() { if (!document.body.classList.contains('product-single')) return; var form = $('form#single-product-form'); var layout = $('.saji-pdp__layout'); if (!form || !layout) return; var stage = layout.closest('.saji-pdp > div') || layout.parentNode; var gallery = $('.saji-pdp__gallery'); var slider = gallery && $('.saji-pdp__slider', gallery); var titleEl = $('h1.product-title', form); var title = titleEl ? trim(titleEl.textContent) : ''; var desc = $('#more-content'); stage.classList.add('hp-stage'); if (!reduce) stage.classList.add('hp-anim'); ambient(stage, gallery); splitTitle(titleEl); highlights(form, desc); trust(form, title); buyNote(form); galleryExtras(gallery, slider, form); var after = marquee(stage); story(after, desc, gallery, title); hideEmpty(); reveal(); waitButton(form, function (btn) { stickyBar(btn, form, gallery, title); flyToCart(btn, gallery); }); // الدخول: نستنى فريمين عشان الحالة الأولى تتطبق الأول window.requestAnimationFrame(function () { window.requestAnimationFrame(function () { stage.classList.add('hp-ready'); }); }); } /* النور اللي بيمشي مع الماوس، وذرات الزعفران الطايرة */ function ambient(stage, gallery) { var amb = make('div', 'hp-amb'); amb.setAttribute('aria-hidden', 'true'); var glow = make('div', 'hp-amb__glow'); var canvas = make('canvas', 'hp-amb__dust'); amb.appendChild(glow); amb.appendChild(canvas); stage.insertBefore(amb, stage.firstChild); // النور يبدأ ورا الصورة function home() { if (!gallery) return; var s = stage.getBoundingClientRect(); var g = gallery.getBoundingClientRect(); glow.style.setProperty('--hp-gx', (g.left - s.left + g.width / 2) + 'px'); glow.style.setProperty('--hp-gy', (g.top - s.top + g.height / 2.4) + 'px'); } home(); if (reduce) return; if (canHover) { var px = 0, py = 0, queued = false; stage.addEventListener('pointermove', function (e) { var s = stage.getBoundingClientRect(); px = e.clientX - s.left; py = e.clientY - s.top; if (queued) return; queued = true; window.requestAnimationFrame(function () { queued = false; glow.style.setProperty('--hp-gx', px + 'px'); glow.style.setProperty('--hp-gy', py + 'px'); }); }, { passive: true }); stage.addEventListener('pointerleave', home); } var ctx = canvas.getContext('2d'); if (!ctx) return; var dpr = Math.min(window.devicePixelRatio || 1, 1.5); var W = 0, H = 0, dots = [], raf = 0, visible = false; function size() { W = stage.clientWidth; H = stage.clientHeight; canvas.width = Math.round(W * dpr); canvas.height = Math.round(H * dpr); canvas.style.width = W + 'px'; canvas.style.height = H + 'px'; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); var n = W < 700 ? 22 : 46; dots = []; for (var i = 0; i < n; i++) { dots.push({ x: Math.random() * W, y: Math.random() * H, r: 0.6 + Math.random() * 1.9, vy: 0.12 + Math.random() * 0.38, vx: (Math.random() - 0.5) * 0.14, a: 0.18 + Math.random() * 0.5, t: Math.random() * 6.28 }); } } function tick() { ctx.clearRect(0, 0, W, H); ctx.fillStyle = '#F0C26B'; for (var i = 0; i < dots.length; i++) { var p = dots[i]; p.t += 0.012; p.y -= p.vy; p.x += p.vx + Math.sin(p.t) * 0.12; if (p.y < -6) { p.y = H + 6; p.x = Math.random() * W; } ctx.globalAlpha = p.a * (0.55 + 0.45 * Math.sin(p.t * 2.2)); ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, 6.283); ctx.fill(); } raf = visible ? window.requestAnimationFrame(tick) : 0; } size(); if (window.ResizeObserver) { var lastW = W; new ResizeObserver(function () { if (Math.abs(stage.clientWidth - lastW) < 2 && Math.abs(stage.clientHeight - H) < 40) return; lastW = stage.clientWidth; size(); home(); }).observe(stage); } // الرسم شغال بس والمسرح ظاهر new IntersectionObserver(function (entries) { visible = entries[0].isIntersecting; if (visible && !raf) raf = window.requestAnimationFrame(tick); }).observe(stage); } /* العنوان كلمة كلمة (نفس الكلام، بس كل كلمة في span) */ function splitTitle(h) { if (!h) return; var words = trim(h.textContent).split(/\s+/); if (!words[0]) return; h.setAttribute('aria-label', words.join(' ')); h.textContent = ''; words.forEach(function (w, i) { var outer = make('span', 'hp-w'); var inner = make('span', '', w); inner.style.setProperty('--i', i); outer.setAttribute('aria-hidden', 'true'); outer.appendChild(inner); h.appendChild(outer); if (i < words.length - 1) h.appendChild(document.createTextNode(' ')); }); } /* أهم المميزات من قسم «المميزات» في الوصف */ function highlights(form, desc) { if (!desc) return; var list = null; $$('h3', desc).some(function (h) { if (h.textContent.indexOf('المميزات') === -1) return false; var n = h.nextElementSibling; while (n && n.tagName !== 'UL' && n.tagName !== 'H3') n = n.nextElementSibling; if (n && n.tagName === 'UL') list = n; return !!list; }); if (!list) list = $('ul', desc); if (!list) return; var items = $$('li', list).slice(0, 4).map(function (li) { var s = $('strong', li); var t = s ? trim(s.textContent).replace(/[::]\s*$/, '') : trim(li.textContent).split(/\s+/).slice(0, 4).join(' '); return t; }).filter(Boolean); if (!items.length) return; var ul = make('ul', 'hp-hls'); items.forEach(function (t) { ul.appendChild(make('li', 'hp-hl', t)); }); var price = $('.saji-pdp__price-display', form); (price ? price.parentNode : form).insertBefore(ul, price ? price.nextSibling : null); } /* مربعات الثقة */ function trust(form, title) { var box = make('div', 'hp-trust'); CONFIG.trust.forEach(function (t) { var item; if (t.wa) { item = make('a', 'hp-trust-item'); item.href = 'https://wa.me/' + CONFIG.whatsapp + '?text=' + encodeURIComponent('السلام عليكم، عندي سؤال عن: ' + title + ' ' + location.href); item.target = '_blank'; item.rel = 'noopener'; } else { item = make('div', 'hp-trust-item'); } var icon = make('span', 'hp-trust-icon'); icon.innerHTML = svg(t.icon); var copy = make('span'); copy.appendChild(make('strong', '', t.title)); copy.appendChild(make('small', '', t.sub)); item.appendChild(icon); item.appendChild(copy); box.appendChild(item); }); var col = $('.saji-pdp__buybox-col', form); form.insertBefore(box, col ? col.nextSibling : null); } function buyNote(form) { var box = $('.saji-pdp__buybox', form); if (box && !$('.hp-buy-note', box)) box.appendChild(make('p', 'hp-buy-note', CONFIG.buyNote)); } /* الصورة: إمالة 3D ولمعة، بادج الخصم، وعداد الصور */ function galleryExtras(gallery, slider, form) { if (!gallery || !slider) return; // نسبة الخصم جنب السعر var stock = $('.saji-pdp__stock small', form); var saleRow = $('.saji-pdp__price-display .price_is_on_sale', form); if (stock && saleRow) saleRow.appendChild(stock); // بادج الخصم: سلة بتكتب النسبة متأخر، فبنحسبها من السعرين var badge = make('span', 'hp-gallery-badge'); badge.hidden = true; slider.appendChild(badge); var priceBox = $('.saji-pdp__price-display', form); function num(e) { return e ? parseFloat(e.textContent.replace(/[^\d.]/g, '')) : 0; } function updateBadge() { var sale = priceBox && $('.price_is_on_sale', priceBox); var now = sale && num($('.total-price', sale)); var before = sale && num($('.before-price', sale)); var pct = sale && sale.offsetParent && before > now && now > 0 ? Math.round((before - now) / before * 100) : 0; badge.hidden = !pct; if (pct) badge.textContent = '-' + pct + '%'; } updateBadge(); window.setTimeout(updateBadge, 1500); if (priceBox) new MutationObserver(updateBadge).observe(priceBox, { childList: true, subtree: true, characterData: true }); // عداد الصور (الصور الأساسية بس) var slides = $$('.saji-pdp__slide', gallery); if (slides.length > 1) { var count = make('span', 'hp-gallery-count'); slider.appendChild(count); var refresh = function () { var idx = 0; for (var k = 0; k < slides.length; k++) if (slides[k].classList.contains('swiper-slide-active')) { idx = k; break; } var txt = (idx + 1) + ' / ' + slides.length; if (count.textContent !== txt) count.textContent = txt; }; refresh(); // بنراقب الشرايح بس (العداد برّاها، فمفيش لفة ما بتخلصش) var wrap = $('.swiper-wrapper', slider); if (wrap) new MutationObserver(refresh).observe(wrap, { subtree: true, attributes: true, attributeFilter: ['class'] }); } // الإمالة واللمعة (لابتوب بس) var glare = make('span', 'hp-glare'); glare.setAttribute('aria-hidden', 'true'); slider.appendChild(glare); if (reduce || !canHover) return; var rect = null, mx = 0, my = 0, queued = false; slider.addEventListener('pointerenter', function () { rect = slider.getBoundingClientRect(); slider.classList.add('is-tilt'); }); slider.addEventListener('pointermove', function (e) { if (!rect) rect = slider.getBoundingClientRect(); mx = (e.clientX - rect.left) / rect.width - 0.5; my = (e.clientY - rect.top) / rect.height - 0.5; if (queued) return; queued = true; window.requestAnimationFrame(function () { queued = false; slider.style.transform = 'perspective(1400px) rotateX(' + (-my * 7).toFixed(2) + 'deg) rotateY(' + (mx * 9).toFixed(2) + 'deg)'; glare.style.setProperty('--hp-lx', (mx * 45).toFixed(1) + '%'); glare.style.setProperty('--hp-ly', (my * 45).toFixed(1) + '%'); }); }, { passive: true }); slider.addEventListener('pointerleave', function () { rect = null; slider.classList.remove('is-tilt'); slider.style.transform = ''; }); } /* الشريط الدهبي المتحرك */ function marquee(stage) { var bar = make('div', 'hp-marquee'); bar.setAttribute('aria-hidden', 'true'); var track = make('div', 'hp-marquee__track'); // القايمة متكررة 4 مرات عشان تملا الشاشات الكبيرة، والحركة بنص الطول بالظبط for (var r = 0; r < 4; r++) { CONFIG.marquee.forEach(function (t) { track.appendChild(make('span', 'hp-marquee__item', t)); }); } bar.appendChild(track); stage.parentNode.insertBefore(bar, stage.nextSibling); // بيقف وهو برّه الشاشة new IntersectionObserver(function (e) { bar.classList.toggle('is-paused', !e[0].isIntersecting); }).observe(bar); return bar; } /* قصة المنتج: الوصف بيتقسم حسب عناوينه، والصورة ثابتة جنبه */ function story(after, desc, gallery, title) { if (!desc) return; var groups = []; var cur = { title: CONFIG.firstPart, nodes: [] }; function hasText(nodes) { return nodes.some(function (n) { return trim(n.textContent); }); } Array.prototype.forEach.call(desc.childNodes, function (n) { if (n.nodeType === 1 && n.tagName === 'H3') { if (hasText(cur.nodes)) groups.push(cur); cur = { title: trim(n.textContent), nodes: [] }; } else if (n.nodeType === 1 && n.tagName === 'BR') { return; } else if (n.nodeType === 3 && !trim(n.textContent)) { return; } else { cur.nodes.push(n); } }); if (hasText(cur.nodes)) groups.push(cur); if (!groups.length) return; var sec = make('section', 'hp-story'); var inner = make('div', 'hp-story__inner'); var head = make('div', 'hp-story__head'); head.setAttribute('data-hp-reveal', ''); head.appendChild(make('span', 'hp-eyebrow', CONFIG.storyEyebrow)); head.appendChild(make('h2', 'hp-story__title', title)); inner.appendChild(head); // صور المنتج نفسها var srcs = []; $$('.saji-pdp__slide img', gallery).forEach(function (img) { var s = img.getAttribute('data-src') || img.currentSrc || img.src; if (s && srcs.indexOf(s) === -1) srcs.push(s); }); var media = make('aside', 'hp-story__media'); var frame = make('div', 'hp-story__frame'); var pics = srcs.map(function (s, i) { var im = make('img'); im.src = s; im.alt = title; im.loading = 'lazy'; if (!i) im.className = 'is-on'; frame.appendChild(im); return im; }); var metaRow = make('div', 'hp-story__meta'); var bigNum = make('span', 'hp-story__num', '01'); var bar = make('span', 'hp-story__bar'); bar.appendChild(document.createElement('i')); metaRow.appendChild(bigNum); metaRow.appendChild(bar); media.appendChild(frame); media.appendChild(metaRow); if (pics.length) inner.appendChild(media); var steps = make('div', 'hp-story__steps'); var stepEls = groups.map(function (g, i) { var step = make('article', 'hp-step' + (i ? '' : ' is-active')); step.appendChild(make('span', 'hp-step__num', pad(i + 1) + ' / ' + pad(groups.length))); step.appendChild(make('h3', '', g.title)); var body = make('div', 'hp-step__body'); g.nodes.forEach(function (n) { body.appendChild(n.cloneNode(true)); }); step.appendChild(body); steps.appendChild(step); return step; }); inner.appendChild(steps); sec.appendChild(inner); after.parentNode.insertBefore(sec, after.nextSibling); document.body.classList.add('hp-has-story'); var active = 0; function setActive(i) { if (i === active) return; stepEls[active].classList.remove('is-active'); stepEls[i].classList.add('is-active'); active = i; bigNum.textContent = pad(i + 1); bar.firstChild.style.setProperty('--hp-p', ((i + 1) / groups.length).toFixed(3)); if (pics.length > 1) { pics.forEach(function (p, k) { p.classList.toggle('is-on', k === i % pics.length); }); } else if (pics[0]) { pics[0].style.setProperty('--hp-zoom', (1 + (i % 2) * 0.07).toFixed(2)); } } bar.firstChild.style.setProperty('--hp-p', (1 / groups.length).toFixed(3)); // القسم اللي في نص الشاشة هو اللي بينوّر var io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (e.isIntersecting) setActive(stepEls.indexOf(e.target)); }); }, { rootMargin: '-45% 0px -45% 0px' }); stepEls.forEach(function (s) { io.observe(s); }); } /* السكاشن الفاضية بتستخبى، وترجع لو اتملت */ function hideEmpty() { var reviews = $('.saji-reviews-theme'); var rBox = reviews && reviews.closest('.container'); if (rBox) { var checkReviews = function () { var has = $('.s-comments-item, [class*="comment-item"]', reviews); rBox.style.display = !has && reviews.textContent.replace(/\s+/g, '').length < 12 ? 'none' : ''; }; checkReviews(); new MutationObserver(checkReviews).observe(reviews, { childList: true, subtree: true }); } var similar = $('.container.similar-products-slider'); if (similar) { var checkSimilar = function () { // سلة بتحط شريحة فاضية حتى لو مفيش منتجات، فبندوّر على كارت منتج حقيقي similar.style.display = $('custom-salla-product-card, salla-product-card, .s-product-card-entry, .product-entry', similar) ? '' : 'none'; }; window.setTimeout(checkSimilar, 3000); new MutationObserver(checkSimilar).observe(similar, { childList: true, subtree: true }); } } /* ظهور ناعم للسكاشن اللي تحت */ function reveal() { $$('.s-block--bundle-similar-products, .container.similar-products-slider, .saji-reviews-theme').forEach(function (e) { e.setAttribute('data-hp-reveal', ''); }); var els = $$('[data-hp-reveal]'); if (reduce || !window.IntersectionObserver) { els.forEach(function (e) { e.classList.add('hp-in'); }); return; } var io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (!e.isIntersecting) return; e.target.classList.add('hp-in'); io.unobserve(e.target); }); }, { rootMargin: '0px 0px -10% 0px' }); els.forEach(function (e) { io.observe(e); }); } /* زرار سلة بيتبني بعد تحميل الصفحة، فبنستناه */ function waitButton(form, done) { var tries = 0; (function look() { var btn = $('salla-add-product-button .s-add-product-button-main button[type="submit"]', form); if (btn) done(btn); else if (++tries < 40) window.setTimeout(look, 250); })(); } /* شريط الشراء الثابت على اللابتوب */ function stickyBar(btn, form, gallery, title) { var price = $('.saji-pdp__price-display strong.total-price', form); var img = gallery && $('.saji-pdp__slide img', gallery); var bar = make('div', 'hp-bar'); var thumb = make('img'); thumb.alt = ''; if (img) thumb.src = img.currentSrc || img.src; var copy = make('div', 'hp-bar-copy'); copy.appendChild(make('div', 'hp-bar-title', title)); var pr = make('div', 'hp-bar-price'); copy.appendChild(pr); var go = make('button', '', 'أضف للسلة'); go.type = 'button'; bar.appendChild(thumb); bar.appendChild(copy); bar.appendChild(go); document.body.appendChild(bar); go.addEventListener('click', function () { btn.click(); }); function syncPrice() { if (price) pr.innerHTML = price.innerHTML; } syncPrice(); if (price) new MutationObserver(syncPrice).observe(price.parentNode, { childList: true, subtree: true, characterData: true }); var btnSeen = true, footSeen = false; function update() { bar.classList.toggle('hp-bar-visible', !btnSeen && !footSeen && window.innerWidth >= 1024); } new IntersectionObserver(function (e) { btnSeen = e[0].isIntersecting; update(); }).observe(btn); var foot = $('footer.hf') || $('footer'); if (foot) new IntersectionObserver(function (e) { footSeen = e[0].isIntersecting; update(); }).observe(foot); window.addEventListener('resize', update, { passive: true }); } /* الصورة بتطير لأيقونة السلة بعد ما الإضافة تنجح */ function flyToCart(btn, gallery) { if (reduce || !Element.prototype.animate) return; var last = 0; function mark() { last = Date.now(); } btn.addEventListener('click', mark, true); document.addEventListener('click', function (e) { if (e.target.closest && e.target.closest('.hp-bar button')) mark(); }, true); function fly() { if (Date.now() - last > 8000) return; // الإضافة جاية من زرار تاني في الصفحة last = 0; var cart = $('#header .s-cart-summary-wrapper') || $('#header salla-cart-summary'); var img = gallery && ($('.saji-pdp__slide.swiper-slide-active img', gallery) || $('.saji-pdp__slide img', gallery)); if (!cart || !img) return; var a = img.getBoundingClientRect(); // لو الصورة برّه الشاشة، بتطير من الزرار if (a.bottom < 0 || a.top > window.innerHeight || !a.width) { var b0 = (btn.offsetParent ? btn : $('.hp-bar button') || btn).getBoundingClientRect(); a = { left: b0.left + b0.width / 2 - 40, top: b0.top - 20, width: 80, height: 80 }; } var c = cart.getBoundingClientRect(); var ghost = make('img', 'hp-ghost'); ghost.src = img.currentSrc || img.src; ghost.alt = ''; ghost.style.left = a.left + 'px'; ghost.style.top = a.top + 'px'; ghost.style.width = a.width + 'px'; ghost.style.height = a.height + 'px'; document.body.appendChild(ghost); var dx = c.left + c.width / 2 - (a.left + a.width / 2); var dy = c.top + c.height / 2 - (a.top + a.height / 2); var s = 44 / Math.max(a.width, 44); var anim = ghost.animate([ { transform: 'translate(0, 0) scale(1)', opacity: 1 }, { transform: 'translate(' + dx * 0.5 + 'px, ' + (dy * 0.5 - 110) + 'px) scale(' + (s * 3.2) + ')', opacity: 1, offset: 0.55 }, { transform: 'translate(' + dx + 'px, ' + dy + 'px) scale(' + s * 0.5 + ')', opacity: 0.2 } ], { duration: 950, easing: 'cubic-bezier(0.55, 0, 0.3, 1)' }); anim.onfinish = function () { ghost.remove(); cart.animate([ { transform: 'scale(1)' }, { transform: 'scale(1.35) rotate(-8deg)' }, { transform: 'scale(1)' } ], { duration: 520, easing: 'cubic-bezier(0.3, 1.6, 0.5, 1)' }); }; } // نستنى نجاح الإضافة من سلة نفسها try { if (window.salla && salla.cart && salla.cart.event && salla.cart.event.onItemAdded) { salla.cart.event.onItemAdded(fly); return; } } catch (err) { /* لو سلة غيّرت الـAPI نكمل بالضغطة */ } btn.addEventListener('click', function () { window.setTimeout(fly, 150); }); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true }); else init(); })(); /* ---------- 13) الرئيسية: مسرح المنتج المميز (نور وذرات)، شريط دهبي، وطيران صورة المنتج للسلة من أي كارت ---------- */ (function () { 'use strict'; var MARQUEE = ['مختار لك بعناية', 'خبرة أكثر من 40 سنة', 'نوصّل لين باب البيت', 'استرجاع خلال 7 أيام']; var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; var canHover = window.matchMedia && window.matchMedia('(hover: hover) and (pointer: fine)').matches; function make(tag, cls, text) { var e = document.createElement(tag); if (cls) e.className = cls; if (text) e.textContent = text; return e; } /* مسرح المنتج المميز */ function stage() { var sec = document.querySelector('.single-product-section-home'); if (!sec || sec.classList.contains('hp-home-stage')) return; sec.classList.add('hp-home-stage'); ['tr', 'tl', 'br', 'bl'].forEach(function (k) { sec.appendChild(make('span', 'hp-corner hp-corner--' + k)); }); var amb = make('div', 'hp-amb'); amb.setAttribute('aria-hidden', 'true'); var glow = make('div', 'hp-amb__glow'); var canvas = make('canvas', 'hp-amb__dust'); amb.appendChild(glow); amb.appendChild(canvas); sec.insertBefore(amb, sec.firstChild); // الشريط الدهبي تحت المسرح، وبيقف وهو برّه الشاشة var bar = make('div', 'hp-marquee'); bar.setAttribute('aria-hidden', 'true'); var track = make('div', 'hp-marquee__track'); for (var r = 0; r < 4; r++) MARQUEE.forEach(function (t) { track.appendChild(make('span', 'hp-marquee__item', t)); }); bar.appendChild(track); sec.parentNode.insertBefore(bar, sec.nextSibling); new IntersectionObserver(function (e) { bar.classList.toggle('is-paused', !e[0].isIntersecting); }).observe(bar); if (reduce) return; // النور بيمشي مع الماوس if (canHover) { var px = 0, py = 0, queued = false; sec.addEventListener('pointermove', function (e) { var s = sec.getBoundingClientRect(); px = e.clientX - s.left; py = e.clientY - s.top; if (queued) return; queued = true; window.requestAnimationFrame(function () { queued = false; glow.style.setProperty('--hp-gx', px + 'px'); glow.style.setProperty('--hp-gy', py + 'px'); }); }, { passive: true }); } // ذرات الزعفران (شغالة بس والمسرح ظاهر) var ctx = canvas.getContext('2d'); if (!ctx) return; var dpr = Math.min(window.devicePixelRatio || 1, 1.5); var W = 0, H = 0, dots = [], raf = 0, visible = false; function size() { W = sec.clientWidth; H = sec.clientHeight; canvas.width = Math.round(W * dpr); canvas.height = Math.round(H * dpr); canvas.style.width = W + 'px'; canvas.style.height = H + 'px'; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); var n = W < 700 ? 20 : 42; dots = []; for (var i = 0; i < n; i++) { dots.push({ x: Math.random() * W, y: Math.random() * H, r: 0.6 + Math.random() * 1.9, vy: 0.12 + Math.random() * 0.38, vx: (Math.random() - 0.5) * 0.14, a: 0.18 + Math.random() * 0.5, t: Math.random() * 6.28 }); } } function tick() { ctx.clearRect(0, 0, W, H); ctx.fillStyle = '#F0C26B'; for (var i = 0; i < dots.length; i++) { var p = dots[i]; p.t += 0.012; p.y -= p.vy; p.x += p.vx + Math.sin(p.t) * 0.12; if (p.y < -6) { p.y = H + 6; p.x = Math.random() * W; } ctx.globalAlpha = p.a * (0.55 + 0.45 * Math.sin(p.t * 2.2)); ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, 6.283); ctx.fill(); } raf = visible ? window.requestAnimationFrame(tick) : 0; } size(); if (window.ResizeObserver) { var lastW = W; new ResizeObserver(function () { if (Math.abs(sec.clientWidth - lastW) < 2 && Math.abs(sec.clientHeight - H) < 40) return; lastW = sec.clientWidth; size(); }).observe(sec); } new IntersectionObserver(function (e) { visible = e[0].isIntersecting; if (visible && !raf) raf = window.requestAnimationFrame(tick); }).observe(sec); } /* صورة المنتج بتطير للسلة بعد ما الإضافة تنجح (صفحة المنتج ليها نسخة خاصة في قسم 12) */ function flyToCart() { if (reduce || !Element.prototype.animate) return; var src = null, from = null, at = 0; document.addEventListener('click', function (e) { var btn = e.target.closest && e.target.closest('button'); if (!btn) return; var card = btn.closest('custom-salla-product-card, salla-product-card, .single-product-section-home'); if (!card) return; var img = card.querySelector('img.card-slide-first, .card-slide-images img, img'); var bg = card.querySelector('.lazy__bg[data-bg]'); var box = img || bg; if (!box) return; src = img ? (img.currentSrc || img.src) : bg.getAttribute('data-bg'); from = box; at = Date.now(); }, true); function fly() { if (!from || Date.now() - at > 8000) return; var cart = document.querySelector('#header .s-cart-summary-wrapper') || document.querySelector('#header salla-cart-summary'); if (!cart) return; var a = from.getBoundingClientRect(); var c = cart.getBoundingClientRect(); from = null; if (!a.width || a.bottom < 0 || a.top > window.innerHeight) return; var w = Math.min(a.width, 240), h = Math.min(a.height, 240); var x = a.left + (a.width - w) / 2, y = a.top + (a.height - h) / 2; var ghost = make('img', 'hp-ghost'); ghost.src = src; ghost.alt = ''; ghost.style.cssText = 'left:' + x + 'px;top:' + y + 'px;width:' + w + 'px;height:' + h + 'px'; document.body.appendChild(ghost); var dx = c.left + c.width / 2 - (x + w / 2); var dy = c.top + c.height / 2 - (y + h / 2); var s = 44 / Math.max(w, 44); var anim = ghost.animate([ { transform: 'translate(0, 0) scale(1)', opacity: 1 }, { transform: 'translate(' + dx * 0.5 + 'px, ' + (dy * 0.5 - 110) + 'px) scale(' + Math.min(1, s * 3.2) + ')', opacity: 1, offset: 0.55 }, { transform: 'translate(' + dx + 'px, ' + dy + 'px) scale(' + s * 0.5 + ')', opacity: 0.2 } ], { duration: 950, easing: 'cubic-bezier(0.55, 0, 0.3, 1)' }); anim.onfinish = function () { ghost.remove(); cart.animate([{ transform: 'scale(1)' }, { transform: 'scale(1.35) rotate(-8deg)' }, { transform: 'scale(1)' }], { duration: 520, easing: 'cubic-bezier(0.3, 1.6, 0.5, 1)' }); }; } try { if (window.salla && salla.cart && salla.cart.event && salla.cart.event.onItemAdded) salla.cart.event.onItemAdded(fly); } catch (err) { /* سلة غيّرت الـAPI */ } } function init() { if (document.body.classList.contains('product-single')) return; if (document.body.classList.contains('index')) stage(); flyToCart(); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, { once: true }); else init(); })();