@kotao/storefront 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-U5677AEA.js → chunk-7XYWHWT4.js} +16 -6
- package/dist/chunk-7XYWHWT4.js.map +1 -0
- package/dist/{chunk-GCQI6OKH.js → chunk-H3D7BAOL.js} +3 -26
- package/dist/chunk-H3D7BAOL.js.map +1 -0
- package/dist/chunk-M7BPQ54D.js +26 -0
- package/dist/chunk-M7BPQ54D.js.map +1 -0
- package/dist/{chunk-ISAFEOR2.js → chunk-PXVDVUFX.js} +3 -2
- package/dist/chunk-PXVDVUFX.js.map +1 -0
- package/dist/{client-D9YYA2w6.d.ts → client-DiPdlvPu.d.ts} +1 -1
- package/dist/fetch-B6TIc6lI.d.ts +47 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/react-router.d.ts +5 -3
- package/dist/react-router.js +3 -2
- package/dist/react-router.js.map +1 -1
- package/dist/react.js +285 -146
- package/dist/react.js.map +1 -1
- package/dist/{routing-BfUp49o8.d.ts → routing-BxRlep_-.d.ts} +11 -1
- package/dist/seo.d.ts +3 -1
- package/dist/seo.js +1 -1
- package/dist/settings.d.ts +3 -37
- package/dist/settings.js +2 -1
- package/package.json +1 -1
- package/dist/chunk-GCQI6OKH.js.map +0 -1
- package/dist/chunk-ISAFEOR2.js.map +0 -1
- package/dist/chunk-U5677AEA.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -437,6 +437,12 @@ function useGlobalThemeTokens() {
|
|
|
437
437
|
|
|
438
438
|
// ../smart-cart/src/format.ts
|
|
439
439
|
var formatMoney2 = (m) => {
|
|
440
|
+
if (m.currency === "EUR" && Number.isFinite(m.amount)) {
|
|
441
|
+
const negative = m.amount < 0;
|
|
442
|
+
const abs = Math.round(Math.abs(m.amount));
|
|
443
|
+
const units = Math.floor(abs / 100).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
444
|
+
return `${negative ? "-" : ""}\u20AC${units},${String(abs % 100).padStart(2, "0")}`;
|
|
445
|
+
}
|
|
440
446
|
if (m.currency && /^[A-Za-z]{3}$/.test(m.currency)) {
|
|
441
447
|
try {
|
|
442
448
|
return new Intl.NumberFormat(void 0, {
|
|
@@ -448,6 +454,10 @@ var formatMoney2 = (m) => {
|
|
|
448
454
|
}
|
|
449
455
|
return new Intl.NumberFormat(void 0, { minimumFractionDigits: 2 }).format(m.amount / 100);
|
|
450
456
|
};
|
|
457
|
+
var formatMoneyCompact = (m) => {
|
|
458
|
+
const formatted = formatMoney2(m);
|
|
459
|
+
return Number.isFinite(m.amount) && Math.round(Math.abs(m.amount)) % 100 === 0 ? formatted.replace(/[.,]00(?=\D*$)/, "") : formatted;
|
|
460
|
+
};
|
|
451
461
|
var escapeHtml = (s) => String(s ?? "").replace(
|
|
452
462
|
/[&<>"']/g,
|
|
453
463
|
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]
|
|
@@ -456,7 +466,7 @@ var formatCountdown = (ms) => {
|
|
|
456
466
|
const total = Number.isFinite(ms) && ms > 0 ? Math.floor(ms / 1e3) : 0;
|
|
457
467
|
const minutes = Math.floor(total / 60);
|
|
458
468
|
const seconds = total % 60;
|
|
459
|
-
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
469
|
+
return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
|
460
470
|
};
|
|
461
471
|
|
|
462
472
|
// ../smart-cart/src/widgets/add-on.ts
|
|
@@ -478,10 +488,10 @@ function findAddOnLine(state, variantId) {
|
|
|
478
488
|
var css = `
|
|
479
489
|
.ksc-addon { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center;
|
|
480
490
|
gap: 2px 12px; padding: 14px 18px; border-top: 1px solid var(--ksc-border); font: inherit; color: var(--ksc-text); }
|
|
481
|
-
.ksc-addon__icon { grid-row: 1 / span 2; width:
|
|
491
|
+
.ksc-addon__icon { grid-row: 1 / span 2; width: 44px; height: 44px; display: flex; align-items: center;
|
|
482
492
|
justify-content: center; color: var(--ksc-accent); }
|
|
483
|
-
.ksc-addon__icon svg { width:
|
|
484
|
-
.ksc-addon__img { grid-row: 1 / span 2; width:
|
|
493
|
+
.ksc-addon__icon svg { width: 34px; height: 34px; }
|
|
494
|
+
.ksc-addon__img { grid-row: 1 / span 2; width: 44px; height: 44px; object-fit: cover; border-radius: 8px;
|
|
485
495
|
background: var(--ksc-border); }
|
|
486
496
|
.ksc-addon__text { grid-column: 2; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
|
|
487
497
|
.ksc-addon__title { font-size: .875rem; font-weight: 600; }
|
|
@@ -499,7 +509,11 @@ var css = `
|
|
|
499
509
|
var SHIELD_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l7 3v5c0 4.6-3 7.8-7 9-4-1.2-7-4.4-7-9V6l7-3z"/><path d="M9 12l2 2 4-4"/></svg>`;
|
|
500
510
|
var addOn = {
|
|
501
511
|
key: ADDON_KEY,
|
|
502
|
-
|
|
512
|
+
// Footer, not 'after-items': the add-on is a checkout-adjacent offer that must stay pinned above
|
|
513
|
+
// the discount code, NOT scroll away with the upsell carousel. It renders before `discountCode`
|
|
514
|
+
// (WIDGETS registry order) so it sits directly above the code input (#1548 moved the whole
|
|
515
|
+
// 'after-items' zone into the scroll region — only the upsell belongs there).
|
|
516
|
+
zone: "footer",
|
|
503
517
|
css,
|
|
504
518
|
render({ config, state, variants }) {
|
|
505
519
|
const variantId = readVariantId(config);
|
|
@@ -545,12 +559,11 @@ function readMessage(config) {
|
|
|
545
559
|
return typeof raw === "string" && raw.trim() !== "" ? raw : null;
|
|
546
560
|
}
|
|
547
561
|
var css2 = `
|
|
548
|
-
.ksc-rt { display: flex; align-items: center; justify-content: center; gap:
|
|
549
|
-
padding:
|
|
550
|
-
color:
|
|
551
|
-
background:
|
|
552
|
-
.ksc-rt__count { font-variant-numeric: tabular-nums; font-weight: 700;
|
|
553
|
-
color: color-mix(in oklab, var(--ksc-positive, #0e9f6e) 85%, var(--ksc-text, #111)); }
|
|
562
|
+
.ksc-rt { display: flex; align-items: center; justify-content: center; gap: 4px;
|
|
563
|
+
padding: 9px 16px; font: inherit; font-size: 0.8125rem; font-weight: 400;
|
|
564
|
+
color: var(--ksc-text, #111);
|
|
565
|
+
background: rgb(215, 254, 218); }
|
|
566
|
+
.ksc-rt__count { font-variant-numeric: tabular-nums; font-weight: 700; }
|
|
554
567
|
.ksc-rt__icon { font-size: 0.95em; line-height: 1; }
|
|
555
568
|
@media (prefers-reduced-motion: reduce) { .ksc-rt { transition: none; } }
|
|
556
569
|
`;
|
|
@@ -563,10 +576,10 @@ var reservationTimer = {
|
|
|
563
576
|
if (minutes === null) return "";
|
|
564
577
|
void readMode(config);
|
|
565
578
|
const seed = formatCountdown(minutes * MS_PER_MINUTE);
|
|
566
|
-
const message = readMessage(config) ?? "Your cart
|
|
579
|
+
const message = readMessage(config) ?? "Your cart will expire in";
|
|
567
580
|
return `<div class="ksc-rt">
|
|
568
581
|
<span>${escapeHtml(message)}</span>
|
|
569
|
-
<span class="ksc-rt__count" data-ksc-countdown data-ksc-end-text="
|
|
582
|
+
<span class="ksc-rt__count" data-ksc-countdown data-ksc-end-text="00:00">${seed}</span>
|
|
570
583
|
<span class="ksc-rt__icon" aria-hidden="true">\u23F0</span>
|
|
571
584
|
</div>`;
|
|
572
585
|
}
|
|
@@ -587,78 +600,121 @@ function readVariantIds(config) {
|
|
|
587
600
|
}
|
|
588
601
|
return [...new Set(ids)];
|
|
589
602
|
}
|
|
603
|
+
function readTitle(config) {
|
|
604
|
+
const raw = config.title;
|
|
605
|
+
return typeof raw === "string" && raw.trim() !== "" ? raw : "You might also like";
|
|
606
|
+
}
|
|
590
607
|
function cartVariantIds(state) {
|
|
591
608
|
if (state === null) return /* @__PURE__ */ new Set();
|
|
592
609
|
const ids = /* @__PURE__ */ new Set();
|
|
593
610
|
for (const line of state.lines) {
|
|
594
611
|
const tag = line.attributes?.[UPSELL_VARIANT_ATTR];
|
|
595
612
|
if (typeof tag === "string") ids.add(tag);
|
|
613
|
+
if (line.variantId !== null && line.variantId !== void 0) ids.add(String(line.variantId));
|
|
596
614
|
}
|
|
597
615
|
return ids;
|
|
598
616
|
}
|
|
617
|
+
var ARROW_LEFT_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 12H5M11 6l-6 6 6 6"/></svg>`;
|
|
618
|
+
var ARROW_RIGHT_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg>`;
|
|
599
619
|
var css3 = `
|
|
600
|
-
.ksc-up { padding:
|
|
601
|
-
.ksc-up__title { margin: 0 0
|
|
602
|
-
|
|
620
|
+
.ksc-up { padding: 14px 6px 16px; font: inherit; color: var(--ksc-text); }
|
|
621
|
+
.ksc-up__title { margin: 0 0 10px; font-size: 0.9375rem; font-weight: 700; text-align: center; }
|
|
622
|
+
.ksc-up__row { display: grid; grid-template-columns: 28px minmax(0, 1fr) 28px; align-items: center; gap: 2px; }
|
|
623
|
+
.ksc-up__arrow { display: flex; align-items: center; justify-content: center; width: 28px; height: 28px;
|
|
624
|
+
padding: 0; border: none; background: none; cursor: pointer; color: rgb(52, 64, 84); border-radius: 8px; }
|
|
625
|
+
.ksc-up__arrow:hover { background: var(--ksc-border); }
|
|
626
|
+
.ksc-up__arrow svg { width: 18px; height: 18px; }
|
|
603
627
|
.ksc-up__track { display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory;
|
|
604
|
-
-webkit-overflow-scrolling: touch;
|
|
605
|
-
.ksc-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
.ksc-
|
|
614
|
-
.ksc-
|
|
615
|
-
.ksc-
|
|
616
|
-
|
|
617
|
-
|
|
628
|
+
scroll-behavior: smooth; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
|
|
629
|
+
.ksc-up__track::-webkit-scrollbar { display: none; }
|
|
630
|
+
.ksc-up__card { scroll-snap-align: start; flex: 0 0 100%; display: grid;
|
|
631
|
+
grid-template-columns: 64px minmax(0, 1fr); gap: 4px 12px; align-items: start;
|
|
632
|
+
border-radius: 12px; padding: 12px; background: rgb(242, 244, 247); box-sizing: border-box; }
|
|
633
|
+
.ksc-up__img { grid-row: 1 / span 4; width: 64px; height: 64px; object-fit: cover; border-radius: 8px;
|
|
634
|
+
background: var(--ksc-surface); }
|
|
635
|
+
.ksc-up__name { font-size: 0.9375rem; font-weight: 700; line-height: 1.25; display: -webkit-box;
|
|
636
|
+
-webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
637
|
+
.ksc-up__prices { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 0.875rem; }
|
|
638
|
+
.ksc-up__price { font-weight: 700; }
|
|
639
|
+
.ksc-up__compare { color: rgb(152, 162, 179); text-decoration: line-through; }
|
|
640
|
+
.ksc-up__save { font-size: 0.75rem; font-weight: 500; color: rgb(7, 148, 85);
|
|
641
|
+
background: rgb(220, 250, 230); padding: 2px 8px; border-radius: 6px; white-space: nowrap; }
|
|
642
|
+
.ksc-up__variant { display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
|
|
643
|
+
font-size: 0.78rem; color: rgb(152, 162, 179); }
|
|
644
|
+
.ksc-up__select { font: inherit; font-size: 0.8125rem; color: var(--ksc-text); padding: 4px 24px 4px 10px;
|
|
645
|
+
border: 1px solid var(--ksc-border); border-radius: 8px; background-color: var(--ksc-surface); cursor: pointer;
|
|
646
|
+
appearance: none; -webkit-appearance: none;
|
|
647
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none' stroke='%23999' stroke-width='1.5'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
|
|
648
|
+
background-repeat: no-repeat; background-position: right 8px center; }
|
|
649
|
+
.ksc-up__add { justify-self: start; margin-top: 6px; padding: 8px 14px; font: inherit; font-size: 0.8125rem;
|
|
650
|
+
font-weight: 600; cursor: pointer; border: none; border-radius: 8px; background: rgb(7, 148, 85);
|
|
651
|
+
color: #fff; transition: opacity .15s ease; }
|
|
618
652
|
.ksc-up__add:hover { opacity: 0.9; }
|
|
619
|
-
.ksc-up__add:focus-visible { outline: 2px solid
|
|
653
|
+
.ksc-up__add:focus-visible { outline: 2px solid rgb(7, 148, 85); outline-offset: 2px; }
|
|
620
654
|
@media (prefers-reduced-motion: reduce) { .ksc-up__track { scroll-behavior: auto; } .ksc-up__add { transition: none; } }
|
|
621
655
|
`;
|
|
622
|
-
function card(variant, currency) {
|
|
656
|
+
function card(variant, currency, siblings) {
|
|
623
657
|
const name = escapeHtml(variant.productTitle);
|
|
624
658
|
const img = variant.imageUrl !== null ? `<img class="ksc-up__img" src="${escapeHtml(variant.imageUrl)}" alt="${escapeHtml(variant.imageAltText ?? "")}" loading="lazy" />` : `<div class="ksc-up__img" role="presentation"></div>`;
|
|
625
|
-
const variantTitle = variant.title !== null && variant.title.trim() !== "" && variant.title !== DEFAULT_VARIANT_TITLE ? `<span class="ksc-up__variant">${escapeHtml(variant.title)}</span>` : "";
|
|
626
659
|
const price = escapeHtml(formatMoney2({ amount: variant.price.amount, currency }));
|
|
627
660
|
const showCompare = variant.compareAtPrice !== null && variant.compareAtPrice.amount > variant.price.amount;
|
|
628
|
-
const
|
|
661
|
+
const compare = showCompare ? `<s class="ksc-up__compare">${escapeHtml(formatMoney2({ amount: variant.compareAtPrice.amount, currency }))}</s>` : "";
|
|
662
|
+
const savePct = showCompare ? Math.round(
|
|
663
|
+
(variant.compareAtPrice.amount - variant.price.amount) / variant.compareAtPrice.amount * 100
|
|
664
|
+
) : 0;
|
|
665
|
+
const save = savePct > 0 ? `<span class="ksc-up__save">You save ${savePct}%</span>` : "";
|
|
666
|
+
const hasMeaningfulTitle = variant.title !== null && variant.title.trim() !== "" && variant.title !== DEFAULT_VARIANT_TITLE;
|
|
667
|
+
const variantHtml = siblings !== void 0 && siblings.length > 1 ? `<span class="ksc-up__variant"><span>Size:</span><select class="ksc-up__select" data-smart-cart-upsell-variant aria-label="Size">${siblings.map(
|
|
668
|
+
(v) => `<option value="${escapeHtml(v.id)}"${v.id === variant.id ? " selected" : ""}>${escapeHtml(v.title ?? "")}</option>`
|
|
669
|
+
).join("")}</select></span>` : hasMeaningfulTitle ? `<span class="ksc-up__variant"><span>Size:</span><span>${escapeHtml(variant.title)}</span></span>` : "";
|
|
629
670
|
return `<div class="ksc-up__card" role="listitem">
|
|
630
671
|
${img}
|
|
631
672
|
<span class="ksc-up__name">${name}</span>
|
|
632
|
-
${
|
|
633
|
-
${
|
|
634
|
-
<button type="button" class="ksc-up__add" data-smart-cart-upsell-add data-variant-id="${escapeHtml(variant.id)}" aria-label="Add ${name} to cart">Add</button>
|
|
673
|
+
<span class="ksc-up__prices"><span class="ksc-up__price">${price}</span>${compare}${save}</span>
|
|
674
|
+
${variantHtml}
|
|
675
|
+
<button type="button" class="ksc-up__add" data-smart-cart-upsell-add data-variant-id="${escapeHtml(variant.id)}" aria-label="Add ${name} to cart">Add to cart</button>
|
|
635
676
|
</div>`;
|
|
636
677
|
}
|
|
637
678
|
var upsellCarousel = {
|
|
638
679
|
key: UPSELL_KEY,
|
|
639
680
|
zone: "after-items",
|
|
640
681
|
css: css3,
|
|
641
|
-
render({ config, state, variants }) {
|
|
682
|
+
render({ config, state, variants, productVariants }) {
|
|
642
683
|
if (variants === void 0 || variants.size === 0) return "";
|
|
643
684
|
const inCart = cartVariantIds(state);
|
|
644
|
-
const cards = readVariantIds(config).filter((id) => !inCart.has(id)).map((id) => variants.get(id)).filter((variant) => variant !== void 0).map(
|
|
685
|
+
const cards = readVariantIds(config).filter((id) => !inCart.has(id)).map((id) => variants.get(id)).filter((variant) => variant !== void 0).map(
|
|
686
|
+
(variant) => card(
|
|
687
|
+
variant,
|
|
688
|
+
state?.currency ?? variant.price.currency,
|
|
689
|
+
variant.productHandle !== null ? productVariants?.get(variant.productHandle) : void 0
|
|
690
|
+
)
|
|
691
|
+
).join("");
|
|
645
692
|
if (cards === "") return "";
|
|
646
693
|
return `<section class="ksc-up" aria-label="Recommended add-ons">
|
|
647
|
-
<p class="ksc-up__title"
|
|
648
|
-
<div class="ksc-
|
|
694
|
+
<p class="ksc-up__title">${escapeHtml(readTitle(config))}</p>
|
|
695
|
+
<div class="ksc-up__row">
|
|
696
|
+
<button type="button" class="ksc-up__arrow" data-smart-cart-upsell-prev aria-label="Previous item">${ARROW_LEFT_SVG}</button>
|
|
697
|
+
<div class="ksc-up__track" role="list">${cards}</div>
|
|
698
|
+
<button type="button" class="ksc-up__arrow" data-smart-cart-upsell-next aria-label="Next item">${ARROW_RIGHT_SVG}</button>
|
|
699
|
+
</div>
|
|
649
700
|
</section>`;
|
|
650
701
|
}
|
|
651
702
|
};
|
|
652
703
|
|
|
653
704
|
// ../smart-cart/src/widgets/discount-code.ts
|
|
654
705
|
var css4 = `
|
|
655
|
-
.ksc-discount { padding:
|
|
656
|
-
.ksc-discount__row { display: flex; gap:
|
|
657
|
-
|
|
658
|
-
.ksc-
|
|
659
|
-
.ksc-
|
|
706
|
+
.ksc-discount { padding: 10px 20px; display: flex; flex-direction: column; gap: 8px; }
|
|
707
|
+
.ksc-discount__row { display: flex; align-items: center; gap: 6px; padding: 5px 5px 5px 14px;
|
|
708
|
+
border: 1px solid rgb(190, 190, 190); border-radius: 10px; background: var(--ksc-surface); }
|
|
709
|
+
.ksc-discount__row:focus-within { border-color: var(--ksc-text); }
|
|
710
|
+
.ksc-discount__input { flex: 1; min-width: 0; padding: 6px 0; border: none; background: none;
|
|
711
|
+
color: var(--ksc-text); font: inherit; font-size: 0.875rem; outline: none; }
|
|
712
|
+
.ksc-discount__apply { padding: 8px 16px; border: none; border-radius: 8px;
|
|
713
|
+
background: rgb(220, 250, 230); color: var(--ksc-text); font: inherit; font-size: 0.875rem;
|
|
714
|
+
font-weight: 500; cursor: pointer; white-space: nowrap; }
|
|
715
|
+
.ksc-discount__apply:hover { filter: brightness(0.97); }
|
|
660
716
|
.ksc-discount__chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
661
|
-
.ksc-discount__chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 8px 3px 10px; background:
|
|
717
|
+
.ksc-discount__chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 8px 3px 10px; background: rgb(242, 244, 247); border-radius: 999px; font-size: 0.8125rem; color: var(--ksc-text); }
|
|
662
718
|
.ksc-discount__chip-remove { display: inline-flex; align-items: center; justify-content: center; background: none; border: none; cursor: pointer; padding: 2px; color: color-mix(in oklab, var(--ksc-text) 60%, transparent); line-height: 1; font-size: 1rem; }
|
|
663
719
|
.ksc-discount__chip-remove:hover { color: var(--ksc-text); }
|
|
664
720
|
`;
|
|
@@ -691,11 +747,26 @@ function readMessage2(config, key) {
|
|
|
691
747
|
const raw = config[key];
|
|
692
748
|
return typeof raw === "string" && raw.trim() !== "" ? raw : null;
|
|
693
749
|
}
|
|
750
|
+
function renderTemplate(template, amount) {
|
|
751
|
+
return template.split(/\{amount\}/g).map((part) => escapeHtml(part)).join(`<b>${escapeHtml(amount)}</b>`);
|
|
752
|
+
}
|
|
753
|
+
var TRUCK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 5h14v11H1zM15 9h4l3 3v4h-7z"/><circle cx="6" cy="18.5" r="1.8"/><circle cx="18" cy="18.5" r="1.8"/></svg>`;
|
|
694
754
|
var css5 = `
|
|
695
|
-
.ksc-fsb { padding:
|
|
696
|
-
.ksc-fsb__msg { margin: 0 0
|
|
697
|
-
.ksc-
|
|
698
|
-
.ksc-
|
|
755
|
+
.ksc-fsb { padding: 14px 20px 10px; font: inherit; color: var(--ksc-text); }
|
|
756
|
+
.ksc-fsb__msg { margin: 0 0 10px; font-size: 0.8125rem; text-align: center; }
|
|
757
|
+
.ksc-fsb__msg b { font-weight: 700; }
|
|
758
|
+
.ksc-fsb__track { position: relative; height: 8px; border-radius: 999px;
|
|
759
|
+
background: rgb(234, 236, 240); }
|
|
760
|
+
.ksc-fsb__fill { height: 100%; border-radius: 999px; background: rgb(29, 41, 57);
|
|
761
|
+
transition: width .3s ease; }
|
|
762
|
+
.ksc-fsb__step { position: absolute; right: -2px; top: 50%; transform: translateY(-50%);
|
|
763
|
+
width: 14px; height: 14px; border-radius: 4px; border: 2px solid rgb(29, 41, 57);
|
|
764
|
+
background: var(--ksc-surface); box-sizing: border-box; }
|
|
765
|
+
.ksc-fsb--unlocked .ksc-fsb__step { background: rgb(29, 41, 57); }
|
|
766
|
+
.ksc-fsb__tier { display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
|
|
767
|
+
margin-top: 6px; font-size: 0.78rem; color: rgb(152, 162, 179); }
|
|
768
|
+
.ksc-fsb__tier svg { width: 20px; height: 20px; }
|
|
769
|
+
.ksc-fsb--unlocked .ksc-fsb__tier { color: rgb(29, 41, 57); }
|
|
699
770
|
@media (prefers-reduced-motion: reduce) { .ksc-fsb__fill { transition: none; } }
|
|
700
771
|
`;
|
|
701
772
|
var freeShippingBar = {
|
|
@@ -705,20 +776,22 @@ var freeShippingBar = {
|
|
|
705
776
|
render({ config, state }) {
|
|
706
777
|
const threshold = readThreshold(config);
|
|
707
778
|
if (threshold === null || state === null) return "";
|
|
708
|
-
const
|
|
779
|
+
const discountTotal = state.discountTotal?.amount ?? 0;
|
|
780
|
+
const subtotal = Math.max(0, state.subtotal.amount - discountTotal);
|
|
709
781
|
const remaining = Math.max(0, threshold - subtotal);
|
|
710
782
|
const unlocked = remaining === 0;
|
|
711
783
|
const pct = Math.min(100, Math.round(subtotal / threshold * 100));
|
|
712
|
-
const remainingMoney =
|
|
784
|
+
const remainingMoney = formatMoneyCompact({
|
|
785
|
+
amount: remaining,
|
|
786
|
+
currency: state.subtotal.currency
|
|
787
|
+
});
|
|
713
788
|
const beforeTemplate = readMessage2(config, "messageBefore");
|
|
714
789
|
const afterTemplate = readMessage2(config, "messageAfter");
|
|
715
|
-
const message = unlocked ? afterTemplate
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
<p class="ksc-fsb__msg">${escapeHtml(message)}</p>
|
|
721
|
-
<div class="ksc-fsb__track"><div class="ksc-fsb__fill" style="width: ${pct}%"></div></div>
|
|
790
|
+
const message = unlocked ? afterTemplate !== null ? renderTemplate(afterTemplate, remainingMoney) : `<b>Free shipping</b> unlocked!` : beforeTemplate !== null ? renderTemplate(beforeTemplate, remainingMoney) : `Add <b>${escapeHtml(remainingMoney)}</b> to unlock <b>Free shipping</b>!`;
|
|
791
|
+
return `<div class="ksc-fsb${unlocked ? " ksc-fsb--unlocked" : ""}">
|
|
792
|
+
<p class="ksc-fsb__msg">${message}</p>
|
|
793
|
+
<div class="ksc-fsb__track"><div class="ksc-fsb__fill" style="width: ${pct}%"></div><span class="ksc-fsb__step" aria-hidden="true"></span></div>
|
|
794
|
+
<div class="ksc-fsb__tier">${TRUCK_SVG}<span>${unlocked ? "" : "\u{1F512} "}Free shipping</span></div>
|
|
722
795
|
</div>`;
|
|
723
796
|
}
|
|
724
797
|
};
|
|
@@ -885,6 +958,23 @@ var PAYMENT_ICON_SVGS = {
|
|
|
885
958
|
<path d="M228.897012,82.7490197 C216.569147,146.069792 174.366398,167.970272 120.46841,167.970272 L93.0241367,167.970272 C86.4398419,167.970272 80.8794007,172.764903 79.8555471,179.265958 L61.8174095,293.621258 C61.1431644,297.883153 64.4394738,301.745495 68.7513129,301.745495 L117.421821,301.745495 C123.182038,301.745495 128.084882,297.550192 128.983876,291.864891 L129.458344,289.384335 L138.631407,231.249423 L139.222412,228.036354 C140.121406,222.351053 145.02425,218.15575 150.784467,218.15575 L158.067979,218.15575 C205.215193,218.15575 242.132193,199.002194 252.920115,143.605884 C257.423406,120.456802 255.092683,101.128442 243.181019,87.5519756 C239.568397,83.4399129 235.081754,80.0437153 229.854273,77.2718188 C229.571257,79.0614817 229.263268,80.8761167 228.897012,82.7490197 L228.897012,82.7490197 Z" fill="#2790C3"></path>
|
|
886
959
|
<path d="M216.952052,72.1275783 C215.070825,71.5781934 213.13133,71.0787526 211.133566,70.6375799 C209.135803,70.1964071 207.071448,69.8051785 204.957148,69.4638939 C197.548776,68.265236 189.457835,67.699203 180.767565,67.699203 L107.457976,67.699203 C105.651665,67.699203 103.936919,68.1070797 102.4053,68.8479169 C99.0174265,70.4710996 96.5118984,73.6675208 95.8959214,77.5881313 L80.3133678,176.385849 L79.8638711,179.265958 C80.8877248,172.764903 86.4481659,167.970272 93.0324607,167.970272 L120.476734,167.970272 C174.374722,167.970272 216.577471,146.078116 228.905336,82.7490197 C229.271592,80.8761167 229.579581,79.0614817 229.862597,77.2718188 C226.741092,75.623664 223.361542,74.2002577 219.723948,72.9932757 C218.816631,72.6936112 217.892665,72.4022708 216.952052,72.1275783" fill="#1F264F"></path>
|
|
887
960
|
</g>
|
|
961
|
+
</svg>`,
|
|
962
|
+
"apple-pay": `<svg width="512px" height="211px" viewBox="0 0 512 211" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
|
963
|
+
<g>
|
|
964
|
+
<path d="M93.5520633,27.1031049 C87.5513758,34.2039183 77.9502759,39.8045599 68.349176,39.0044683 C67.1490386,29.4033684 71.849577,19.2021998 77.3502072,12.901478 C83.3508946,5.6006416 93.8520976,0.400045829 102.353071,0 C103.353186,10.0011457 99.4527392,19.8022685 93.5520633,27.1031049 Z M102.25306,40.904686 C88.3514675,40.1045943 76.4501041,48.8055911 69.8493479,48.8055911 C63.1485803,48.8055911 53.0474231,41.3047318 42.0461628,41.5047547 C27.7445244,41.7047776 14.4430006,49.8057057 7.14216427,62.7071836 C-7.8595543,88.5101396 3.24171744,126.714516 17.7433787,147.716922 C24.8441922,158.118114 33.345166,169.51942 44.5464492,169.119374 C55.1476637,168.719328 59.3481449,162.218584 72.1496114,162.218584 C85.0510894,162.218584 88.7515133,169.119374 99.9527965,168.919351 C111.554126,168.719328 118.854962,158.51816 125.955775,148.116968 C134.056703,136.315616 137.357081,124.814299 137.557104,124.21423 C137.357081,124.014207 115.154538,115.513233 114.954515,89.9103 C114.754492,68.5078482 132.45652,58.3066795 133.256612,57.7066108 C123.255466,42.9049151 107.653679,41.3047318 102.25306,40.904686 Z M182.56226,11.9013634 L182.56226,167.819225 L206.765033,167.819225 L206.765033,114.513118 L240.268871,114.513118 C270.872377,114.513118 292.37484,93.5107124 292.37484,63.1072295 C292.37484,32.7037465 271.272423,11.9013634 241.068963,11.9013634 L182.56226,11.9013634 Z M206.765033,32.3037007 L234.668229,32.3037007 C255.670635,32.3037007 267.67201,43.5049839 267.67201,63.2072409 C267.67201,82.909498 255.670635,94.2107926 234.568218,94.2107926 L206.765033,94.2107926 L206.765033,32.3037007 Z M336.579904,169.019363 C351.781646,169.019363 365.883261,161.31848 372.283994,149.117083 L372.784052,149.117083 L372.784052,167.819225 L395.186618,167.819225 L395.186618,90.2103344 C395.186618,67.7077565 377.184556,53.2060952 349.481382,53.2060952 C323.778438,53.2060952 304.776261,67.9077794 304.076181,88.1100938 L325.878678,88.1100938 C327.678884,78.5089939 336.579904,72.2082721 348.781302,72.2082721 C363.582998,72.2082721 371.883949,79.1090626 371.883949,91.8105177 L371.883949,100.411503 L341.680488,102.211709 C313.577269,103.911904 298.375528,115.413222 298.375528,135.415513 C298.375528,155.617827 314.077326,169.019363 336.579904,169.019363 Z M343.080649,150.517243 C330.179171,150.517243 321.978231,144.316533 321.978231,134.815444 C321.978231,125.014321 329.879137,119.313668 344.980867,118.413565 L371.883949,116.713371 L371.883949,125.514379 C371.883949,140.116051 359.482528,150.517243 343.080649,150.517243 Z M425.090044,210.224083 C448.692748,210.224083 459.794019,201.223052 469.495131,173.919924 L512,54.7062671 L487.397182,54.7062671 L458.893916,146.816819 L458.393859,146.816819 L429.890594,54.7062671 L404.587695,54.7062671 L445.592392,168.219271 L443.39214,175.120061 C439.691716,186.821402 433.691029,191.321918 422.989803,191.321918 C421.089585,191.321918 417.389162,191.121895 415.88899,190.921872 L415.88899,209.624014 C417.28915,210.02406 423.289838,210.224083 425.090044,210.224083 Z" fill="#000000"></path>
|
|
965
|
+
</g>
|
|
966
|
+
</svg>`,
|
|
967
|
+
"google-pay": `<svg width="512px" height="204px" viewBox="0 0 512 204" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
|
968
|
+
<title>Google Pay</title>
|
|
969
|
+
<g>
|
|
970
|
+
<path d="M362.926585,55.0572275 C377.002187,55.0572275 387.878788,58.8960279 396.196189,66.5736286 C404.51359,74.2512294 408.35239,84.4880304 408.35239,97.2840316 L408.35239,158.704838 L390.437988,158.704838 L390.437988,144.629236 L389.798188,144.629236 C382.120587,156.145637 371.243986,161.903838 358.447985,161.903838 C347.571384,161.903838 337.974383,158.704838 330.296782,152.306837 C323.258982,145.908836 318.780381,136.951636 318.780381,127.354635 C318.780381,117.117834 322.619182,108.800433 330.296782,102.402432 C337.974383,96.0044315 348.850984,93.4452313 361.646985,93.4452313 C373.163386,93.4452313 382.120587,95.3646315 389.158388,99.8432319 L389.158388,95.3646315 C389.158388,89.3931642 386.92904,83.421697 382.470345,79.5309543 L381.480787,78.7298298 C376.362387,74.2512294 369.964386,71.6920291 362.926585,71.6920291 C352.049984,71.6920291 343.732584,76.1706296 337.974383,85.1278305 L321.339581,74.8910295 C331.576382,61.4552281 345.012184,55.0572275 362.926585,55.0572275 Z M272.714777,11.5508233 C284.195633,11.5508233 295.105804,15.5456243 303.828346,22.9962452 L305.34458,24.3468245 C314.301781,32.0244253 318.780381,43.5408264 318.780381,55.6970276 C318.780381,67.8532288 314.301781,78.7298298 305.34458,87.0472306 C296.387379,95.3646315 285.510778,99.8432319 272.714777,99.8432319 L242.004374,99.2034318 L242.004374,158.704838 L222.810372,158.704838 L222.810372,11.5508233 L272.714777,11.5508233 Z M365.485786,108.800433 C357.808185,108.800433 351.410184,110.719833 346.291784,114.558633 C341.173383,117.757634 338.614183,122.236234 338.614183,127.994435 C338.614183,133.112835 341.173383,137.591436 345.012184,140.150636 C349.490784,143.349636 354.609185,145.269036 359.727585,145.269036 C366.893346,145.269036 374.059107,142.482352 379.664324,137.429163 L380.840987,136.311835 C387.238988,130.553635 390.437988,123.515834 390.437988,115.838233 C384.679788,111.359633 376.362387,108.800433 365.485786,108.800433 Z M273.994377,29.465225 L242.004374,29.465225 L242.004374,80.64923 L273.994377,80.64923 C281.032177,80.64923 288.069978,78.0900298 292.548579,72.9716293 C302.78538,63.3746283 302.78538,47.3796268 293.188379,37.7826258 L292.548579,37.1428258 C287.430178,32.0244253 281.032177,28.825425 273.994377,29.465225 Z M512,58.2562278 L448.659794,203.490842 L429.465792,203.490842 L453.138394,152.946637 L411.55139,58.8960279 L432.024992,58.8960279 L462.095595,131.193435 L462.735395,131.193435 L492.166198,58.8960279 L512,58.8960279 L512,58.2562278 Z" fill="#5F6368"></path>
|
|
971
|
+
<g>
|
|
972
|
+
<path d="M165.868166,86.4074306 C165.868166,80.64923 165.228366,74.8910295 164.588566,69.1328289 L84.6135583,69.1328289 L84.6135583,101.762632 L130.039363,101.762632 C128.119963,111.999433 122.361762,121.596434 113.404561,127.354635 L113.404561,148.468037 L140.915964,148.468037 C156.910965,133.752635 165.868166,111.999433 165.868166,86.4074306 Z" fill="#4285F4"></path>
|
|
973
|
+
<path d="M84.6135583,168.941639 C107.646361,168.941639 126.840362,161.264038 140.915964,148.468037 L113.404561,127.354635 C105.72696,132.473035 96.1299594,135.672035 84.6135583,135.672035 C62.8603561,135.672035 43.6663543,120.956634 37.2683536,100.483032 L9.11715089,100.483032 L9.11715089,122.236234 C23.8325523,151.027237 52.6235551,168.941639 84.6135583,168.941639 Z" fill="#34A853"></path>
|
|
974
|
+
<path d="M37.2683536,100.483032 C33.4295533,90.246231 33.4295533,78.7298298 37.2683536,67.8532288 L37.2683536,46.1000266 L9.11715089,46.1000266 C-3.0390503,69.772629 -3.0390503,97.9238317 9.11715089,122.236234 L37.2683536,100.483032 Z" fill="#FBBC04"></path>
|
|
975
|
+
<path d="M84.6135583,33.3040254 C96.7697595,33.3040254 108.286161,37.7826258 117.243361,46.1000266 L117.243361,46.1000266 L141.555764,21.7876243 C126.200562,7.71202289 105.72696,-0.60537792 85.2533583,0.0344221425 C53.2633552,0.0344221425 23.8325523,17.9488239 9.75695095,46.7398267 L37.9081537,68.4930288 C43.6663543,48.0194268 62.8603561,33.3040254 84.6135583,33.3040254 Z" fill="#EA4335"></path>
|
|
976
|
+
</g>
|
|
977
|
+
</g>
|
|
888
978
|
</svg>`
|
|
889
979
|
};
|
|
890
980
|
|
|
@@ -905,10 +995,11 @@ function readBadges(config) {
|
|
|
905
995
|
return valid.length > 0 ? valid : null;
|
|
906
996
|
}
|
|
907
997
|
var css7 = `
|
|
908
|
-
.ksc-tb { display: flex; flex-wrap: wrap; gap:
|
|
998
|
+
.ksc-tb { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: center;
|
|
909
999
|
padding: 10px 16px 4px; }
|
|
910
|
-
.ksc-tb__icon { display: flex; align-items: center;
|
|
911
|
-
|
|
1000
|
+
.ksc-tb__icon { display: flex; align-items: center; justify-content: center; width: 38px; height: 26px;
|
|
1001
|
+
border: 1px solid rgb(234, 236, 240); border-radius: 5px; background: #fff; box-sizing: border-box; }
|
|
1002
|
+
.ksc-tb__icon svg { max-height: 15px; max-width: 28px; width: auto; height: auto; display: block; }
|
|
912
1003
|
`;
|
|
913
1004
|
var trustBadges = {
|
|
914
1005
|
key: "trustBadges",
|
|
@@ -956,7 +1047,7 @@ var STYLES2 = `
|
|
|
956
1047
|
--ksc-border: color-mix(in oklab, var(--ksc-text) 12%, transparent); }
|
|
957
1048
|
.overlay { position: absolute; inset: 0; background: rgba(0,0,0,.45); opacity: 0;
|
|
958
1049
|
transition: opacity .25s ease; }
|
|
959
|
-
.panel { position: absolute; top: 0; right: 0; height: 100%; width: min(
|
|
1050
|
+
.panel { position: absolute; top: 0; right: 0; height: 100%; width: min(520px, 100vw);
|
|
960
1051
|
background: var(--ksc-surface); color: var(--ksc-text); font-family: var(--ksc-font);
|
|
961
1052
|
transform: translateX(100%); transition: transform .25s ease; display: flex; flex-direction: column;
|
|
962
1053
|
box-shadow: -8px 0 40px rgba(0,0,0,.14); }
|
|
@@ -965,12 +1056,13 @@ var STYLES2 = `
|
|
|
965
1056
|
:host(:not([open])) { pointer-events: none; }
|
|
966
1057
|
:host([open]) { pointer-events: auto; }
|
|
967
1058
|
|
|
968
|
-
/* Header */
|
|
969
|
-
.ksc-head { display: flex; align-items: center;
|
|
970
|
-
|
|
971
|
-
.ksc-head__title { font-size:
|
|
972
|
-
.ksc-head__count {
|
|
973
|
-
.ksc-head__close {
|
|
1059
|
+
/* Header \u2014 centered "My cart \xB7 N" with the close control pinned right (original cart layout). */
|
|
1060
|
+
.ksc-head { position: relative; display: flex; align-items: center; justify-content: center;
|
|
1061
|
+
gap: 6px; flex: 0 0 auto; padding: 16px 52px; }
|
|
1062
|
+
.ksc-head__title { font-size: 1.125rem; font-weight: 600; letter-spacing: .01em; }
|
|
1063
|
+
.ksc-head__count { font-weight: 600; font-size: 1.125rem; }
|
|
1064
|
+
.ksc-head__close { position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
|
|
1065
|
+
display: flex; align-items: center; justify-content: center;
|
|
974
1066
|
width: 32px; height: 32px; padding: 0; border: none; background: none; cursor: pointer;
|
|
975
1067
|
color: var(--ksc-text); border-radius: 8px; }
|
|
976
1068
|
.ksc-head__close:hover { background: var(--ksc-border); }
|
|
@@ -982,61 +1074,66 @@ var STYLES2 = `
|
|
|
982
1074
|
gap: 14px; padding: 56px 24px; text-align: center; color: var(--ksc-muted); }
|
|
983
1075
|
.ksc-empty svg { width: 44px; height: 44px; opacity: .5; }
|
|
984
1076
|
.ksc-empty p { margin: 0; font-size: .95rem; }
|
|
985
|
-
.ksc-line { display: grid; grid-template-columns:
|
|
986
|
-
padding:
|
|
987
|
-
.ksc-
|
|
1077
|
+
.ksc-line { display: grid; grid-template-columns: 80px 1fr; gap: 14px;
|
|
1078
|
+
padding: 14px 20px; }
|
|
1079
|
+
.ksc-line + .ksc-line { border-top: 1px solid var(--ksc-border); }
|
|
1080
|
+
.ksc-line__img { width: 80px; height: 80px; object-fit: cover; border-radius: 8px;
|
|
988
1081
|
background: var(--ksc-border); }
|
|
989
1082
|
.ksc-line__img--ph { display: block; }
|
|
990
|
-
.ksc-line__body { display: flex; flex-direction: column; gap:
|
|
991
|
-
.ksc-line__top { display: flex; align-items: flex-start; justify-content: space-between; gap:
|
|
992
|
-
.ksc-
|
|
993
|
-
.ksc-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
.ksc-
|
|
1083
|
+
.ksc-line__body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
1084
|
+
.ksc-line__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
|
|
1085
|
+
.ksc-line__main { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
|
|
1086
|
+
.ksc-line__title { font-size: .9375rem; font-weight: 700; line-height: 1.3; }
|
|
1087
|
+
.ksc-line__compare { color: rgb(152, 162, 179); text-decoration: line-through;
|
|
1088
|
+
font-size: .875rem; white-space: nowrap; }
|
|
1089
|
+
.ksc-line__meta { display: flex; flex-direction: column; gap: 3px; }
|
|
1090
|
+
.ksc-line__opt { font-size: .8125rem; color: rgb(152, 162, 179); line-height: 1.35;
|
|
997
1091
|
overflow: hidden; text-overflow: ellipsis; }
|
|
998
|
-
.ksc-line__opt b { font-weight:
|
|
999
|
-
.ksc-line__variant { display: flex;
|
|
1000
|
-
|
|
1092
|
+
.ksc-line__opt b { font-weight: 700; color: var(--ksc-text); }
|
|
1093
|
+
.ksc-line__variant { display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
|
|
1094
|
+
font-size: .8125rem; color: rgb(152, 162, 179); }
|
|
1095
|
+
.ksc-line__discount { font-size: .8125rem; font-weight: 500; color: var(--ksc-positive); line-height: 1.35; }
|
|
1096
|
+
.ksc-line__discount s { color: rgb(152, 162, 179); text-decoration: line-through; }
|
|
1097
|
+
.ksc-line__select { font: inherit; font-size: .8125rem; color: var(--ksc-text); padding: 4px 24px 4px 10px;
|
|
1001
1098
|
border: 1px solid var(--ksc-border); border-radius: 8px; background: var(--ksc-surface); cursor: pointer;
|
|
1002
1099
|
appearance: none; -webkit-appearance: none;
|
|
1003
1100
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none' stroke='%23999' stroke-width='1.5'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
|
|
1004
1101
|
background-repeat: no-repeat; background-position: right 8px center; }
|
|
1005
1102
|
.ksc-line__select:focus { outline: none; border-color: var(--ksc-accent); }
|
|
1006
1103
|
.ksc-line__bottom { display: flex; align-items: center; justify-content: space-between;
|
|
1007
|
-
gap: 10px; margin-top:
|
|
1104
|
+
gap: 10px; margin-top: 4px; }
|
|
1008
1105
|
.ksc-qty { display: inline-flex; align-items: center; border: 1px solid var(--ksc-border);
|
|
1009
|
-
border-radius:
|
|
1010
|
-
.ksc-qty button { width:
|
|
1106
|
+
border-radius: 8px; }
|
|
1107
|
+
.ksc-qty button { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
|
|
1011
1108
|
padding: 0; border: none; background: none; cursor: pointer; color: var(--ksc-text);
|
|
1012
|
-
font-size: 16px; line-height: 1; border-radius:
|
|
1109
|
+
font-size: 16px; line-height: 1; border-radius: 8px; }
|
|
1013
1110
|
.ksc-qty button:hover { background: var(--ksc-border); }
|
|
1014
|
-
.ksc-qty__n { min-width:
|
|
1015
|
-
.ksc-
|
|
1016
|
-
.ksc-
|
|
1017
|
-
.ksc-
|
|
1018
|
-
|
|
1019
|
-
background:
|
|
1020
|
-
.ksc-
|
|
1111
|
+
.ksc-qty__n { min-width: 26px; text-align: center; font-size: .875rem; font-variant-numeric: tabular-nums; }
|
|
1112
|
+
.ksc-line__prices { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; flex: 0 0 auto; }
|
|
1113
|
+
.ksc-line__price { font-size: .9375rem; font-weight: 700; }
|
|
1114
|
+
.ksc-line__save { display: inline-flex; align-items: center; gap: 4px; font-size: .75rem;
|
|
1115
|
+
font-weight: 500; color: rgb(7, 148, 85); white-space: nowrap;
|
|
1116
|
+
background: rgb(220, 250, 230); padding: 3px 8px; border-radius: 6px; }
|
|
1117
|
+
.ksc-line__save svg { width: 12px; height: 12px; }
|
|
1118
|
+
.ksc-line__remove { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px;
|
|
1021
1119
|
padding: 0; border: none; background: none; cursor: pointer; color: var(--ksc-muted); border-radius: 8px; }
|
|
1022
1120
|
.ksc-line__remove:hover { color: var(--ksc-text); background: var(--ksc-border); }
|
|
1023
|
-
.ksc-line__remove svg { width:
|
|
1121
|
+
.ksc-line__remove svg { width: 17px; height: 17px; }
|
|
1024
1122
|
|
|
1025
1123
|
/* Footer / summary / checkout */
|
|
1026
1124
|
.footer { flex: 0 0 auto; border-top: 1px solid var(--ksc-border); }
|
|
1027
|
-
.ksc-summary { display: flex; flex-direction: column; gap:
|
|
1125
|
+
.ksc-summary { display: flex; flex-direction: column; gap: 6px; padding: 12px 20px 2px; }
|
|
1028
1126
|
.ksc-summary__row { display: flex; align-items: center; justify-content: space-between;
|
|
1029
|
-
font-size: .
|
|
1030
|
-
.ksc-summary__row--
|
|
1031
|
-
.
|
|
1032
|
-
.checkout { display: block; text-align: center; margin: 8px 18px 0; padding: 15px;
|
|
1127
|
+
font-size: .875rem; color: rgb(71, 84, 103); }
|
|
1128
|
+
.ksc-summary__row--total { font-size: 1rem; font-weight: 700; color: var(--ksc-text); }
|
|
1129
|
+
.checkout { display: block; text-align: center; margin: 10px 20px 0; padding: 16px;
|
|
1033
1130
|
background: var(--ksc-accent); color: var(--ksc-accent-text); text-decoration: none;
|
|
1034
|
-
border-radius:
|
|
1131
|
+
border-radius: 10px; font-weight: 700; font-size: 1rem; }
|
|
1035
1132
|
.checkout:hover { opacity: .92; }
|
|
1036
1133
|
.ksc-continue { display: block; width: 100%; padding: 8px 18px 16px; text-align: center;
|
|
1037
|
-
border: none; background: none; cursor: pointer; color: var(--ksc-
|
|
1038
|
-
font-size: .
|
|
1039
|
-
.ksc-continue:hover {
|
|
1134
|
+
border: none; background: none; cursor: pointer; color: var(--ksc-text); font: inherit;
|
|
1135
|
+
font-size: .875rem; font-weight: 700; }
|
|
1136
|
+
.ksc-continue:hover { opacity: .7; }
|
|
1040
1137
|
|
|
1041
1138
|
@media (prefers-reduced-motion: reduce) { .overlay, .panel { transition: none; } }
|
|
1042
1139
|
.chrome { position: absolute; inset: 0; pointer-events: none; }
|
|
@@ -1046,6 +1143,7 @@ var STYLES2 = `
|
|
|
1046
1143
|
var CLOSE_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg>`;
|
|
1047
1144
|
var TRASH_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M7 7l1 13h8l1-13"/></svg>`;
|
|
1048
1145
|
var BAG_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8h12l1 12H5L6 8zM9 8a3 3 0 0 1 6 0"/></svg>`;
|
|
1146
|
+
var TAG_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 13l-7 7-9-9V4h7l9 9z"/><circle cx="7.5" cy="7.5" r="1" fill="currentColor"/></svg>`;
|
|
1049
1147
|
var Base = typeof HTMLElement !== "undefined" ? HTMLElement : class {
|
|
1050
1148
|
};
|
|
1051
1149
|
var SmartCartElement = class _SmartCartElement extends Base {
|
|
@@ -1139,6 +1237,13 @@ var SmartCartElement = class _SmartCartElement extends Base {
|
|
|
1139
1237
|
}
|
|
1140
1238
|
const upsellBtn = target?.closest("[data-smart-cart-upsell-add]");
|
|
1141
1239
|
if (upsellBtn) void this.#onUpsellAdd(upsellBtn);
|
|
1240
|
+
const upsellNav = target?.closest(
|
|
1241
|
+
"[data-smart-cart-upsell-prev], [data-smart-cart-upsell-next]"
|
|
1242
|
+
);
|
|
1243
|
+
if (upsellNav) {
|
|
1244
|
+
this.#onUpsellNav(upsellNav);
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1142
1247
|
const discountApply = target?.closest("[data-smart-cart-discount-apply]");
|
|
1143
1248
|
if (discountApply) {
|
|
1144
1249
|
void this.#onDiscountApply(discountApply);
|
|
@@ -1149,7 +1254,12 @@ var SmartCartElement = class _SmartCartElement extends Base {
|
|
|
1149
1254
|
});
|
|
1150
1255
|
this.#root.querySelector(".panel")?.addEventListener("change", (e) => {
|
|
1151
1256
|
const select = e.target?.closest("[data-smart-cart-variant]");
|
|
1152
|
-
if (select)
|
|
1257
|
+
if (select) {
|
|
1258
|
+
void this.#onVariantSelect(select);
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
const upsellSelect = e.target?.closest("[data-smart-cart-upsell-variant]");
|
|
1262
|
+
if (upsellSelect) this.#onUpsellVariantSelect(upsellSelect);
|
|
1153
1263
|
});
|
|
1154
1264
|
}
|
|
1155
1265
|
connectedCallback() {
|
|
@@ -1194,8 +1304,7 @@ var SmartCartElement = class _SmartCartElement extends Base {
|
|
|
1194
1304
|
this.#renderCart(state);
|
|
1195
1305
|
this.#renderChrome(state);
|
|
1196
1306
|
}
|
|
1197
|
-
void this.#resolveUpsellVariants();
|
|
1198
|
-
void this.#resolveProductVariants();
|
|
1307
|
+
void this.#resolveUpsellVariants().then(() => this.#resolveProductVariants());
|
|
1199
1308
|
}
|
|
1200
1309
|
/** Add a line (from a theme add-to-cart submit intercepted by mountSmartCart) and open the drawer on
|
|
1201
1310
|
* the result. Opens first for instant feedback, then adds and reconciles against the server cart.
|
|
@@ -1217,8 +1326,9 @@ var SmartCartElement = class _SmartCartElement extends Base {
|
|
|
1217
1326
|
}
|
|
1218
1327
|
}
|
|
1219
1328
|
/** Lazily fetch sibling variants for every cart line that has a product handle and a real variant
|
|
1220
|
-
* title (single-variant lines have none → no switcher)
|
|
1221
|
-
*
|
|
1329
|
+
* title (single-variant lines have none → no switcher), plus every resolved upsell/add-on
|
|
1330
|
+
* product (the upsell card's size select). Caches per handle, never re-fetches, and re-renders
|
|
1331
|
+
* the cart once new variants land so the `<select>`s appear. Fail-closed per the lookup. */
|
|
1222
1332
|
async #resolveProductVariants() {
|
|
1223
1333
|
const lookup = this.#variantLookup;
|
|
1224
1334
|
if (!lookup?.fetchProductVariants || this.#lastState === null) return;
|
|
@@ -1229,6 +1339,12 @@ var SmartCartElement = class _SmartCartElement extends Base {
|
|
|
1229
1339
|
handles.add(handle);
|
|
1230
1340
|
}
|
|
1231
1341
|
}
|
|
1342
|
+
for (const variant of this.#upsellVariants?.values() ?? []) {
|
|
1343
|
+
const handle = variant.productHandle;
|
|
1344
|
+
if (handle !== null && handle.length > 0 && !this.#productVariants.has(handle) && !this.#productVariantsFetching.has(handle)) {
|
|
1345
|
+
handles.add(handle);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1232
1348
|
if (handles.size === 0) return;
|
|
1233
1349
|
await Promise.all(
|
|
1234
1350
|
[...handles].map(async (handle) => {
|
|
@@ -1373,6 +1489,20 @@ var SmartCartElement = class _SmartCartElement extends Base {
|
|
|
1373
1489
|
this.#addOnPending = false;
|
|
1374
1490
|
}
|
|
1375
1491
|
}
|
|
1492
|
+
/** Scroll the upsell track one card left/right (the arrows sit outside the track). */
|
|
1493
|
+
#onUpsellNav(btn) {
|
|
1494
|
+
const track = btn.closest(".ksc-up")?.querySelector(".ksc-up__track");
|
|
1495
|
+
if (!track) return;
|
|
1496
|
+
const direction = btn.hasAttribute("data-smart-cart-upsell-prev") ? -1 : 1;
|
|
1497
|
+
track.scrollBy({ left: direction * track.clientWidth, behavior: "smooth" });
|
|
1498
|
+
}
|
|
1499
|
+
/** Retarget an upsell card's add button when the shopper picks a different size — the select
|
|
1500
|
+
* carries no other intent (no re-render, no network). */
|
|
1501
|
+
#onUpsellVariantSelect(select) {
|
|
1502
|
+
if (!(select instanceof HTMLSelectElement)) return;
|
|
1503
|
+
const addBtn = select.closest(".ksc-up__card")?.querySelector("[data-smart-cart-upsell-add]");
|
|
1504
|
+
if (addBtn && select.value) addBtn.setAttribute("data-variant-id", select.value);
|
|
1505
|
+
}
|
|
1376
1506
|
async #onUpsellAdd(btn) {
|
|
1377
1507
|
if (!this.#adapter || this.#upsellPending) return;
|
|
1378
1508
|
const variantId = btn.getAttribute("data-variant-id");
|
|
@@ -1548,7 +1678,8 @@ ${css8}`);
|
|
|
1548
1678
|
config: cfg,
|
|
1549
1679
|
state,
|
|
1550
1680
|
formatMoney: formatMoney2,
|
|
1551
|
-
...this.#upsellVariants !== null && { variants: this.#upsellVariants }
|
|
1681
|
+
...this.#upsellVariants !== null && { variants: this.#upsellVariants },
|
|
1682
|
+
...this.#productVariants.size > 0 && { productVariants: this.#productVariants }
|
|
1552
1683
|
});
|
|
1553
1684
|
} catch (err) {
|
|
1554
1685
|
console.error(`[kotao-smart-cart] widget render failed`, widget.key, err);
|
|
@@ -1606,44 +1737,59 @@ ${css8}`);
|
|
|
1606
1737
|
const hasSwitcher = variants !== void 0 && variants.length > 1;
|
|
1607
1738
|
const optName = l.options?.[0]?.name ?? "";
|
|
1608
1739
|
const propLines = (l.properties ?? []).map(
|
|
1609
|
-
(p) => `<span class="ksc-line__opt"
|
|
1740
|
+
(p) => `<span class="ksc-line__opt">${escapeHtml(p.name)}: <b>${escapeHtml(p.value)}</b></span>`
|
|
1610
1741
|
);
|
|
1611
1742
|
const optLines = hasSwitcher ? [] : opts.map(
|
|
1612
|
-
(o) => o.name ? `<span class="ksc-line__opt"
|
|
1743
|
+
(o) => o.name ? `<span class="ksc-line__opt">${escapeHtml(o.name)}: <b>${escapeHtml(o.value)}</b></span>` : `<span class="ksc-line__opt">${escapeHtml(o.value)}</span>`
|
|
1613
1744
|
);
|
|
1614
|
-
const switcher = hasSwitcher ? `<div class="ksc-line__variant">${optName ? `<span
|
|
1745
|
+
const switcher = hasSwitcher ? `<div class="ksc-line__variant">${optName ? `<span>${escapeHtml(optName)}:</span>` : ""}<select class="ksc-line__select" data-smart-cart-variant data-line-id="${id}" data-qty="${l.quantity}" aria-label="${escapeHtml(optName || "Variant")}">${variants.map(
|
|
1615
1746
|
(v) => `<option value="${escapeHtml(v.id)}"${v.title === l.variantTitle ? " selected" : ""}>${escapeHtml(v.title ?? "")}</option>`
|
|
1616
1747
|
).join("")}</select></div>` : "";
|
|
1617
1748
|
const metaParts = [...propLines, ...optLines, ...switcher ? [switcher] : []];
|
|
1618
1749
|
const meta = metaParts.length ? `<div class="ksc-line__meta">${metaParts.join("")}</div>` : "";
|
|
1619
|
-
const
|
|
1620
|
-
const
|
|
1621
|
-
|
|
1622
|
-
|
|
1750
|
+
const hasLineDiscount = (l.discountAllocations?.length ?? 0) > 0;
|
|
1751
|
+
const struck = l.compareAtLinePrice && l.compareAtLinePrice.amount > l.linePrice.amount ? l.compareAtLinePrice : hasLineDiscount && l.originalLinePrice && l.originalLinePrice.amount > l.linePrice.amount ? l.originalLinePrice : void 0;
|
|
1752
|
+
const compare = struck ? `<span class="ksc-line__compare">${escapeHtml(formatMoney2(struck))}</span>` : "";
|
|
1753
|
+
const save = struck && struck.amount - l.linePrice.amount > 0 ? `<span class="ksc-line__save">${TAG_SVG}You save ${escapeHtml(
|
|
1754
|
+
formatMoneyCompact({
|
|
1755
|
+
amount: struck.amount - l.linePrice.amount,
|
|
1623
1756
|
currency: l.linePrice.currency
|
|
1624
1757
|
})
|
|
1625
1758
|
)}</span>` : "";
|
|
1759
|
+
const displayPrice = l.linePrice;
|
|
1760
|
+
const discountRows = hasLineDiscount ? l.discountAllocations.map((a) => {
|
|
1761
|
+
const code = escapeHtml(a.code);
|
|
1762
|
+
if (typeof a.quantity === "number" && a.quantity > 0) {
|
|
1763
|
+
const unit = Math.round((l.originalLinePrice ?? l.linePrice).amount / l.quantity);
|
|
1764
|
+
const struck2 = escapeHtml(
|
|
1765
|
+
formatMoney2({ amount: unit * a.quantity, currency: l.linePrice.currency })
|
|
1766
|
+
);
|
|
1767
|
+
return `<div class="ksc-line__discount"><span>\u{1F381} ${a.quantity}\xD7 ${code} \u2014 <s>${struck2}</s> FREE \xB7 You save 100%</span></div>`;
|
|
1768
|
+
}
|
|
1769
|
+
return `<div class="ksc-line__discount"><span>\u{1F3F7} ${code} \u2212${escapeHtml(formatMoney2(a.amount))}</span></div>`;
|
|
1770
|
+
}).join("") : "";
|
|
1626
1771
|
return `<div class="ksc-line" data-line-id="${id}">
|
|
1627
1772
|
${image}
|
|
1628
1773
|
<div class="ksc-line__body">
|
|
1629
1774
|
<div class="ksc-line__top">
|
|
1630
|
-
<
|
|
1631
|
-
|
|
1775
|
+
<div class="ksc-line__main">
|
|
1776
|
+
<span class="ksc-line__title">${escapeHtml(l.title)}</span>
|
|
1777
|
+
${meta}
|
|
1778
|
+
${discountRows}
|
|
1779
|
+
</div>
|
|
1780
|
+
<div class="ksc-line__prices">
|
|
1781
|
+
${compare}
|
|
1782
|
+
<span class="ksc-line__price">${escapeHtml(formatMoney2(displayPrice))}</span>
|
|
1783
|
+
${save}
|
|
1784
|
+
</div>
|
|
1632
1785
|
</div>
|
|
1633
|
-
${meta}
|
|
1634
1786
|
<div class="ksc-line__bottom">
|
|
1635
1787
|
<div class="ksc-qty">
|
|
1636
1788
|
<button type="button" data-smart-cart-qty-dec data-qty="${l.quantity}" aria-label="Decrease quantity">\u2212</button>
|
|
1637
1789
|
<span class="ksc-qty__n">${l.quantity}</span>
|
|
1638
1790
|
<button type="button" data-smart-cart-qty-inc data-qty="${l.quantity}" aria-label="Increase quantity">+</button>
|
|
1639
1791
|
</div>
|
|
1640
|
-
<
|
|
1641
|
-
<div class="ksc-line__prices">
|
|
1642
|
-
<span class="ksc-line__price">${escapeHtml(formatMoney2(l.linePrice))}</span>
|
|
1643
|
-
${save}
|
|
1644
|
-
</div>
|
|
1645
|
-
<button type="button" class="ksc-line__remove" data-smart-cart-line-remove aria-label="Remove item">${TRASH_SVG}</button>
|
|
1646
|
-
</div>
|
|
1792
|
+
<button type="button" class="ksc-line__remove" data-smart-cart-line-remove aria-label="Remove item">${TRASH_SVG}</button>
|
|
1647
1793
|
</div>
|
|
1648
1794
|
</div>
|
|
1649
1795
|
</div>`;
|
|
@@ -1663,7 +1809,7 @@ ${css8}`);
|
|
|
1663
1809
|
}
|
|
1664
1810
|
try {
|
|
1665
1811
|
if (displayLines.length === 0) {
|
|
1666
|
-
items.innerHTML = `<div class="ksc-empty">${BAG_SVG}<p data-empty>Your cart is empty
|
|
1812
|
+
items.innerHTML = `<div class="ksc-empty">${BAG_SVG}<p data-empty>Your cart is empty</p></div>`;
|
|
1667
1813
|
checkoutWrap.innerHTML = "";
|
|
1668
1814
|
if (continueWrap)
|
|
1669
1815
|
continueWrap.innerHTML = `<button type="button" class="ksc-continue" data-smart-cart-close>Continue shopping</button>`;
|
|
@@ -1673,28 +1819,21 @@ ${css8}`);
|
|
|
1673
1819
|
return;
|
|
1674
1820
|
}
|
|
1675
1821
|
items.innerHTML = displayLines.map((l) => this.#renderLine(l)).join("");
|
|
1676
|
-
const
|
|
1677
|
-
(sum, l) => sum +
|
|
1678
|
-
0
|
|
1679
|
-
);
|
|
1680
|
-
const cartDiscount = state.discountTotal?.amount ?? 0;
|
|
1681
|
-
const savings = compareAtSavings + cartDiscount;
|
|
1682
|
-
const displayTotal = {
|
|
1683
|
-
amount: Math.max(0, state.subtotal.amount - cartDiscount),
|
|
1822
|
+
const finalSubtotal = {
|
|
1823
|
+
amount: state.lines.reduce((sum, l) => sum + l.linePrice.amount, 0),
|
|
1684
1824
|
currency: state.subtotal.currency
|
|
1685
1825
|
};
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
);
|
|
1826
|
+
const discountsTotal = state.discountTotal?.amount ?? state.discountAllocations?.reduce((sum, a) => sum + a.amount.amount, 0) ?? 0;
|
|
1827
|
+
const displayTotal = finalSubtotal;
|
|
1828
|
+
const rows = [
|
|
1829
|
+
...discountsTotal > 0 ? [
|
|
1830
|
+
`<div class="ksc-summary__row ksc-summary__row--discount"><span>Discounts</span><span>-${escapeHtml(formatMoney2({ amount: discountsTotal, currency: state.subtotal.currency }))}</span></div>`
|
|
1831
|
+
] : [],
|
|
1832
|
+
`<div class="ksc-summary__row ksc-summary__row--total"><span>Subtotal</span><span>${escapeHtml(formatMoney2(finalSubtotal))}</span></div>`
|
|
1833
|
+
];
|
|
1695
1834
|
const totalLabel = escapeHtml(formatMoney2(displayTotal));
|
|
1696
1835
|
checkoutWrap.innerHTML = `<div class="ksc-summary">${rows.join("")}</div>
|
|
1697
|
-
<a class="checkout" data-checkout href="${escapeHtml(state.checkoutUrl)}">Checkout${totalLabel ? ` \
|
|
1836
|
+
<a class="checkout" data-checkout href="${escapeHtml(state.checkoutUrl)}">Checkout${totalLabel ? ` \u2022 ${totalLabel}` : ""}</a>`;
|
|
1698
1837
|
if (continueWrap)
|
|
1699
1838
|
continueWrap.innerHTML = `<button type="button" class="ksc-continue" data-smart-cart-close>or continue shopping</button>`;
|
|
1700
1839
|
} catch (err) {
|