← Commit history

adom-stock: brand type, even pill row, checked stamp

Colby Knox ·81c6b5d2da ·28d ago ·parent 1d1b4f3
1 file changed +12−9
widgets/stock-widget.js+12−9
@@ -3,16 +3,19 @@  * src is the page's stock route: /api/pages/OWNER/SLUG/stock */ (() => {   const esc = s => String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));-  const CSS = `:host{display:block;color:#e6edf3;font:12px/1.3 system-ui,sans-serif;--accent:#00b8b0;--muted:#8b949e;--border:#30363d;--bg:#0d1117;--surface:#161b22}-*{box-sizing:border-box}.wrap{display:flex;flex-wrap:wrap;align-items:center;gap:6px}-.pill{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;border:1px solid var(--border);border-radius:999px;background:var(--surface);color:#e6edf3;text-decoration:none;white-space:nowrap;font-variant-numeric:tabular-nums}-a.pill:hover{border-color:var(--accent)}.pill .v{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.04em}.pill .q{color:var(--accent)}.pill .q.out{color:var(--muted)}.pill .p{color:#e6edf3}-.pill.dim{color:var(--muted)}.pill.dim .q{color:var(--muted)}-.when{flex-basis:100%;color:var(--muted);font-size:11px;margin-top:2px}.when a{color:var(--accent);text-decoration:none}.note{color:var(--muted)}`;+  const CSS = `@font-face{font-family:'Satoshi';src:url('https://adom.inc/fonts/satoshi/satoshi-400-normal.woff2') format('woff2');font-weight:400;font-display:swap}+@font-face{font-family:'Satoshi';src:url('https://adom.inc/fonts/satoshi/satoshi-500-normal.woff2') format('woff2');font-weight:500;font-display:swap}+:host{display:block;color:#e6edf3;font:12px/1.3 'Satoshi',system-ui,sans-serif;--accent:#00b8b0;--muted:#8b949e;--border:#30363d;--bg:#0d1117;--surface:#161b22}+*{box-sizing:border-box}.wrap{display:flex;flex-wrap:wrap;gap:5px;align-items:stretch}+.pill{flex:1 1 auto;display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:4px 9px;border:1px solid var(--border);border-radius:999px;background:var(--surface);color:#e6edf3;text-decoration:none;white-space:nowrap;font-size:11.5px;line-height:1.2;font-variant-numeric:tabular-nums;transition:border-color .15s}+a.pill:hover{border-color:var(--accent)}.pill .v{color:var(--muted);font-weight:500}.pill .q{color:var(--accent);font-weight:500}.pill .q.out{color:var(--muted);font-weight:400}.pill .p{color:#e6edf3}+.pill.dim{color:var(--muted)}.pill.dim .q{color:var(--muted);font-weight:400}+.when{flex-basis:100%;color:var(--muted);font-size:11px;line-height:1.2;margin-top:2px}.when a{color:var(--accent);text-decoration:none}.when a:hover{text-decoration:underline}.note{color:var(--muted);font-size:11.5px}`;   const VENDORS = ['mouser', 'digikey', 'lcsc'];   // Freshness stamp in Ray's form: 12h ago (from the distributor's fetched_at).   const ago = iso => { if (!iso) return ''; const m = Math.max(0, (Date.now() - Date.parse(iso)) / 60000); return m < 60 ? `${Math.max(1, Math.round(m))}m ago` : m < 2880 ? `${Math.round(m / 60)}h ago` : `${Math.round(m / 1440)}d ago`; };   const num = n => Number(n).toLocaleString();+  const price = p => String(p).replace(/(\.\d\d)0$/, '$1');   class AdomStock extends HTMLElement {     constructor() { super(); this.attachShadow({ mode: 'open' }); }     async connectedCallback() {@@ -55,12 +58,12 @@ a.pill:hover{border-color:var(--accent)}.pill .v{color:var(--muted);font-size:11         if (!r) return `<span class="pill dim"><span class="v">${esc(label)}</span><span class="q">not asked</span></span>`;         if (r.error) return `<span class="pill dim" title="${esc(r.error)}"><span class="v">${esc(label)}</span><span class="q">${/no data/.test(r.error) ? 'no data yet' : /budget/.test(r.error) ? 'daily lookups used' : /PARTS_API_KEY/.test(r.error) ? 'not configured' : 'lookup failed'}</span></span>`;         if (!r.found) return `<span class="pill dim"><span class="v">${esc(label)}</span><span class="q">not listed</span></span>`;-        const inner = `<span class="v">${esc(label)}</span><span class="q ${r.stock > 0 ? '' : 'out'}">${r.stock > 0 ? num(r.stock) : 'out of stock'}</span>${r.unit_price ? `<span class="p">${esc(r.unit_price)}</span>` : ''}`;+        const inner = `<span class="v">${esc(label)}</span><span class="q ${r.stock > 0 ? '' : 'out'}">${r.stock > 0 ? num(r.stock) : 'out of stock'}</span>${r.unit_price ? `<span class="p">${esc(price(r.unit_price))}</span>` : ''}`;         const title = `${label}: ${r.part || r.mpn || ''}${r.checked_at ? `, ${ago(r.checked_at)}` : ''}`;         return r.product_url ? `<a class="pill" href="${esc(r.product_url)}" target="_blank" rel="noopener" title="${esc(title)}">${inner}</a>` : `<span class="pill" title="${esc(title)}">${inner}</span>`;       });-      const refresh = d.checked_at && d.signed_in !== false && !d.login_required ? ' <a class="refresh" href="#" title="Ask the distributors again (counts against the daily lookup budget)">refresh</a>' : d.login_required ? ' (sign in to refresh)' : '';-      wrap.innerHTML = pills.join('') + `<span class="when">${esc(ago(d.checked_at))}${refresh}</span>`;+      const refresh = d.checked_at && d.signed_in !== false && !d.login_required ? ' ยท <a class="refresh" href="#" title="Ask the distributors again (counts against the daily lookup budget)">Refresh</a>' : d.login_required ? ' (sign in to refresh)' : '';+      wrap.innerHTML = pills.join('') + `<span class="when">${d.checked_at ? 'Checked ' + esc(ago(d.checked_at)) : ''}${refresh}</span>`;     }   }   if (!customElements.get('adom-stock')) customElements.define('adom-stock', AdomStock);