@tokenoftrust/storefront-runner 2.4.9 → 2.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/storefront/src/components/style-guide/StyleGuideNav.astro +8 -6
- package/apps/storefront/src/layouts/Layout.astro +3 -6
- package/apps/storefront/src/lib/compliance/rawComplianceNotices.ts +10 -5
- package/apps/storefront/src/lib/compliance/tamper-sentinel-boot.ts +2 -0
- package/apps/storefront/src/lib/previewReload.ts +9 -3
- package/apps/storefront/src/lib/styleGuidePaths.ts +31 -0
- package/apps/storefront/src/pages/[...slug].astro +6 -6
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +5 -3
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +5 -2
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +4 -2
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +6 -4
- package/apps/storefront/src/pages/style-guide/index.astro +7 -5
- package/docs/widget-library-guide.md +2 -1
- package/package.json +1 -1
- package/packages/public-runtime/src/binary-path.ts +1 -1
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* aria-current="page". When `headings` is supplied (the guide's H2 outline) a
|
|
15
15
|
* nested table of contents is rendered as in-page anchor links.
|
|
16
16
|
*/
|
|
17
|
+
import { styleGuideHref } from "@/lib/styleGuidePaths";
|
|
18
|
+
|
|
17
19
|
type Active = "index" | "tenant" | "components" | "chrome" | "guide";
|
|
18
20
|
|
|
19
21
|
interface Heading {
|
|
@@ -33,11 +35,11 @@ interface Props {
|
|
|
33
35
|
|
|
34
36
|
const { tenant, theme, active, headings = [] } = Astro.props;
|
|
35
37
|
|
|
36
|
-
const
|
|
38
|
+
const href = (path: string) => styleGuideHref(Astro.locals.basePath ?? "", path);
|
|
37
39
|
// Per-theme surfaces only resolve when we know which theme to skin with.
|
|
38
|
-
const componentsHref = theme ?
|
|
39
|
-
const chromeHref = theme ?
|
|
40
|
-
const guideHref = theme ?
|
|
40
|
+
const componentsHref = theme ? href(`/${tenant}/${theme}/`) : undefined;
|
|
41
|
+
const chromeHref = theme ? href(`/${tenant}/chrome/${theme}/`) : undefined;
|
|
42
|
+
const guideHref = theme ? href(`/${tenant}/guide/${theme}/`) : undefined;
|
|
41
43
|
|
|
42
44
|
const toc = headings.filter((h) => h.depth === 2);
|
|
43
45
|
---
|
|
@@ -47,14 +49,14 @@ const toc = headings.filter((h) => h.depth === 2);
|
|
|
47
49
|
<ul class="sg-nav__list">
|
|
48
50
|
<li>
|
|
49
51
|
<a
|
|
50
|
-
href={
|
|
52
|
+
href={href("/")}
|
|
51
53
|
class:list={["sg-nav__link", { "is-active": active === "index" }]}
|
|
52
54
|
aria-current={active === "index" ? "page" : undefined}
|
|
53
55
|
>All client guides</a>
|
|
54
56
|
</li>
|
|
55
57
|
<li>
|
|
56
58
|
<a
|
|
57
|
-
href={
|
|
59
|
+
href={href(`/${tenant}/`)}
|
|
58
60
|
class:list={["sg-nav__link", { "is-active": active === "tenant" }]}
|
|
59
61
|
aria-current={active === "tenant" ? "page" : undefined}
|
|
60
62
|
>{tenant} — overview</a>
|
|
@@ -18,6 +18,8 @@ import CartDrawerStyles from "@/components/commerce/CartDrawerStyles.astro";
|
|
|
18
18
|
import NicotineWarning from "@/components/compliance/NicotineWarning.astro";
|
|
19
19
|
import PactActNotice from "@/components/compliance/PactActNotice.astro";
|
|
20
20
|
import ShippingRestrictionNotice from "@/components/compliance/ShippingRestrictionNotice.astro";
|
|
21
|
+
import ExciseTaxNotice from "@/components/compliance/ExciseTaxNotice.astro";
|
|
22
|
+
import { EXCISE_TAX_DISCLOSURE_TEXT } from "@/lib/compliance/rawComplianceNotices";
|
|
21
23
|
import IsolatedAgeGate from "@/components/islands/IsolatedAgeGate.tsx";
|
|
22
24
|
import AuthBadge from "@/components/auth/AuthBadge.astro";
|
|
23
25
|
import { referenceTheme } from "@/themes/reference";
|
|
@@ -446,12 +448,7 @@ const footerWidgets = await renderWidgetSlot(
|
|
|
446
448
|
is calculated + added inside the managed cart. This is the storefront's
|
|
447
449
|
honest shopper-facing signal of it. */}
|
|
448
450
|
{capabilities.exciseTax.enabled && features.catalog && (
|
|
449
|
-
<
|
|
450
|
-
class="border-t border-[var(--color-border)] bg-[var(--color-bg)] py-2.5 text-center text-xs text-[var(--color-muted)]"
|
|
451
|
-
data-capability="excise-tax"
|
|
452
|
-
>
|
|
453
|
-
Applicable excise tax is calculated at checkout.
|
|
454
|
-
</p>
|
|
451
|
+
<ExciseTaxNotice variant="footer" config={{ note: EXCISE_TAX_DISCLOSURE_TEXT }} />
|
|
455
452
|
)}
|
|
456
453
|
|
|
457
454
|
{/* Checkout loader — turns add-to-cart forms into the cart drawer + hosted
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* independent of its content: the FDA nicotine warning, the PACT Act notice, the
|
|
7
7
|
* shipping/jurisdiction notice, and the excise-tax disclosure. Each mirrors the exact
|
|
8
8
|
* markup its Layout.astro sibling renders (NicotineWarning.astro "bar" variant,
|
|
9
|
-
* PactActNotice.astro
|
|
10
|
-
* ComplianceNotice.astro
|
|
9
|
+
* PactActNotice.astro, ShippingRestrictionNotice.astro and ExciseTaxNotice.astro
|
|
10
|
+
* "footer" variants via ComplianceNotice.astro) so a raw and a block-composed page present
|
|
11
11
|
* these anchors identically. See `rawHtmlPolicy` for which anchors this does
|
|
12
12
|
* and doesn't cover (notably: NOT `age-gate`).
|
|
13
13
|
*/
|
|
@@ -61,11 +61,16 @@ export function pactActNoticeHtml(minAge?: number): string {
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
64
|
+
/** The excise-tax disclosure wording — the one copy Layout.astro and the raw path both render. */
|
|
65
|
+
export const EXCISE_TAX_DISCLOSURE_TEXT = "Applicable excise tax is calculated at checkout.";
|
|
66
|
+
|
|
67
|
+
/** Mirrors ExciseTaxNotice.astro's "footer" variant (via ComplianceNotice.astro), as Layout.astro renders it. */
|
|
65
68
|
export function exciseTaxNoticeHtml(): string {
|
|
66
69
|
return (
|
|
67
|
-
'<
|
|
68
|
-
"
|
|
70
|
+
'<div class="border-t border-[var(--color-border)] bg-[var(--color-bg)]" data-compliance="excise-tax">' +
|
|
71
|
+
'<p class="container-prose py-3 text-center text-sm text-[var(--color-muted)]" role="note" aria-label="Excise tax notice">' +
|
|
72
|
+
escapeHtml(EXCISE_TAX_DISCLOSURE_TEXT) +
|
|
73
|
+
"</p></div>"
|
|
69
74
|
);
|
|
70
75
|
}
|
|
71
76
|
|
|
@@ -42,10 +42,12 @@ const SURFACE_SELECTORS: Record<ProtectedSurface, readonly string[]> = {
|
|
|
42
42
|
'[data-compliance="pact-act"]',
|
|
43
43
|
'[data-compliance="purchase-limit"]',
|
|
44
44
|
'[data-compliance="adult-signature"]',
|
|
45
|
+
'[data-compliance="excise-tax"]',
|
|
45
46
|
],
|
|
46
47
|
"shipping-jurisdiction-notice": [
|
|
47
48
|
'[data-compliance="shipping-restriction"]',
|
|
48
49
|
'[data-compliance="jurisdiction"]',
|
|
50
|
+
'[data-compliance="state-eligibility"]',
|
|
49
51
|
],
|
|
50
52
|
"cart-preflight": ["[data-cart-preflight]"],
|
|
51
53
|
"checkout-controls": ["[data-checkout-controls]"],
|
|
@@ -106,12 +106,18 @@ export function buildPreviewReloadScript(opts: {
|
|
|
106
106
|
* All dynamic text is written via textContent (never innerHTML), so a hostile
|
|
107
107
|
* blockedURI can't inject markup. Kept tiny + dependency-free.
|
|
108
108
|
*/
|
|
109
|
-
export function buildCspViolationBannerScript(): string {
|
|
109
|
+
export function buildCspViolationBannerScript(basePath = ""): string {
|
|
110
|
+
// A style-guide surface is `/_style-guide/…` or `/style-guide/…`, under the tenant
|
|
111
|
+
// prefix when path-routed (lib/styleGuidePaths.ts).
|
|
110
112
|
return `(() => {
|
|
111
113
|
if (window.__totCspBanner) return; window.__totCspBanner = true;
|
|
112
114
|
const seen = new Set();
|
|
113
115
|
let box = null;
|
|
114
|
-
const
|
|
116
|
+
const BASE = ${jsonForScript(basePath)};
|
|
117
|
+
const path = window.location.pathname || "";
|
|
118
|
+
const isStyleGuide = /^\\/_?style-guide(?:\\/|$)/.test(
|
|
119
|
+
BASE && path.indexOf(BASE + "/") === 0 ? path.slice(BASE.length) : path,
|
|
120
|
+
);
|
|
115
121
|
const isPreviewInspectionStyle = (directive, uri) =>
|
|
116
122
|
directive === "style-src-elem" &&
|
|
117
123
|
(uri === "inline" || uri === "(inline)") &&
|
|
@@ -176,7 +182,7 @@ export function injectPreviewReloadHtml(
|
|
|
176
182
|
// violation banner (both test-env only, injected via the same seam).
|
|
177
183
|
const script =
|
|
178
184
|
`<script nonce="${opts.nonce}">${buildPreviewReloadScript(opts)}</script>` +
|
|
179
|
-
`<script nonce="${opts.nonce}">${buildCspViolationBannerScript()}</script>`;
|
|
185
|
+
`<script nonce="${opts.nonce}">${buildCspViolationBannerScript(opts.basePath)}</script>`;
|
|
180
186
|
if (/<\/body>/i.test(html)) {
|
|
181
187
|
return html.replace(/<\/body>/i, `${script}</body>`);
|
|
182
188
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URLs of the preview/dev style-guide surfaces under the request's tenant routing.
|
|
3
|
+
*
|
|
4
|
+
* The guides live at `/style-guide/…` and are addressed through the internal
|
|
5
|
+
* `/_style-guide/…` alias, which `[...slug].astro` rewrites in-process. A rewrite
|
|
6
|
+
* re-runs the middleware against the NEW URL, so tenant resolution is decided again
|
|
7
|
+
* from that URL alone. On the shared preview host, where the tenant is selected by a
|
|
8
|
+
* `/<domain>` path prefix (`locals.basePath`), a URL without that prefix resolves the
|
|
9
|
+
* host's own tenant and a registered tenant's guide 404s. Every style-guide link and
|
|
10
|
+
* the alias rewrite therefore carry the prefix.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const ALIAS = "_style-guide";
|
|
14
|
+
|
|
15
|
+
/** Link to a style-guide surface. `path` starts with "/" (e.g. `/<tenant>/chrome/<theme>/`). */
|
|
16
|
+
export function styleGuideHref(basePath: string, path = "/"): string {
|
|
17
|
+
return `${basePath}/${ALIAS}${path}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Where an `/_style-guide…` alias request renders: the real route, under the same
|
|
22
|
+
* tenant prefix and with the query intact. `undefined` when `slug` is not the alias.
|
|
23
|
+
*/
|
|
24
|
+
export function styleGuideAliasRewrite(
|
|
25
|
+
basePath: string,
|
|
26
|
+
slug: string,
|
|
27
|
+
search = "",
|
|
28
|
+
): string | undefined {
|
|
29
|
+
if (slug !== ALIAS && !slug.startsWith(`${ALIAS}/`)) return undefined;
|
|
30
|
+
return `${basePath}/style-guide/${slug.slice(ALIAS.length + 1)}${search}`;
|
|
31
|
+
}
|
|
@@ -15,6 +15,7 @@ import { truncate } from "@/lib/format";
|
|
|
15
15
|
import { rawHtmlPolicy, rawHtmlResponse, rawPageCanonicalUrl } from "@/lib/rawMarketingHtml";
|
|
16
16
|
import { renderRawComplianceTop, renderRawComplianceBottom } from "@/lib/compliance/rawComplianceNotices";
|
|
17
17
|
import { rewriteThroughRenderChain } from "@/lib/pinnedRouteRewriteBoundary";
|
|
18
|
+
import { styleGuideAliasRewrite } from "@/lib/styleGuidePaths";
|
|
18
19
|
|
|
19
20
|
const { tenant, canonicalBase, content, basePath, capabilities, features } = Astro.locals;
|
|
20
21
|
const slug = (Astro.params.slug ?? "").replace(/^\/+|\/+$/g, "");
|
|
@@ -33,12 +34,11 @@ if (
|
|
|
33
34
|
// Preview/dev-only style-guide surfaces are requested at `/_style-guide/<tenant>/…`
|
|
34
35
|
// (the leading underscore signals internal). Astro won't route a `_`-prefixed pages
|
|
35
36
|
// dir, so the pages live under `/style-guide/…` and we rewrite the underscored URL
|
|
36
|
-
// onto them. These are noindex + sitemap-excluded and
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
37
|
+
// onto them, under the same tenant prefix. These are noindex + sitemap-excluded and
|
|
38
|
+
// never reskin the live site.
|
|
39
|
+
const styleGuideTarget = styleGuideAliasRewrite(basePath, slug, Astro.url.search);
|
|
40
|
+
if (styleGuideTarget !== undefined) {
|
|
41
|
+
return rewriteThroughRenderChain(Astro, styleGuideTarget);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// Raw tenant-authored marketing subpage (vendor-injected HTML) — serve the
|
|
@@ -21,6 +21,7 @@ export const prerender = false;
|
|
|
21
21
|
// render here without the app Layout. The `.sg-commerce` wrapper pins the
|
|
22
22
|
// reference palette so they look coherent regardless of the marketing theme CSS.
|
|
23
23
|
import { loadStyleGuideThemes, styleGuideCompositionSheets } from "@/lib/styleGuideThemes";
|
|
24
|
+
import { styleGuideHref } from "@/lib/styleGuidePaths";
|
|
24
25
|
import { derivedTokenDeclarations } from "@/themes/derivedTokens";
|
|
25
26
|
import "@/styles/global.css";
|
|
26
27
|
import PriceDisplay from "@/components/commerce/PriceDisplay.astro";
|
|
@@ -90,6 +91,7 @@ import type { HeroBlock, MarketingBlock } from "@/lib/storyblok/content-model";
|
|
|
90
91
|
const { tenant, theme } = Astro.params;
|
|
91
92
|
const cspNonce = Astro.locals.cspNonce;
|
|
92
93
|
const favicon = Astro.locals.tenant.theme_tokens.brand?.favicon ?? "/favicon.svg";
|
|
94
|
+
const href = (path: string) => styleGuideHref(Astro.locals.basePath ?? "", path);
|
|
93
95
|
|
|
94
96
|
// --- Sample chrome data (preview-only; no live tenant content) ----------------
|
|
95
97
|
// Every actionable item declares its tracking intent (`action`) alongside its
|
|
@@ -653,9 +655,9 @@ const componentVarsInline = [
|
|
|
653
655
|
<span class="role">{t.role}</span>
|
|
654
656
|
<b>{t.name}</b>
|
|
655
657
|
<span class="status">{t.status} · concept {t.concept?.id}@{t.concept?.version}</span>
|
|
656
|
-
<a href={
|
|
657
|
-
<a href={
|
|
658
|
-
<a href={
|
|
658
|
+
<a href={href(`/${tenant}/chrome/${t.id}/`)} style="margin-left:auto">shared chrome →</a>
|
|
659
|
+
<a href={href(`/${tenant}/guide/${t.id}/`)}>widget library guide →</a>
|
|
660
|
+
<a href={href(`/${tenant}/`)}>← all guides</a>
|
|
659
661
|
</header>
|
|
660
662
|
|
|
661
663
|
<main>
|
|
@@ -30,8 +30,11 @@ const cspNonce = Astro.locals.cspNonce;
|
|
|
30
30
|
const favicon = Astro.locals.tenant.theme_tokens.brand?.favicon ?? "/favicon.svg";
|
|
31
31
|
|
|
32
32
|
import { loadStyleGuideThemes } from "@/lib/styleGuideThemes";
|
|
33
|
+
import { styleGuideHref } from "@/lib/styleGuidePaths";
|
|
33
34
|
import { derivedTokenDeclarations } from "@/themes/derivedTokens";
|
|
34
35
|
|
|
36
|
+
const href = (path: string) => styleGuideHref(Astro.locals.basePath ?? "", path);
|
|
37
|
+
|
|
35
38
|
const t = (await loadStyleGuideThemes(
|
|
36
39
|
tenant ?? "",
|
|
37
40
|
Astro.locals.tenant,
|
|
@@ -112,8 +115,8 @@ const componentVarsInline = [
|
|
|
112
115
|
<span class="flag">Preview · shared chrome · noindex</span>
|
|
113
116
|
<span class="role">{t.role}</span>
|
|
114
117
|
<b>{t.name}</b>
|
|
115
|
-
<a class="right" href={
|
|
116
|
-
<a href={
|
|
118
|
+
<a class="right" href={href(`/${tenant}/guide/${t.id}/`)}>widget library guide →</a>
|
|
119
|
+
<a href={href(`/${tenant}/${t.id}/`)}>← component guide</a>
|
|
117
120
|
</nav>
|
|
118
121
|
|
|
119
122
|
<main class="sg-page" style={componentVarsInline}>
|
|
@@ -21,10 +21,12 @@ import "@/styles/global.css";
|
|
|
21
21
|
import type { MarkdownInstance } from "astro";
|
|
22
22
|
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
23
23
|
import { loadStyleGuideThemes } from "@/lib/styleGuideThemes";
|
|
24
|
+
import { styleGuideHref } from "@/lib/styleGuidePaths";
|
|
24
25
|
import { derivedTokenDeclarations } from "@/themes/derivedTokens";
|
|
25
26
|
|
|
26
27
|
const { tenant, theme } = Astro.params;
|
|
27
28
|
const cspNonce = Astro.locals.cspNonce;
|
|
29
|
+
const href = (path: string) => styleGuideHref(Astro.locals.basePath ?? "", path);
|
|
28
30
|
const favicon = Astro.locals.tenant.theme_tokens.brand?.favicon ?? "/favicon.svg";
|
|
29
31
|
|
|
30
32
|
const t = (await loadStyleGuideThemes(
|
|
@@ -125,8 +127,8 @@ const componentVarsInline = [
|
|
|
125
127
|
<span class="flag">Preview · widget library · noindex</span>
|
|
126
128
|
<span class="role">{t.role}</span>
|
|
127
129
|
<b>{t.name}</b>
|
|
128
|
-
<a class="right" href={
|
|
129
|
-
<a href={
|
|
130
|
+
<a class="right" href={href(`/${tenant}/${t.id}/`)}>← component guide</a>
|
|
131
|
+
<a href={href(`/${tenant}/`)}>tenant hub →</a>
|
|
130
132
|
</header>
|
|
131
133
|
|
|
132
134
|
<div class="sg-shell">
|
|
@@ -18,9 +18,11 @@ export const prerender = false;
|
|
|
18
18
|
|
|
19
19
|
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
20
20
|
import { loadStyleGuideThemes } from "@/lib/styleGuideThemes";
|
|
21
|
+
import { styleGuideHref } from "@/lib/styleGuidePaths";
|
|
21
22
|
|
|
22
23
|
const { tenant } = Astro.params;
|
|
23
24
|
const cspNonce = Astro.locals.cspNonce;
|
|
25
|
+
const href = (path: string) => styleGuideHref(Astro.locals.basePath ?? "", path);
|
|
24
26
|
const favicon = Astro.locals.tenant.theme_tokens.brand?.favicon ?? "/favicon.svg";
|
|
25
27
|
|
|
26
28
|
const themes = await loadStyleGuideThemes(
|
|
@@ -83,13 +85,13 @@ const navTheme = themes[0]?.id;
|
|
|
83
85
|
</aside>
|
|
84
86
|
<main class="wrap">
|
|
85
87
|
<span class="flag">Preview · dev only · noindex</span>
|
|
86
|
-
<p class="back"><a href="/
|
|
88
|
+
<p class="back"><a href={href("/")}>← all clients</a></p>
|
|
87
89
|
<h1>{tenant} — theme style guides</h1>
|
|
88
90
|
<p class="sub">Open any guide independently to compare looks side-by-side. Nothing here reskins the live site. The <b>Widget Library Guide</b> (left nav) documents every shared component.</p>
|
|
89
91
|
|
|
90
92
|
{themes.map((t) => (
|
|
91
93
|
<div>
|
|
92
|
-
<a class="card" href={
|
|
94
|
+
<a class="card" href={href(`/${tenant}/${t.id}/`)}>
|
|
93
95
|
<div class="row">
|
|
94
96
|
<span class:list={["badge", t.role]}>{t.role}</span>
|
|
95
97
|
<span class="name">{t.name}</span>
|
|
@@ -98,8 +100,8 @@ const navTheme = themes[0]?.id;
|
|
|
98
100
|
{t.description && <p class="desc">{t.description}</p>}
|
|
99
101
|
</a>
|
|
100
102
|
<div class="sub-links">
|
|
101
|
-
<a href={
|
|
102
|
-
<a href={
|
|
103
|
+
<a href={href(`/${tenant}/chrome/${t.id}/`)}>shared chrome preview →</a>
|
|
104
|
+
<a href={href(`/${tenant}/guide/${t.id}/`)}>widget library guide →</a>
|
|
103
105
|
</div>
|
|
104
106
|
</div>
|
|
105
107
|
))}
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
export const prerender = false;
|
|
22
22
|
|
|
23
23
|
import { listedTenantIds } from "@tot/public-runtime";
|
|
24
|
+
import { styleGuideHref } from "@/lib/styleGuidePaths";
|
|
24
25
|
|
|
25
26
|
const cspNonce = Astro.locals.cspNonce;
|
|
27
|
+
const href = (path: string) => styleGuideHref(Astro.locals.basePath ?? "", path);
|
|
26
28
|
const includeTestTenants = Astro.url.searchParams.get("includeTestTenants") === "1";
|
|
27
29
|
|
|
28
30
|
// All tenant-local theme descriptors, grouped by tenant. Colocated repo-root
|
|
@@ -91,18 +93,18 @@ const tenants = [...byTenant.entries()]
|
|
|
91
93
|
<h1>Client style guides</h1>
|
|
92
94
|
<p class="sub">Every client tenant and its theme guides. Open a guide to preview the standard components and page sections re-skinned under that theme. Nothing here re-skins a live site.</p>
|
|
93
95
|
<p class="sub">{includeTestTenants
|
|
94
|
-
? <span>Showing platform test tenants too — <a href="/
|
|
95
|
-
: <span>Platform test tenants are hidden — <a href="
|
|
96
|
+
? <span>Showing platform test tenants too — <a href={href("/")}>hide them</a>.</span>
|
|
97
|
+
: <span>Platform test tenants are hidden — <a href={href("/?includeTestTenants=1")}>show them</a>.</span>}</p>
|
|
96
98
|
|
|
97
99
|
{tenants.map(({ tenant, themes }) => (
|
|
98
100
|
<section class="tenant">
|
|
99
101
|
<h2>
|
|
100
102
|
{tenant}
|
|
101
|
-
<a href={
|
|
102
|
-
{themes[0]?.id && <a href={
|
|
103
|
+
<a href={href(`/${tenant}/`)}>tenant hub →</a>
|
|
104
|
+
{themes[0]?.id && <a href={href(`/${tenant}/guide/${themes[0].id}/`)}>widget library guide →</a>}
|
|
103
105
|
</h2>
|
|
104
106
|
{themes.map((t) => (
|
|
105
|
-
<a class="card" href={
|
|
107
|
+
<a class="card" href={href(`/${tenant}/${t.id}/`)}>
|
|
106
108
|
<div class="row">
|
|
107
109
|
<span class:list={["badge", t.role]}>{t.role}</span>
|
|
108
110
|
<span class="name">{t.name}</span>
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
**Status:** maintained reference, workstream `shared-ecommerce-widgets`. This is the
|
|
4
4
|
human- and agent-facing guide to the shared regulated-ecommerce widget library that every
|
|
5
5
|
storefront tenant inherits. It is the **source of truth**; the style-guide route
|
|
6
|
-
`/_style-guide/<tenant>/guide/<theme>/` renders this same file as HTML
|
|
6
|
+
`/_style-guide/<tenant>/guide/<theme>/` renders this same file as HTML (on the shared preview
|
|
7
|
+
host, under the tenant's path prefix: `/<domain>/_style-guide/<tenant>/guide/<theme>/`).
|
|
7
8
|
|
|
8
9
|
> **How to keep this accurate.** Every widget entry is enumerated from real code under
|
|
9
10
|
> `apps/storefront/src/components/**` and the shared libs in `apps/storefront/src/lib/`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.11",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
|
|
6
6
|
"packageManager": "pnpm@11.9.0",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* - WRITE: `customization-seed.ts#buildSeedFiles` base64-encodes binaries when
|
|
10
10
|
* it materializes the colocated subtree into a flat Gitea-repo seed.
|
|
11
|
-
* - READ: `gitea-source.ts#
|
|
11
|
+
* - READ: `mcp-gitea-source.ts#createMcpGiteaSource().readContent` base64-encodes
|
|
12
12
|
* binaries when it reads them back at a commit for the reconcile/assets sink.
|
|
13
13
|
*
|
|
14
14
|
* Keeping the extension set here (and importing it in both) guarantees the two
|