SEV-329: @switchev/web-shared package — formatters, markdown, waitForImage

Stands up the shared browser-helpers package (consumed by public/vendor/admin
via the Gitea npm registry) to de-duplicate copy-pasted frontend code:
- format.js: formatLabel/formatStatus/formatTimeline/formatBudget (single source
  of truth — these had drifted, see SEV-310).
- markdown.js: renderMarkdown (marked + strict DOMPurify; both peer deps).
- wait-image.js: waitForImage (was byte-identical in public + vendor).

ESM source package (no build step — Vite consumers import directly). publishConfig
points at the Gitea npm registry. node --test green (formatters).

Next: publish v0.1.0, then migrate each site to consume it and delete the copies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bastian de Byl
2026-06-09 09:42:38 -04:00
parent cb1d8ff661
commit 137086109c
6 changed files with 154 additions and 4 deletions
+39
View File
@@ -0,0 +1,39 @@
// SEV-329: shared display formatters. These were copy-pasted (and subtly
// divergent — SEV-310) across public/vendor/admin. Single source of truth here.
/**
* Friendly label for an internal slug: replaces '-' and '_' with spaces and
* Title-Cases each word. e.g. "contract_pending" → "Contract Pending".
*/
export function formatLabel(val) {
if (!val) return '';
return String(val).replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
}
/** Friendly status label (alias of formatLabel, named for intent at call sites). */
export const formatStatus = formatLabel;
const TIMELINE_LABELS = {
'4_to_6_months': '46 months',
'6_to_12_months': '612 months',
'12_to_24_months': '1224 months',
flexible: 'Flexible',
};
/** Friendly conversion timeline. Falls back to formatLabel for unknown slugs. */
export function formatTimeline(val) {
return TIMELINE_LABELS[val] || formatLabel(val);
}
const BUDGET_LABELS = {
'under-10k': 'Under $10,000',
'10k-25k': '$10,000 $25,000',
'25k-50k': '$25,000 $50,000',
'50k-100k': '$50,000 $100,000',
'100k-plus': '$100,000+',
};
/** Friendly budget-range label for the wizard's slug values. */
export function formatBudget(val) {
return BUDGET_LABELS[val] || val || '';
}