first deployment of kikomiko with url photos

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shayan khoshrou
2026-10-19 19:10:57 +02:00
co-authored by Cursor
parent 8d98304137
commit ae3ed7c7b7
159 changed files with 59509 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
import {
hydrateCart,
subscribe,
getSnapshot,
updateQuantity,
removeItem,
formatPrice,
} from "/js/cart.js";
function escapeHtml(s) {
return String(s)
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;");
}
/** Cart page: items + totals only (checkout is a separate step). */
export function initCartPage() {
const root = document.querySelector("[data-cart-page]");
if (!root) return;
hydrateCart();
const list = root.querySelector("[data-cart-lines]");
const totalEl = root.querySelector("[data-cart-total]");
const checkoutBtn = root.querySelector("[data-cart-checkout]");
const emptyEl = root.querySelector("[data-cart-empty]");
const contentEl = root.querySelector("[data-cart-content]");
function render(snap) {
const empty = !snap.items.length;
if (emptyEl) emptyEl.hidden = !empty;
if (contentEl) contentEl.hidden = empty;
if (checkoutBtn) {
if (empty) checkoutBtn.setAttribute("disabled", "");
else checkoutBtn.removeAttribute("disabled");
}
if (!list || !totalEl) return;
if (empty) {
list.innerHTML = "";
totalEl.textContent = formatPrice(0);
return;
}
list.innerHTML = snap.items
.map(
(item) => `
<div class="cart-line" data-id="${escapeHtml(item.productId)}">
${
item.image
? `<img src="${escapeHtml(item.image)}" alt="" width="72" height="96" />`
: `<div style="width:72px;height:96px;background:#f7f7f7"></div>`
}
<div style="flex:1;min-width:0">
<a href="/products/${escapeHtml(item.slug)}/">${escapeHtml(item.name)}</a>
<div class="text-muted" style="font-size:0.85rem;margin-top:0.25rem">${formatPrice(item.price)}</div>
<div class="qty-controls">
<button type="button" data-qty-dec aria-label="کاهش تعداد">−</button>
<span>${item.quantity}</span>
<button type="button" data-qty-inc aria-label="افزایش تعداد">+</button>
<button type="button" data-qty-remove aria-label="حذف از سبد" style="margin-inline-start:0.5rem;font-size:0.75rem;color:#8a8a8a">حذف</button>
</div>
</div>
</div>`
)
.join("");
totalEl.textContent = formatPrice(snap.subtotal);
list.querySelectorAll(".cart-line").forEach((row) => {
const id = row.getAttribute("data-id");
const item = snap.items.find((i) => i.productId === id);
if (!item || !id) return;
row.querySelector("[data-qty-dec]")?.addEventListener("click", () =>
updateQuantity(id, item.quantity - 1)
);
row.querySelector("[data-qty-inc]")?.addEventListener("click", () =>
updateQuantity(id, item.quantity + 1)
);
row.querySelector("[data-qty-remove]")?.addEventListener("click", () =>
removeItem(id)
);
});
}
subscribe(render);
render(getSnapshot());
}