@@ -256,9 +258,8 @@ export async function renderStore($app, storeLabelRaw) {
${exclusiveBadge}
@@ -277,14 +278,24 @@ export async function renderStore($app, storeLabelRaw) {
`;
}
- // ---- Infinite scroll paging ----
- const PAGE_SIZE = 140;
+ // ---- Infinite scroll paging (shared across both columns) ----
+ const PAGE_SIZE = 140; // total per "page" across both columns
+ const PAGE_EACH = Math.max(1, Math.floor(PAGE_SIZE / 2));
- let filtered = items.slice();
- let shown = 0;
+ let filteredExclusive = [];
+ let filteredCompare = [];
+ let shownExclusive = 0;
+ let shownCompare = 0;
+
+ function totalFiltered() {
+ return filteredExclusive.length + filteredCompare.length;
+ }
+ function totalShown() {
+ return shownExclusive + shownCompare;
+ }
function setStatus() {
- const total = filtered.length;
+ const total = totalFiltered();
if (!total) {
$status.textContent = "No in-stock items for this store.";
return;
@@ -294,28 +305,35 @@ export async function renderStore($app, storeLabelRaw) {
function renderNext(reset) {
if (reset) {
- $results.innerHTML = "";
- shown = 0;
+ $resultsExclusive.innerHTML = "";
+ $resultsCompare.innerHTML = "";
+ shownExclusive = 0;
+ shownCompare = 0;
}
- const slice = filtered.slice(shown, shown + PAGE_SIZE);
- shown += slice.length;
+ const sliceEx = filteredExclusive.slice(shownExclusive, shownExclusive + PAGE_EACH);
+ const sliceCo = filteredCompare.slice(shownCompare, shownCompare + PAGE_EACH);
- if (slice.length) {
- $results.insertAdjacentHTML("beforeend", slice.map(renderCard).join(""));
- }
+ shownExclusive += sliceEx.length;
+ shownCompare += sliceCo.length;
- if (!filtered.length) {
+ if (sliceEx.length) $resultsExclusive.insertAdjacentHTML("beforeend", sliceEx.map(renderCard).join(""));
+ if (sliceCo.length) $resultsCompare.insertAdjacentHTML("beforeend", sliceCo.map(renderCard).join(""));
+
+ const total = totalFiltered();
+ const shown = totalShown();
+
+ if (!total) {
$sentinel.textContent = "";
- } else if (shown >= filtered.length) {
- $sentinel.textContent = `Showing ${shown} / ${filtered.length}`;
+ } else if (shown >= total) {
+ $sentinel.textContent = `Showing ${shown} / ${total}`;
} else {
- $sentinel.textContent = `Showing ${shown} / ${filtered.length}…`;
+ $sentinel.textContent = `Showing ${shown} / ${total}…`;
}
}
// Click -> item page (delegated). SKU + Open links stopPropagation already.
- $results.addEventListener("click", (e) => {
+ $resultsWrap.addEventListener("click", (e) => {
const el = e.target.closest(".item");
if (!el) return;
const sku = el.getAttribute("data-sku") || "";
@@ -325,26 +343,31 @@ export async function renderStore($app, storeLabelRaw) {
});
function applyFilter() {
- const tokens = tokenizeQuery($q.value);
+ const raw = String($q.value || "");
+ localStorage.setItem(LS_KEY, raw);
- if (!tokens.length) {
- filtered = items.slice();
- } else {
- filtered = items.filter((it) => matchesAllTokens(it.searchText, tokens));
+ const tokens = tokenizeQuery(raw);
+
+ let base = items;
+ if (tokens.length) {
+ base = items.filter((it) => matchesAllTokens(it.searchText, tokens));
}
+
+ filteredExclusive = base.filter((it) => it._exclusive);
+ filteredCompare = base.filter((it) => !it._exclusive);
+
setStatus();
renderNext(true);
}
- // Initial render
- setStatus();
- renderNext(true);
+ // Initial render (apply saved query if present)
+ applyFilter();
const io = new IntersectionObserver(
(entries) => {
const hit = entries.some((x) => x.isIntersecting);
if (!hit) return;
- if (shown >= filtered.length) return;
+ if (totalShown() >= totalFiltered()) return;
renderNext(false);
},
{ root: null, rootMargin: "600px 0px", threshold: 0.01 }
@@ -353,7 +376,6 @@ export async function renderStore($app, storeLabelRaw) {
let t = null;
$q.addEventListener("input", () => {
- saveStoreQuery(storeLabel, $q.value);
if (t) clearTimeout(t);
t = setTimeout(applyFilter, 60);
});
diff --git a/viz/style.css b/viz/style.css
index 51f5c65..dba7b21 100644
--- a/viz/style.css
+++ b/viz/style.css
@@ -253,7 +253,6 @@ a.skuLink:hover { text-decoration: underline; cursor: pointer; }
justify-content: space-between; /* spread each row to fill */
}
-
.storeBtn {
border: 1px solid var(--border);
background: #0f1318;
@@ -358,3 +357,36 @@ a.skuLink:hover { text-decoration: underline; cursor: pointer; }
position: sticky;
bottom: 0;
}
+
+/* --- Store page: two-column results (new; isolated to store page) --- */
+.storeGrid {
+ margin-top: 12px;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+ align-items: start;
+}
+
+.storeCol {
+ min-width: 0;
+}
+
+.storeColHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 0 2px 10px 2px;
+}
+
+.storeColList {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+@media (max-width: 640px) {
+ .storeGrid {
+ grid-template-columns: 1fr; /* stack columns */
+ }
+}