Skip to main content

max / makenotwork

3.8 KB · 86 lines History Blame Raw
1 // MNW frontend core, entry point.
2 //
3 // Loaded once, globally, as a `<script type="module">` in place of the retired
4 // `static/mnw.js`. It installs every delegated listener the old god-file did
5 // (toasts, HTMX glue, the data-action + hx-callback dispatchers, copy-link,
6 // keyboard, restart banner) and bridges the shared primitives onto
7 // `window` so the not-yet-migrated `static/*.js` files keep resolving them.
8 //
9 // As feature files migrate into frontend/src, drop their entries from the
10 // bridge and register their handlers via `dispatch.register()` instead of a
11 // global; the `frontend_globals` seal ratchets the legacy count down.
12
13 import { escapeHtml, escapeAttr } from './dom.ts';
14 import { csrfHeaders, apiError } from './net.ts';
15 import { showToast, initToasts } from './toast.ts';
16 import { safeGet, safeSet } from './storage.ts';
17 import { copyWithFeedback, initCopyLink } from './clipboard.ts';
18 import { resolveHtmxLoadingButton, withLoadingState } from './loading.ts';
19 import { initActionDispatcher, initAfterRequestDispatcher } from './dispatch.ts';
20 import { initCartBadge } from './cart-badge.ts';
21 import { initShowing } from './showing.ts';
22 import { toggleShortcutsHelp, initKeyboard } from './keyboard.ts';
23 import { initRestartBanner } from './restart-banner.ts';
24 import { initHtmxGlue } from './htmx-glue.ts';
25
26 // Common, lightweight islands are registered globally here (side-effect import
27 // defines the custom element). Heavy or page-specific islands (media player,
28 // uploader) load per-page instead. Custom elements auto-upgrade on connect, so
29 // carousels in HTMX-swapped content wire themselves with no extra glue.
30 import '../islands/carousel.ts';
31 // Image uploader appears in HTMX-swapped wizard steps, so it's registered
32 // globally (auto-upgrades on swap). The heavier upload flows (item audio/version
33 // queue, gallery, bundle) still use the legacy static/upload.js until migrated.
34 import '../islands/uploader/image-uploader.ts';
35 // SyncKit dashboard: the keys-endpoint secret action. Registers a dispatcher
36 // verb (no window global) and is inert on pages without the button.
37 import '../islands/synckit-keys-secret.ts';
38 // /pricing list-vs-founder toggle. Tiny, and inert on every other page and on
39 // /pricing itself once the founder window closes.
40 import '../islands/price-mode.ts';
41
42 /**
43 * Legacy bridge, the not-yet-migrated `static/*.js` files call these by their
44 * historical global names. `mnw.js` exposed them as classic-script globals
45 * (function declarations / `window.*`); the module re-exposes them so the
46 * cutover is behavior-preserving. Retire each entry as its consumers move into
47 * frontend/src.
48 */
49 function installLegacyBridge(): void {
50 const w = window as unknown as Record<string, unknown>;
51 w.escapeHtml = escapeHtml;
52 w.escapeAttr = escapeAttr;
53 w.csrfHeaders = csrfHeaders;
54 w.showToast = showToast;
55 w.safeStorageGet = safeGet;
56 w.safeStorageSet = safeSet;
57 w.toggleShortcutsHelp = toggleShortcutsHelp;
58 w.copyWithFeedback = copyWithFeedback;
59 w.resolveHtmxLoadingButton = resolveHtmxLoadingButton;
60 w.withLoadingState = withLoadingState;
61 // Historical name; wraps apiError so the (response, fallback) signature and
62 // the Promise<string> return match the old global exactly.
63 w.apiErrorMessage = (response: Response | null | undefined, fallback?: string) => apiError(response, fallback);
64 }
65
66 function initCore(): void {
67 installLegacyBridge();
68 initToasts();
69 initHtmxGlue();
70 initActionDispatcher();
71 initAfterRequestDispatcher();
72 initCopyLink();
73 initKeyboard();
74 initCartBadge();
75 initShowing();
76 initRestartBanner();
77 }
78
79 // A module script is deferred, so the DOM is already parsed by the time this
80 // runs; the readyState guard is belt-and-suspenders.
81 if (document.readyState === 'loading') {
82 document.addEventListener('DOMContentLoaded', initCore);
83 } else {
84 initCore();
85 }
86