← back to Micawallpaper
Revert "micawallpaper: adopt href-to-deeper-data storefront primitives (TK-10093)"
a7210143847e123a39298f952c235a462d7ff7f2 · 2026-08-01 11:47:36 -0700 · Steve Abrams
This reverts commit e2074b5c711b92674482fb7e44e86a0ce8dee305.
Files touched
D public/drill.jsM public/index.html
Diff
commit a7210143847e123a39298f952c235a462d7ff7f2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Aug 1 11:47:36 2026 -0700
Revert "micawallpaper: adopt href-to-deeper-data storefront primitives (TK-10093)"
This reverts commit e2074b5c711b92674482fb7e44e86a0ce8dee305.
---
public/drill.js | 36 -----------------------------
public/index.html | 68 +++++++++----------------------------------------------
2 files changed, 11 insertions(+), 93 deletions(-)
diff --git a/public/drill.js b/public/drill.js
deleted file mode 100644
index e63cdd3..0000000
--- a/public/drill.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// ── href-to-deeper-data primitives — SINGLE SOURCE OF TRUTH (HARD rule, 2026-07-31) ──
-// Every displayed data point must be an href to its deeper (filtered) data. These are the
-// reusable atoms; a viewer's index.html loads this file, then defines FIELDS, FIL, $, esc,
-// and applyFilters (which these reference at call time via the shared classic-script global
-// scope). Canonical copy: ~/Projects/_shared/web/drill.js → each viewer's public/drill.js.
-// Memory: all-data-points-href-to-deeper-data. Reference viewers: astek-landing, schumacher-internal.
-
-// Build the URL for a given filter set — any count/atom becomes a real, shareable link.
-function qstr(fil, q, pat) {
- const u = new URLSearchParams();
- for (const [k] of FIELDS) { if (fil[k]) u.set(k, fil[k]); }
- if (q) u.set('q', q); if (pat) u.set('pat', pat);
- const s = u.toString(); return s ? ('?' + s) : location.pathname;
-}
-// Read the URL's filter state back into FIL + the search inputs (deep-link / back-button).
-function readURL() {
- const u = new URLSearchParams(location.search);
- for (const [k] of FIELDS) FIL[k] = u.get(k) || '';
- $('#q').value = u.get('q') || ''; $('#pattern').value = u.get('pat') || '';
-}
-// Reflect the current filter state into the URL (push = new history entry, else replace).
-function writeURL(push) {
- const url = qstr(FIL, $('#q').value.trim(), $('#pattern').value.trim());
- history[push ? 'pushState' : 'replaceState']({}, '', url);
-}
-// drill(field,value,label,cls) → an <a> whose href IS the filtered view for that value.
-// cmd/ctrl/middle-click opens it in a new tab; plain click filters in place (delegated listener).
-function drill(field, val, label, cls) {
- if (val == null || val === '') return '';
- const href = qstr({ ...FIL, [field]: String(val) }, $('#q').value.trim(), $('#pattern').value.trim());
- return `<a class="drill ${cls || ''}" href="${href}" data-filter="${field}" data-v="${esc(val)}" title="Filter to ${esc(val)}">${label != null ? esc(label) : esc(val)}</a>`;
-}
-// Atom drill target: SET the filter to this value (drill in), vs pickF which TOGGLES.
-function setF(k, v) { if (FIL[k] === String(v)) return; FIL[k] = String(v); applyFilters('push'); }
-
-window.qstr = qstr; window.readURL = readURL; window.writeURL = writeURL; window.drill = drill; window.setF = setF;
diff --git a/public/index.html b/public/index.html
index 389e982..574695c 100644
--- a/public/index.html
+++ b/public/index.html
@@ -555,8 +555,6 @@ textarea:focus-visible,
})();
</script>
-<style>a.drill.chip{text-decoration:none}.r-aes .drill,.d-chip.drill{cursor:pointer;text-decoration:none;border-bottom:1px dotted transparent}.r-aes .drill:hover,.d-chip.drill:hover{border-bottom-color:currentColor;opacity:.85}</style>
-<script src="/drill.js"></script>
<script>
const state = { q:'', facet:'all', sort:'newest', view:'grid', page:1, pages:1, total:0, loading:false, exhausted:false };
// Touch device = no hover. Drives tap-to-reveal card behavior.
@@ -577,45 +575,6 @@ const HOSTKEY = location.hostname.replace(/\./g, '_');
})();
const LABELS = {"all":"All","silver":"Silver Mica","pearl":"Pearl Mica"};
-// ── href-to-deeper-data (HARD rule) — storefront model: single `aesthetic` facet + q + sort ──
-// Mirror the filter state into the URL so any filtered view is a real shareable/deep-linkable
-// href; aesthetic values become .drill atoms. drill.js is loaded for the fleet atom contract +
-// the enforcer canary; the server-paged logic below is storefront-specific.
-function sfQstr(){
- const u=new URLSearchParams();
- if(state.facet && state.facet!=='all') u.set('aesthetic',state.facet);
- if(state.q) u.set('q',state.q);
- if(state.sort && state.sort!=='newest') u.set('sort',state.sort);
- const s=u.toString(); return s?('?'+s):location.pathname;
-}
-function sfWriteURL(push){ try{ history[push?'pushState':'replaceState']({},'',sfQstr()); }catch(_){} }
-function sfReadURL(){
- const u=new URLSearchParams(location.search);
- state.facet=u.get('aesthetic')||'all';
- state.q=u.get('q')||'';
- if(u.get('sort')) state.sort=u.get('sort');
- const si=document.getElementById('searchInput'); if(si) si.value=state.q;
- const ss=document.getElementById('sortSelect'); if(ss && u.get('sort')) ss.value=state.sort;
-}
-function sfSyncChip(){ document.querySelectorAll('#facets [data-facet]').forEach(b=>b.classList.toggle('active',(b.dataset.facet||'all')===state.facet)); }
-function sfSetAesthetic(v){ state.facet=v||'all'; sfSyncChip(); resetGrid(); sfWriteURL(true); const shop=document.getElementById('shop'); if(shop) shop.scrollIntoView({behavior:'smooth'}); }
-window.sfSetAesthetic=sfSetAesthetic;
-// a .drill atom whose href IS the filtered view for that aesthetic (tag='span' inside the card <a>)
-function sfDrill(value,label,tag){
- if(value==null||value==='') return escAttr(label==null?'':label);
- const t=tag||'a';
- const u=new URLSearchParams(location.search); u.set('aesthetic',String(value));
- const hattr=(t==='a')?(' href="?'+escAttr(u.toString())+'"'):'';
- return '<'+t+' class="drill" data-filter="aesthetic" data-v="'+escAttr(value)+'"'+hattr+' title="See all '+escAttr(String(label))+'">'+escAttr(label)+'</'+t+'>';
-}
-// delegated: plain click on any aesthetic drill atom filters in place; modifier/middle keeps the href
-document.addEventListener('click',function(e){
- const d=e.target.closest('.drill[data-filter="aesthetic"]'); if(!d) return;
- if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button===1) return;
- e.preventDefault(); e.stopPropagation(); sfSetAesthetic(d.dataset.v);
-});
-addEventListener('popstate',function(){ sfReadURL(); sfSyncChip(); resetGrid(); });
-
function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[c])); }
function cleanSku(s){
var V=/(?:^|-)(versace|kravet|fentucci|sandberg|harlequin|blithfield|westport|thibaut|koroseal|schumacher|scalamandre|fromental|dedar|carnegie|marburg|fabricut|coordonne|nina-campbell|lee-jofa(?:-modern)?|clarke(?:-and)?-clarke|clarke|brunschwig(?:-and)?(?:-fils)?|designers-guild|graham-(?:and-)?brown|andrew-martin|candice-olson|ronald-redding|jeffrey-stevens|sister-parish|arte-international|wolf-gordon|phillip-jeffries|cole-(?:and-)?son|maya-romanoff|g-p-j-baker|les-ensembliers|breegan(?:-jane)?)(?:-\\d+)?(?=-|$)/gi;
@@ -645,7 +604,7 @@ function rowHTML(p) {
return '<img loading="lazy" src="' + escAttr(safeImg(p.image_url)) + '" alt="' + escAttr(p.title) + '">'
+ '<div class="r-pat">' + escAttr(p.pattern_name || p.title) + '</div>'
+ '<div class="r-col r-sku">' + escAttr(cleanSku(p.sku || p.handle_display || p.handle) || '—') + '</div>'
- + '<div class="r-col r-aes">' + (p.aesthetic ? sfDrill(p.aesthetic, String(aes).replace(/-/g, ' '), 'span') : escAttr(String(aes).replace(/-/g, ' '))) + '</div>'
+ + '<div class="r-col r-aes">' + escAttr(String(aes).replace(/-/g, ' ')) + '</div>'
+ '<div class="r-col r-price">' + price + '</div>';
}
@@ -676,11 +635,9 @@ function openDetails(p) {
chipsEl.innerHTML = '';
for (const a of safeP.aesthetic) {
if (!a) continue;
- const c = document.createElement('a');
- c.className = 'd-chip drill'; c.dataset.filter = 'aesthetic'; c.dataset.v = a;
- c.href = '?aesthetic=' + encodeURIComponent(a);
+ const c = document.createElement('span');
+ c.className = 'd-chip';
c.textContent = ((typeof LABELS !== 'undefined' && LABELS[a]) || a).replace(/-/g, ' ');
- c.addEventListener('click', ev => { if (ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.button===1) return; ev.preventDefault(); ev.stopPropagation(); dwmClose('Details'); sfSetAesthetic(a); });
chipsEl.appendChild(c);
}
const specsEl = m.querySelector('[data-d-specs]');
@@ -706,19 +663,18 @@ async function loadFacets() {
} catch (e) { console.error('loadFacets failed:', e); return; }
const el = document.getElementById('facets');
for (const [k, v] of Object.entries(f.aesthetics).sort((a,b) => b[1] - a[1])) {
- const b = document.createElement('a');
- b.className = 'chip drill'; b.dataset.facet = k; b.dataset.filter = 'aesthetic'; b.dataset.v = k;
- b.href = '?aesthetic=' + encodeURIComponent(k);
+ const b = document.createElement('button');
+ b.className = 'chip'; b.dataset.facet = k;
b.innerHTML = (LABELS[k] || k) + ' <span style="opacity:.55;font-weight:500;margin-left:4px">' + v + '</span>';
el.appendChild(b);
}
- // dynamic aesthetic chips are .drill anchors (handled by the delegated document click).
- // this handler covers the static "All" button (data-facet=all, not a .drill).
el.addEventListener('click', e => {
- const t = e.target.closest('[data-facet]'); if (!t || t.classList.contains('drill')) return;
- state.facet = t.dataset.facet || 'all'; sfSyncChip(); resetGrid(); sfWriteURL(true);
+ if (e.target.tagName !== 'BUTTON') return;
+ document.querySelectorAll('#facets button').forEach(b => b.classList.remove('active'));
+ e.target.classList.add('active');
+ state.facet = e.target.dataset.facet;
+ resetGrid();
});
- sfSyncChip();
document.getElementById('totalCount').textContent = f.total;
document.getElementById('footerStat').textContent = f.total + ' patterns · live archive';
// Footer aesthetic links
@@ -726,7 +682,7 @@ async function loadFacets() {
for (const [k] of Object.entries(f.aesthetics)) {
const b = document.createElement('button');
b.textContent = LABELS[k] || k;
- b.onclick = () => sfSetAesthetic(k);
+ b.onclick = () => { state.facet = k; resetGrid(); document.querySelectorAll('#facets button').forEach(x => x.classList.toggle('active', x.dataset.facet === k)); document.getElementById('shop').scrollIntoView({behavior:'smooth'}); };
footerEl.appendChild(b);
}
}
@@ -794,7 +750,6 @@ document.getElementById('searchInput').addEventListener('input', e => {
clearTimeout(window._t);
window._t = setTimeout(() => {
resetGrid();
- sfWriteURL(false);
// Mobile: results grid sits below the fold under the keyboard, so a search looks
// like "nothing happened". Bring results into view when a query is entered.
if (state.q) { const a = document.getElementById('statLine') || document.getElementById('grid'); if (a) a.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
@@ -864,7 +819,6 @@ function setTheme(t){ document.documentElement.dataset.theme = t; try { localSto
setTheme(document.documentElement.dataset.theme || 'light');
if (tb) tb.addEventListener('click', () => setTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'));
-sfReadURL();
loadFacets();
loadGridPage();
// renderRailSections is defined in a later <script> block; defer to DOMContentLoaded.
← e2074b5 micawallpaper: adopt href-to-deeper-data storefront primitiv
·
back to Micawallpaper
·
Reapply "micawallpaper: adopt href-to-deeper-data storefront e6f9eb2 →