Skip to main content

max / makenotwork

Move the cart badge out of initTabs It fetches /api/cart/count and fills the header link on every page, from inside the one-time tab wiring. It is not tab behaviour and it is the only reference to nav-cart-link in the tree; it sat there because initTabs was already the thing that ran everywhere. Its own module now, so deleting core/tabs.ts once the last hand-written strip is described is a deletion rather than a migration.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-19 17:01 UTC
Signed with PGP, not checked
Commit: cf4473b450fd491aa07b0c3317f876722fdb0cc4
Parent: a5106f8
3 files changed, +25 insertions, -15 deletions
@@ -18,6 +18,7 @@
18 18 import { resolveHtmxLoadingButton, withLoadingState } from './loading.ts';
19 19 import { initActionDispatcher, initAfterRequestDispatcher } from './dispatch.ts';
20 20 import { setActiveTab, initTabs } from './tabs.ts';
21 + import { initCartBadge } from './cart-badge.ts';
21 22 import { initShowing } from './showing.ts';
22 23 import { toggleShortcutsHelp, initKeyboard } from './keyboard.ts';
23 24 import { initRestartBanner } from './restart-banner.ts';
@@ -73,6 +74,7 @@
73 74 initCopyLink();
74 75 initKeyboard();
75 76 initTabs();
77 + initCartBadge();
76 78 initShowing();
77 79 initRestartBanner();
78 80 }
@@ -130,7 +130,7 @@
130 130 }
131 131
132 132 /** One-time tab wiring: hover preload, overflow init, hash restore, outside-
133 - * click close, cart-count badge. Ported from mnw.js:227. */
133 + * click close. Ported from mnw.js:227. */
134 134 export function initTabs(): void {
135 135 document.querySelectorAll<HTMLElement>('.tab').forEach((btn) => {
136 136 btn.addEventListener('mouseenter', function (this: HTMLElement) {
@@ -156,18 +156,4 @@
156 156 });
157 157 document.querySelectorAll('.tab-more-btn').forEach((b) => b.setAttribute('aria-expanded', 'false'));
158 158 });
159 -
160 - const cartLink = document.getElementById('nav-cart-link');
161 - if (cartLink) {
162 - fetch('/api/cart/count', { credentials: 'same-origin' })
163 - .then((r) => (r.ok ? r.json() : null))
164 - .then((data: { count?: number } | null) => {
165 - if (data && typeof data.count === 'number' && data.count > 0) {
166 - cartLink.classList.remove('hidden');
167 - const badge = document.getElementById('cart-badge');
168 - if (badge) badge.textContent = ' (' + data.count + ')';
169 - }
170 - })
171 - .catch(() => {});
172 - }
173 159 }
@@ -1,0 +1,22 @@
1 + // Cart count badge in the site header. Lived inside `initTabs()` until the
2 + // dashboard strips became described regions and `core/tabs.ts` went away; it
3 + // was never tab behaviour, it just ran on every page from the one place that
4 + // already did.
5 +
6 + /** Fill the header cart link with its item count, and reveal it when non-zero.
7 + * Inert on pages without `#nav-cart-link` (`partials/site_header.html`). */
8 + export function initCartBadge(): void {
9 + const cartLink = document.getElementById('nav-cart-link');
10 + if (!cartLink) return;
11 +
12 + fetch('/api/cart/count', { credentials: 'same-origin' })
13 + .then((r) => (r.ok ? r.json() : null))
14 + .then((data: { count?: number } | null) => {
15 + if (data && typeof data.count === 'number' && data.count > 0) {
16 + cartLink.classList.remove('hidden');
17 + const badge = document.getElementById('cart-badge');
18 + if (badge) badge.textContent = ' (' + data.count + ')';
19 + }
20 + })
21 + .catch(() => {});
22 + }