/* Add custom JS code below */
function styleSunsetFastCheckout() {
document
.querySelectorAll('salla-mini-checkout-widget')
.forEach(widget => {
if (!widget.shadowRoot) return;
if (widget.shadowRoot.querySelector('#sunset-fast-checkout-style')) return;
const style = document.createElement('style');
style.id = 'sunset-fast-checkout-style';
style.textContent = `
.s-fast-checkout-button.outline {
background: #B88A3B !important;
border-color: #B88A3B !important;
color: #FFFFFF !important;
box-shadow:
0 3px 8px rgba(184,138,59,.16),
0 1px 2px rgba(0,0,0,.08);
transition:
background-color .22s ease,
border-color .22s ease,
box-shadow .22s ease,
transform .18s ease !important;
}
.s-fast-checkout-button.outline:hover {
background: #A6792F !important;
border-color: #A6792F !important;
color: #FFFFFF !important;
box-shadow:
0 5px 12px rgba(166,121,47,.20),
0 2px 4px rgba(0,0,0,.10);
transform: translateY(-1px);
}
.s-fast-checkout-button.outline:active {
background: #956B2A !important;
border-color: #956B2A !important;
transform: translateY(0) scale(.992);
box-shadow:
0 2px 5px rgba(0,0,0,.14);
}
.s-fast-checkout-button.outline svg,
.s-fast-checkout-button.outline svg path {
color: #FFFFFF !important;
fill: #FFFFFF !important;
}
`;
widget.shadowRoot.appendChild(style);
});
}
customElements
.whenDefined('salla-mini-checkout-widget')
.then(() => {
styleSunsetFastCheckout();
const observer = new MutationObserver(() => {
styleSunsetFastCheckout();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
/* =========================================
SUNSET SPA - FINAL FOOTER V3
مستقل عن تحميل مكونات سلة
========================================= */
(function () {
"use strict";
function createSunsetFooter() {
const footer = document.querySelector("footer.store-footer");
if (!footer) return;
// منع التكرار
if (footer.querySelector("#sunset-final-footer")) return;
const container = footer.querySelector(
".store-footer__inner > .container"
);
const bottom = footer.querySelector(".footer-bottom");
if (!container || !bottom) return;
const newFooter = document.createElement("section");
newFooter.id = "sunset-final-footer";
newFooter.dir = "rtl";
newFooter.setAttribute(
"aria-label",
"معلومات غروب الشمس سبا"
);
newFooter.innerHTML = `
وجهتك لخدمات المساج والسبا الرجالي
في مكة المكرمة، حيث الاسترخاء والعناية
في أجواء راقية وخاصة.
✦ خصوصية تامة
✦ عناية مميزة
✦ تجربة فاخرة
`;
// وضع الفوتر الجديد قبل وسائل الدفع
container.insertBefore(newFooter, bottom);
// الإخفاء لا يتم إلا بعد إنشاء الفوتر الجديد
footer.classList.add("sunset-final-ready");
}
if (document.readyState === "loading") {
document.addEventListener(
"DOMContentLoaded",
createSunsetFooter,
{ once: true }
);
} else {
createSunsetFooter();
}
})();
/* =========================================
SUNSET SPA - HEADER V4 JS
Menu + Independent Search Dialog
========================================= */
(function () {
"use strict";
const LINKS = [
["الرئيسية", "/"],
["خدمات المساج", "/المساج/c2002398162"],
["الحمام المغربي والعناية", "/الحمام-المغربي-والعناية/c1093094099"],
["العروض والباكجيات", "/العروض-والباكجيات/c1052219358"],
["فروعنا", "/فروعنا/page-1487047488"]
];
const SEARCH_TERMS = [
"مساج جاوا",
"مساج استرخائي",
"حمام مغربي",
"الباكيج الملكي"
];
let active = null;
let lastFocus = null;
let searchTimer = null;
function link(label, url) {
const a = document.createElement("a");
a.href = url;
a.textContent = label;
return a;
}
function closeDialog(restore) {
if (!active) return;
active.classList.remove("is-open");
active.setAttribute("aria-hidden", "true");
document.body.classList.remove("ss-v4-modal-open");
active = null;
if (restore !== false && lastFocus &&
typeof lastFocus.focus === "function") {
lastFocus.focus();
}
}
function openDialog(root) {
if (active) closeDialog(false);
lastFocus = document.activeElement;
root.classList.add("is-open");
root.setAttribute("aria-hidden", "false");
document.body.classList.add("ss-v4-modal-open");
active = root;
const target = root.querySelector(
".ss-v4-search-input, .ss-v4-close"
);
if (target) target.focus();
}
function createDialog(id, title, isSearch) {
const root = document.createElement("div");
root.className = "ss-v4-dialog" +
(isSearch ? " ss-v4-search" : "");
root.id = id;
root.setAttribute("aria-hidden", "true");
const panel = document.createElement("section");
panel.className = "ss-v4-panel";
panel.setAttribute("role", "dialog");
panel.setAttribute("aria-modal", "true");
panel.setAttribute("aria-label", title);
const heading = document.createElement("div");
heading.className = "ss-v4-heading";
const h2 = document.createElement("h2");
h2.textContent = title;
const close = document.createElement("button");
close.className = "ss-v4-close";
close.type = "button";
close.textContent = "×";
close.setAttribute("aria-label", "إغلاق");
close.addEventListener("click", () => closeDialog());
heading.append(h2, close);
panel.appendChild(heading);
root.appendChild(panel);
root.addEventListener("click", function (e) {
if (e.target === root) closeDialog();
});
document.body.appendChild(root);
return { root, panel };
}
document.addEventListener("keydown", function (e) {
if (!active) return;
if (e.key === "Escape") {
e.preventDefault();
closeDialog();
return;
}
if (e.key !== "Tab") return;
const focusable = Array.from(active.querySelectorAll(
'button:not([disabled]),a[href],input:not([disabled])'
)).filter(el => el.getClientRects().length);
if (!focusable.length) return;
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey &&
document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
function createNavigation(header) {
const row = header.querySelector(".header-container > .flex");
if (!row || row.children.length < 3) return;
if (!header.querySelector(".ss-desktop-nav")) {
const nav = document.createElement("nav");
nav.className = "ss-desktop-nav";
nav.setAttribute("aria-label", "التنقل الرئيسي");
LINKS.slice(0, 4).forEach(([name, url]) => {
const a = link(name, url);
const current = decodeURI(location.pathname)
.replace(/\/+$/, "") || "/";
const target = decodeURI(
new URL(url, location.origin).pathname
).replace(/\/+$/, "") || "/";
if (current === target) {
a.setAttribute("aria-current", "page");
}
nav.appendChild(a);
});
row.children[0].insertBefore(
nav, row.children[0].firstChild
);
}
header.classList.add("ss-header-ready");
}
function createMenu(header) {
const trigger = header.querySelector(".mburger");
if (!trigger || document.getElementById("ss-v4-menu")) return;
const dialog = createDialog(
"ss-v4-menu", "القائمة", false
);
const nav = document.createElement("nav");
nav.className = "ss-v4-links";
nav.setAttribute("aria-label", "أقسام المتجر");
LINKS.forEach(([name, url]) => {
nav.appendChild(link(name, url));
});
dialog.panel.appendChild(nav);
trigger.setAttribute("aria-haspopup", "dialog");
trigger.setAttribute("aria-controls", "ss-v4-menu");
trigger.addEventListener("click", function (e) {
e.preventDefault();
e.stopImmediatePropagation();
openDialog(dialog.root);
}, true);
}
function createSearch(header) {
const trigger = header.querySelector(".search-btn");
if (!trigger || document.getElementById("ss-v4-search")) {
return;
}
const dialog = createDialog(
"ss-v4-search", "البحث", true
);
const form = document.createElement("form");
form.className = "ss-v4-search-form";
form.action = "/search";
form.method = "GET";
const input = document.createElement("input");
input.className = "ss-v4-search-input";
input.type = "search";
input.name = "q";
input.autocomplete = "off";
input.required = true;
input.placeholder = "ابحث عن خدمة أو باكيج...";
input.setAttribute("aria-label", "ابحث في خدمات المتجر");
const submit = document.createElement("button");
submit.className = "ss-v4-search-submit";
submit.type = "submit";
submit.textContent = "بحث";
form.append(input, submit);
const suggestions = document.createElement("div");
suggestions.className = "ss-v4-suggestions";
const sugTitle = document.createElement("p");
sugTitle.className = "ss-v4-small-title";
sugTitle.textContent = "عمليات بحث مقترحة";
const chips = document.createElement("div");
chips.className = "ss-v4-chips";
SEARCH_TERMS.forEach(term => {
const btn = document.createElement("button");
btn.type = "button";
btn.textContent = term;
btn.addEventListener("click", function () {
input.value = term;
input.dispatchEvent(new Event("input"));
input.focus();
});
chips.appendChild(btn);
});
suggestions.append(sugTitle, chips);
const results = document.createElement("div");
results.className = "ss-v4-results";
const resultsLabel = document.createElement("p");
resultsLabel.className = "ss-v4-results-label";
resultsLabel.textContent = "نتائج المنتجات";
const products = document.createElement("salla-products-list");
products.setAttribute("source", "search");
products.setAttribute("limit", "4");
products.setAttribute("row-cards", "");
results.append(resultsLabel, products);
const status = document.createElement("p");
status.className = "ss-v4-status";
status.setAttribute("role", "status");
status.setAttribute("aria-live", "polite");
status.textContent = "ابدأ بالكتابة لعرض الخدمات المناسبة.";
const allResults = link(
"عرض جميع نتائج البحث ←",
"/search"
);
allResults.className = "ss-v4-all-results";
dialog.panel.append(form, suggestions, results, status, allResults);
let revision = 0;
function updateSearch() {
const query = input.value.trim();
clearTimeout(searchTimer);
revision += 1;
const thisRevision = revision;
if (query.length < 2) {
results.classList.remove("is-visible");
allResults.classList.remove("is-visible");
suggestions.style.display = "";
status.textContent = "اكتب حرفين على الأقل للبحث.";
return;
}
suggestions.style.display = "none";
allResults.href = "/search?q=" + encodeURIComponent(query);
allResults.classList.add("is-visible");
searchTimer = setTimeout(async function () {
if (thisRevision !== revision) return;
if (!customElements.get("salla-products-list")) {
status.textContent =
"اضغط عرض جميع النتائج للبحث في المتجر.";
results.classList.remove("is-visible");
return;
}
products.setAttribute("source-value", query);
results.classList.add("is-visible");
status.textContent = "جاري تحميل النتائج...";
try {
if (typeof products.reload === "function") {
await products.reload();
}
if (thisRevision === revision) {
status.textContent =
"النتائج المعروضة من متجر غروب الشمس سبا.";
}
} catch (error) {
if (thisRevision === revision) {
results.classList.remove("is-visible");
status.textContent =
"تعذر عرض النتائج السريعة. استخدم عرض جميع النتائج.";
}
}
}, 400);
}
input.addEventListener("input", updateSearch);
trigger.setAttribute("aria-haspopup", "dialog");
trigger.setAttribute("aria-controls", "ss-v4-search");
trigger.addEventListener("click", function (e) {
e.preventDefault();
e.stopImmediatePropagation();
openDialog(dialog.root);
}, true);
}
function init() {
const header = document.querySelector("header.store-header");
if (!header || header.classList.contains("ss-v4-initialized")) {
return;
}
createNavigation(header);
createMenu(header);
createSearch(header);
header.classList.add("ss-v4-initialized");
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init, { once: true });
} else {
init();
}
})();
/* ==========================================
SUNSET SPA | REVIEWS COUNTER V9
0 → 9000 over 2 seconds
========================================== */
(function () {
"use strict";
const SELECTOR =
".ss-reviews-v9__count[data-target]";
const formatter = new Intl.NumberFormat("en-US");
function initialize(counter) {
if (counter.dataset.ssV9Ready === "1") return;
const target = Number(counter.dataset.target);
const section = counter.closest(".ss-reviews-v9");
if (!section || !Number.isFinite(target) || target <= 0) return;
counter.dataset.ssV9Ready = "1";
let started = false;
function start() {
if (started) return;
started = true;
if (
window.matchMedia &&
window.matchMedia("(prefers-reduced-motion: reduce)").matches
) {
counter.textContent = formatter.format(target);
return;
}
const duration = 2000;
let startTime = null;
counter.textContent = "0";
function tick(timestamp) {
if (startTime === null) startTime = timestamp;
const progress = Math.min(
(timestamp - startTime) / duration,
1
);
const eased = 1 - Math.pow(1 - progress, 3);
const value = Math.round(target * eased);
counter.textContent = formatter.format(value);
if (progress < 1) {
requestAnimationFrame(tick);
} else {
counter.textContent = formatter.format(target);
}
}
requestAnimationFrame(tick);
}
if ("IntersectionObserver" in window) {
const observer = new IntersectionObserver(
function (entries) {
if (entries.some(entry => entry.isIntersecting)) {
observer.disconnect();
start();
}
},
{ threshold: 0.15 }
);
observer.observe(section);
} else {
start();
}
}
function initAll() {
const counters = document.querySelectorAll(SELECTOR);
counters.forEach(initialize);
return counters.length > 0;
}
function boot() {
if (initAll()) return;
const observer = new MutationObserver(function () {
if (initAll()) observer.disconnect();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(function () {
observer.disconnect();
}, 15000);
}
if (document.readyState === "loading") {
document.addEventListener(
"DOMContentLoaded",
boot,
{ once: true }
);
} else {
boot();
}
})();