@tokenoftrust/storefront-runner 2.2.126 → 2.3.0
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/package.json +3 -1
- package/apps/storefront/public/shared/commerce-chrome.css +57 -15
- package/apps/storefront/public/shared/commerce-marketing.css +7 -7
- package/apps/storefront/src/components/Badge.astro +1 -1
- package/apps/storefront/src/components/Breadcrumbs.astro +8 -3
- package/apps/storefront/src/components/Section.astro +4 -1
- package/apps/storefront/src/components/Seo.astro +7 -5
- package/apps/storefront/src/components/blog/BlogIndexView.astro +22 -13
- package/apps/storefront/src/components/blog/ShareRow.astro +43 -0
- package/apps/storefront/src/components/chrome/AnnouncementBar.astro +1 -1
- package/apps/storefront/src/components/chrome/NavDropdown.astro +7 -7
- package/apps/storefront/src/components/chrome/SiteFooter.astro +17 -0
- package/apps/storefront/src/components/chrome/SiteHeader.astro +5 -5
- package/apps/storefront/src/components/commerce/TagFilterCloud.astro +1 -1
- package/apps/storefront/src/components/compliance/NicotineWarning.astro +12 -22
- package/apps/storefront/src/components/compliance/PactActNotice.astro +9 -10
- package/apps/storefront/src/components/content/ProseSections.astro +2 -2
- package/apps/storefront/src/components/home/Hero.astro +34 -12
- package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +39 -5
- package/apps/storefront/src/components/islands/VariantSelector.tsx +3 -3
- package/apps/storefront/src/components/marketing/CardGrid.astro +1 -1
- package/apps/storefront/src/components/marketing/CodeSample.astro +1 -1
- package/apps/storefront/src/components/marketing/CtaBand.astro +1 -1
- package/apps/storefront/src/components/marketing/Faq.astro +1 -1
- package/apps/storefront/src/components/marketing/Integrations.astro +1 -1
- package/apps/storefront/src/components/marketing/MarketingCtas.astro +1 -1
- package/apps/storefront/src/components/marketing/MarketingHero.astro +1 -1
- package/apps/storefront/src/components/marketing/ProofStrip.astro +1 -1
- package/apps/storefront/src/components/marketing/SplitCompare.astro +1 -1
- package/apps/storefront/src/components/marketing/Steps.astro +1 -1
- package/apps/storefront/src/components/marketing/Testimonials.astro +2 -2
- package/apps/storefront/src/components/marketing/TrustBar.astro +1 -1
- package/apps/storefront/src/components/membership/TierComparisonTable.astro +1 -1
- package/apps/storefront/src/components/plp/ActiveFilters.astro +1 -1
- package/apps/storefront/src/components/plp/FacetSidebar.astro +4 -4
- package/apps/storefront/src/components/plp/Pagination.astro +1 -1
- package/apps/storefront/src/components/plp/SortSelect.astro +1 -1
- package/apps/storefront/src/components/style-guide/StyleGuideNav.astro +18 -3
- package/apps/storefront/src/components/the-build/TheBuildIndexView.astro +9 -5
- package/apps/storefront/src/config/devTenantSeed.ts +20 -34
- package/apps/storefront/src/config/resolver.ts +0 -38
- package/apps/storefront/src/layouts/Layout.astro +8 -1
- package/apps/storefront/src/lib/assets/preview-version-cookie.ts +52 -5
- package/apps/storefront/src/lib/blog/pagination.ts +20 -10
- package/apps/storefront/src/lib/blog/presentation.ts +94 -0
- package/apps/storefront/src/lib/blog/rss.ts +1 -1
- package/apps/storefront/src/lib/blog/types.ts +24 -7
- package/apps/storefront/src/lib/breadcrumbs.ts +25 -0
- package/apps/storefront/src/lib/chrome/model.ts +4 -0
- package/apps/storefront/src/lib/cloudflare-workers.d.ts +53 -0
- package/apps/storefront/src/lib/compliance/rawComplianceNotices.ts +38 -18
- package/apps/storefront/src/lib/dashboard/delegateGate.ts +28 -0
- package/apps/storefront/src/lib/homeVisualParity.ts +8 -5
- package/apps/storefront/src/lib/jsonld.ts +5 -5
- package/apps/storefront/src/lib/pinnedRouteRewriteBoundary.ts +20 -2
- package/apps/storefront/src/lib/rawChrome.ts +74 -12
- package/apps/storefront/src/lib/runtimeEnv.ts +1 -1
- package/apps/storefront/src/lib/seo/documentTitle.ts +19 -0
- package/apps/storefront/src/lib/shared/addToRelease.ts +32 -0
- package/apps/storefront/src/lib/storyblok/content-model.ts +3 -0
- package/apps/storefront/src/lib/styleGuideThemes.ts +20 -22
- package/apps/storefront/src/pages/[...slug].astro +13 -8
- package/apps/storefront/src/pages/blog/[slug].astro +56 -24
- package/apps/storefront/src/pages/blog/author/[author].astro +17 -9
- package/apps/storefront/src/pages/blog/category/[category].astro +18 -10
- package/apps/storefront/src/pages/blog/index.astro +2 -0
- package/apps/storefront/src/pages/blog/page/[n].astro +2 -0
- package/apps/storefront/src/pages/blog/tag/[tag].astro +18 -10
- package/apps/storefront/src/pages/collections/[handle].astro +5 -4
- package/apps/storefront/src/pages/collections/index.astro +4 -3
- package/apps/storefront/src/pages/index.astro +34 -27
- package/apps/storefront/src/pages/products/[handle].astro +5 -4
- package/apps/storefront/src/pages/saved.astro +4 -3
- package/apps/storefront/src/pages/search.astro +4 -3
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +129 -118
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +19 -15
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +23 -27
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +7 -14
- package/apps/storefront/src/pages/style-guide/index.astro +6 -5
- package/apps/storefront/src/pages/tenants/[id]/[...path].ts +32 -7
- package/apps/storefront/src/pages/the-build/[slug].astro +44 -20
- package/apps/storefront/src/pages/the-build/index.astro +2 -0
- package/apps/storefront/src/pages/the-build/page/[n].astro +2 -0
- package/apps/storefront/src/styles/admin.css +47 -0
- package/apps/storefront/src/styles/global.css +104 -56
- package/apps/storefront/src/themes/derivedTokens.ts +34 -0
- package/apps/storefront/src/themes/schema.ts +6 -0
- package/apps/storefront/test/pipeline/harness.ts +164 -0
- package/apps/storefront/test/pipeline/intake-worker.mjs +14 -0
- package/apps/storefront/test/pipeline/pipeline-host.ts +77 -0
- package/apps/storefront/test/pipeline/synthetic-job.ts +156 -0
- package/apps/storefront/vitest.workers.config.cts +67 -0
- package/docs/widget-library-guide.md +1496 -0
- package/package.json +1 -1
- package/packages/cli/src/declared-config.mjs +400 -5
- package/packages/public-runtime/package.json +1 -0
- package/packages/public-runtime/src/chrome.ts +93 -2
- package/packages/public-runtime/src/compliance-coherence.d.mts +17 -0
- package/packages/public-runtime/src/compliance-coherence.mjs +84 -0
- package/packages/public-runtime/src/declared-tenant-config.d.mts +1 -1
- package/packages/public-runtime/src/declared-tenant-config.mjs +6 -2
- package/packages/public-runtime/src/extension-contract-values.d.mts +4 -1
- package/packages/public-runtime/src/extension-contract-values.mjs +14 -1
- package/packages/public-runtime/src/extension-contract.ts +2 -0
- package/packages/public-runtime/src/tenant.ts +48 -4
- package/pnpm-lock.runner.yaml +469 -0
- package/scripts/tenant/validate.mjs +27 -1
|
@@ -20,7 +20,8 @@ export const prerender = false;
|
|
|
20
20
|
// utilities + reference theme-token fallbacks so the (token-styled) components
|
|
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
|
-
import {
|
|
23
|
+
import { loadStyleGuideThemes, styleGuideCompositionSheets } from "@/lib/styleGuideThemes";
|
|
24
|
+
import { derivedTokenDeclarations } from "@/themes/derivedTokens";
|
|
24
25
|
import "@/styles/global.css";
|
|
25
26
|
import PriceDisplay from "@/components/commerce/PriceDisplay.astro";
|
|
26
27
|
import RatingStars from "@/components/commerce/RatingStars.astro";
|
|
@@ -45,6 +46,7 @@ import NavDropdown from "@/components/chrome/NavDropdown.astro";
|
|
|
45
46
|
import SiteFooter from "@/components/chrome/SiteFooter.astro";
|
|
46
47
|
import { CHROME_PLACEMENT } from "@/lib/chrome/trackingPlacements";
|
|
47
48
|
import NicotineWarning from "@/components/compliance/NicotineWarning.astro";
|
|
49
|
+
import { NICOTINE_WARNING_PRESETS } from "../../../../../../packages/cli/src/declared-config.mjs";
|
|
48
50
|
import PactActNotice from "@/components/compliance/PactActNotice.astro";
|
|
49
51
|
import AdultSignatureNotice from "@/components/compliance/AdultSignatureNotice.astro";
|
|
50
52
|
import Prop65Warning from "@/components/compliance/Prop65Warning.astro";
|
|
@@ -477,19 +479,12 @@ const t = (await loadStyleGuideThemes(
|
|
|
477
479
|
|
|
478
480
|
if (!t) return new Response(null, { status: 404 });
|
|
479
481
|
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
Astro.locals.tenant,
|
|
487
|
-
Astro.locals.content,
|
|
488
|
-
);
|
|
489
|
-
// Adoption is now "does chrome.json carry the consolidated header/footer
|
|
490
|
-
// shape" (lib/chrome/model.ts ChromeConfig) — the old `sharedChrome: true`
|
|
491
|
-
// opt-in flag is retired; a successfully-shaped config IS the adopted signal.
|
|
492
|
-
const usesSharedChrome = !!chromeConfig?.header && !!chromeConfig?.footer;
|
|
482
|
+
// The platform composition sheet always exists, so the guide always links it.
|
|
483
|
+
// A tenant's own composition layer (e.g. a ported marketing site's mkt.css) is
|
|
484
|
+
// linked only when the theme descriptor declares it in `preview.stylesheets` —
|
|
485
|
+
// never guessed from a path, which 404s for every tenant that has none. Only
|
|
486
|
+
// root-relative paths under this tenant's own /tenants/<tenant>/ tree are taken.
|
|
487
|
+
const compositionSheets = styleGuideCompositionSheets(t, tenant ?? "");
|
|
493
488
|
|
|
494
489
|
const tk = t.tokens ?? {};
|
|
495
490
|
const storyboard = t.storyboard ?? null;
|
|
@@ -506,10 +501,7 @@ const REFERENCE_COMPONENT_VARS: Record<string, string> = {
|
|
|
506
501
|
// values so the text/icon-token samples render concretely and re-skin when a
|
|
507
502
|
// descriptor overrides them via preview.componentVars.
|
|
508
503
|
"--color-warning": "#8a5717", "--color-error": "#a22014", "--color-info": "#2c5b73",
|
|
509
|
-
"--
|
|
510
|
-
"--color-focus-ring": "#b5612f", "--color-disabled": "#e4dfd4",
|
|
511
|
-
"--color-disabled-contrast": "#8b938f", "--color-field-border": "#8f887a",
|
|
512
|
-
"--color-star": "#b5612f", "--tap-target": "44px",
|
|
504
|
+
"--tap-target": "44px",
|
|
513
505
|
"--radius-sm": "3px", "--radius-md": "6px", "--radius-lg": "12px", "--radius-full": "999px",
|
|
514
506
|
"--shadow-sm": "0 1px 2px rgba(28,38,36,.06)", "--shadow-md": "0 6px 24px -8px rgba(28,38,36,.14)",
|
|
515
507
|
"--shadow-lg": "0 24px 60px -20px rgba(28,38,36,.22)", "--container-max": "1240px",
|
|
@@ -523,9 +515,13 @@ const componentVars: Record<string, string> = {
|
|
|
523
515
|
...REFERENCE_COMPONENT_VARS,
|
|
524
516
|
...((t.preview?.componentVars ?? {}) as Record<string, string>),
|
|
525
517
|
};
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
518
|
+
// Derived tokens (accent-ink, accent-contrast, hovers, focus ring, …) are
|
|
519
|
+
// re-declared on the same element, so they derive from THIS theme's palette
|
|
520
|
+
// rather than inheriting values derived from the page root's.
|
|
521
|
+
const componentVarsInline = [
|
|
522
|
+
...Object.entries(componentVars).map(([k, v]) => `${k}:${v}`),
|
|
523
|
+
...derivedTokenDeclarations(componentVars),
|
|
524
|
+
].join(";");
|
|
529
525
|
---
|
|
530
526
|
|
|
531
527
|
<!doctype html>
|
|
@@ -537,16 +533,12 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
537
533
|
<link rel="icon" href={favicon} />
|
|
538
534
|
<meta name="description" content={`${t.name} preview style guide and component contract.`} />
|
|
539
535
|
<title>{t.name} — style guide (preview)</title>
|
|
540
|
-
{/*
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
and the preview visibly re-skins with the theme. */}
|
|
536
|
+
{/* External, CSP-clean 'self' sheets: the theme token/base layer under
|
|
537
|
+
review, the platform composition sheet, and any composition layer the
|
|
538
|
+
descriptor declares. */}
|
|
544
539
|
<link rel="stylesheet" href={t.stylesheet} />
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
) : (
|
|
548
|
-
<link rel="stylesheet" href={`/tenants/${tenant}/pages/mkt.css`} />
|
|
549
|
-
)}
|
|
540
|
+
<link rel="stylesheet" href="/shared/commerce-chrome.css" />
|
|
541
|
+
{compositionSheets.map((href) => <link rel="stylesheet" href={href} />)}
|
|
550
542
|
{/* Guide-only chrome; distinct .sg-* names so it never collides with the theme. */}
|
|
551
543
|
<style nonce={cspNonce}>
|
|
552
544
|
.sg-bar { position: sticky; top: 0; z-index: 200; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; background: #0f1729; color: #e6edf6; padding: 12px 20px; font: 600 .95rem -apple-system, sans-serif; }
|
|
@@ -578,33 +570,36 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
578
570
|
when the descriptor carries t.storyboard. */
|
|
579
571
|
.sg-story { background: #101b30; color: #e6edf6; padding: 24px 20px 28px; }
|
|
580
572
|
.sg-story .inner { max-width: 1080px; margin: 0 auto; }
|
|
581
|
-
.sg-story h2 { font: 800 .
|
|
573
|
+
.sg-story h2 { font: 800 max(.875rem, 14px)/1.2 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: #7fe3d4; margin: 0 0 8px; }
|
|
582
574
|
.sg-story p.summary { margin: 0 0 18px; max-width: 76ch; color: #c6d2e4; font-size: .96rem; }
|
|
583
575
|
.sg-story .insp { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
|
|
584
576
|
.sg-story .insp .card { background: #16223c; border: 1px solid #26365a; border-radius: 12px; padding: 14px 16px; }
|
|
585
|
-
.sg-story .insp .role { display: inline-block; font-size: .
|
|
586
|
-
.sg-story .insp .slug { font-family: ui-monospace, Menlo, monospace; font-size: .
|
|
577
|
+
.sg-story .insp .role { display: inline-block; font-size: max(.875rem, 14px); letter-spacing: .08em; text-transform: uppercase; font-weight: 800; color: #0a1a12; background: #7fe3d4; padding: 3px 8px; border-radius: 999px; margin-bottom: 8px; }
|
|
578
|
+
.sg-story .insp .slug { font-family: ui-monospace, Menlo, monospace; font-size: max(.875rem, 14px); color: #9fb0c8; margin-bottom: 8px; }
|
|
587
579
|
.sg-story .insp ul { margin: 0; padding-left: 16px; }
|
|
588
|
-
.sg-story .insp li { font-size: .
|
|
580
|
+
.sg-story .insp li { font-size: max(.875rem, 14px); color: #c6d2e4; margin-bottom: 3px; }
|
|
589
581
|
|
|
590
582
|
/* Page-section samples — a representative slice of the storefront rethemed:
|
|
591
583
|
hero, promo-card row, category tiles. Token-styled (no per-tenant CSS) so
|
|
592
584
|
they re-skin from the emitted component vars. */
|
|
593
585
|
.sg-hero { display: grid; gap: 24px; grid-template-columns: 1.15fr .85fr; align-items: stretch; }
|
|
594
586
|
.sg-hero .copy { background: var(--color-primary); color: var(--color-primary-contrast); border-radius: var(--radius-lg); padding: clamp(24px, 4vw, 44px); display: flex; flex-direction: column; justify-content: center; }
|
|
595
|
-
.sg-hero .copy .kick { font: 800 .
|
|
587
|
+
.sg-hero .copy .kick { font: 800 max(.875rem, 14px)/1 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; }
|
|
588
|
+
.sg-hero .promo .kick { color: var(--color-accent-ink); font: 800 max(.875rem, 14px)/1 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; }
|
|
589
|
+
.sg-hero .promo h4 { font-family: var(--font-display); font-size: 1.25rem; margin: 8px 0 4px; }
|
|
590
|
+
.sg-hero .promo p { margin: 0; color: var(--color-muted); font-size: max(.875rem, 14px); }
|
|
596
591
|
.sg-hero .copy h3 { font-family: var(--font-display); font-size: clamp(1.6rem, 3.4vw, 2.6rem); line-height: 1.08; margin: 12px 0 10px; color: inherit; }
|
|
597
592
|
.sg-hero .copy p { color: inherit; opacity: .9; margin: 0 0 20px; max-width: 40ch; }
|
|
598
593
|
.sg-hero .promo { border-radius: var(--radius-lg); overflow: hidden; background: var(--color-surface); border: 1px solid var(--color-border); display: flex; align-items: flex-end; min-height: 220px; padding: 22px; color: var(--color-text); box-shadow: var(--shadow-md); }
|
|
599
|
-
.sg-btn { display: inline-flex; align-items: center; gap: .5em; align-self: flex-start; min-height: 44px; padding: .7em 1.5em; border-radius: var(--radius-full); font-weight: 700; background: var(--color-accent); color:
|
|
594
|
+
.sg-btn { display: inline-flex; align-items: center; gap: .5em; align-self: flex-start; min-height: 44px; padding: .7em 1.5em; border-radius: var(--radius-full); font-weight: 700; background: var(--color-accent); color: var(--color-accent-contrast); border: 2px solid transparent; }
|
|
600
595
|
.sg-btn.ghost { background: transparent; color: inherit; border-color: currentColor; }
|
|
601
596
|
.sg-promos { display: grid; gap: 16px; grid-template-columns: repeat(3, 1fr); }
|
|
602
597
|
.sg-promo { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 22px; box-shadow: var(--shadow-sm); }
|
|
603
|
-
.sg-promo .tag { display: inline-block; font-size: .
|
|
598
|
+
.sg-promo .tag { display: inline-block; font-size: max(.75rem, 12px); letter-spacing: .08em; text-transform: uppercase; font-weight: 800; color: var(--color-primary-contrast); background: var(--color-sale); padding: 3px 8px; border-radius: 999px; margin-bottom: 10px; }
|
|
604
599
|
.sg-promo h4 { font-family: var(--font-display); font-size: 1.1rem; margin: 0 0 6px; color: var(--color-text); }
|
|
605
|
-
.sg-promo p { margin: 0; color: var(--color-muted); font-size: .
|
|
600
|
+
.sg-promo p { margin: 0; color: var(--color-muted); font-size: max(.875rem, 14px); }
|
|
606
601
|
.sg-tiles { display: grid; gap: 14px; grid-template-columns: repeat(4, 1fr); }
|
|
607
|
-
.sg-tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-height: 132px; text-align: center; border-radius: var(--radius-lg); color:
|
|
602
|
+
.sg-tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-height: 132px; text-align: center; border-radius: var(--radius-lg); color: var(--color-primary-contrast); background: linear-gradient(135deg, var(--color-primary), var(--color-primary) 60%, color-mix(in srgb, var(--color-primary) 70%, #000)); padding: 18px; }
|
|
608
603
|
.sg-tile .ico { width: 40px; height: 40px; border-radius: 999px; background: rgba(255,255,255,.16); display: grid; place-items: center; font-size: 1.1rem; }
|
|
609
604
|
.sg-tile span { font-family: var(--font-display); font-weight: 700; font-size: .95rem; }
|
|
610
605
|
@media (max-width: 900px) { .sg-hero { grid-template-columns: 1fr; } .sg-promos { grid-template-columns: 1fr; } .sg-tiles { grid-template-columns: 1fr 1fr; } }
|
|
@@ -626,7 +621,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
626
621
|
from tokens alone — never a hard-coded color. */
|
|
627
622
|
.sg-tok-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
|
|
628
623
|
.sg-tok { border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 12px 14px; background: var(--color-surface); }
|
|
629
|
-
.sg-tok .lab { display: block; font-size: .
|
|
624
|
+
.sg-tok .lab { display: block; font-size: max(.75rem, 12px); letter-spacing: .04em; color: var(--color-muted); font-family: var(--font-mono, ui-monospace, Menlo, monospace); margin-top: 6px; }
|
|
630
625
|
.sg-tok .txt { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; line-height: 1.2; display: inline-flex; align-items: center; gap: .5em; }
|
|
631
626
|
.sg-tok .ico { width: 1.15em; height: 1.15em; flex: none; }
|
|
632
627
|
.sg-tok-state { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
|
|
@@ -645,6 +640,11 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
645
640
|
/* Tap-target demo: an icon button sized to the WCAG minimum. */
|
|
646
641
|
.sg-tap { display: inline-flex; align-items: center; justify-content: center; min-width: var(--tap-target); min-height: var(--tap-target); border-radius: var(--radius-full); border: 1px solid var(--color-border); background: var(--color-surface); color: var(--color-primary); cursor: pointer; }
|
|
647
642
|
.sg-tap svg { width: 20px; height: 20px; }
|
|
643
|
+
/* Guide-owned captions: the guide meets the bar it enforces (≥14px text). */
|
|
644
|
+
.sg-cap { font: 500 max(.875rem, 14px)/1.45 -apple-system, sans-serif; color: var(--color-muted, #5c6663); margin: 0 0 8px; }
|
|
645
|
+
.sg-tok .txt .ico { color: var(--sg-ico); }
|
|
646
|
+
.sg-foot { padding: 28px 20px; background: #0f1729; color: #cdd8e8; text-align: center; }
|
|
647
|
+
.sg-foot p { margin: 0; font: 500 max(.875rem, 14px)/1.4 -apple-system, sans-serif; }
|
|
648
648
|
</style>
|
|
649
649
|
</head>
|
|
650
650
|
<body>
|
|
@@ -658,6 +658,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
658
658
|
<a href={`/_style-guide/${tenant}/`}>← all guides</a>
|
|
659
659
|
</header>
|
|
660
660
|
|
|
661
|
+
<main>
|
|
661
662
|
{storyboard && (
|
|
662
663
|
<section class="sg-story">
|
|
663
664
|
<div class="inner">
|
|
@@ -680,7 +681,6 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
680
681
|
</section>
|
|
681
682
|
)}
|
|
682
683
|
|
|
683
|
-
<main>
|
|
684
684
|
<div class="container">
|
|
685
685
|
<section class="sg-block">
|
|
686
686
|
<p class="sg-h">Color tokens</p>
|
|
@@ -745,7 +745,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
745
745
|
<button class="btn btn-primary is-loading" type="button" aria-busy="true">Loading</button>
|
|
746
746
|
<button class="btn btn-primary" type="button" disabled>Disabled</button>
|
|
747
747
|
</div>
|
|
748
|
-
<p class="
|
|
748
|
+
<p class="sg-cap" style="margin-top:12px">All targets ≥44px. Tab to any control to see the <code>:focus-visible</code> ring.</p>
|
|
749
749
|
</section>
|
|
750
750
|
|
|
751
751
|
<section class="sg-block">
|
|
@@ -780,7 +780,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
780
780
|
<blockquote class="quote">“Testimonial / customer quote placeholder — do not ship until sourced.”</blockquote>
|
|
781
781
|
<p class="cite">— Role, Company · <b class="opt">needs-review</b></p>
|
|
782
782
|
</div>
|
|
783
|
-
<p class="
|
|
783
|
+
<p class="sg-cap" style="margin-bottom:8px">Logo strip — "as seen in" / customer & partner logos (placeholder):</p>
|
|
784
784
|
<div class="logo-strip">
|
|
785
785
|
<span class="logo">LOGO</span><span class="logo">LOGO</span><span class="logo">LOGO</span><span class="logo">LOGO</span>
|
|
786
786
|
</div>
|
|
@@ -835,12 +835,14 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
835
835
|
</div>
|
|
836
836
|
</section>
|
|
837
837
|
|
|
838
|
-
{/* ── Marketing page components (
|
|
839
|
-
The
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
838
|
+
{/* ── Marketing page components (a declared composition layer) ──────
|
|
839
|
+
The ported-site composition palette (mkt.css-style classes) that a
|
|
840
|
+
tenant's own pages draw from. Rendered when the descriptor declares
|
|
841
|
+
that layer in preview.stylesheets; the token-styled platform marketing
|
|
842
|
+
blocks further down render for every theme. When a port harvests a
|
|
843
|
+
new reusable pattern into the layer, add a sample here (see
|
|
844
|
+
agency-kit/playbooks/style-concept.md §Harvesting components). */}
|
|
845
|
+
{compositionSheets.length > 0 && (
|
|
844
846
|
<>
|
|
845
847
|
<section class="sg-block">
|
|
846
848
|
<p class="sg-h">Marketing components — <code>mkt.css</code></p>
|
|
@@ -923,6 +925,17 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
923
925
|
</div>
|
|
924
926
|
</section>
|
|
925
927
|
|
|
928
|
+
<section class="sg-block">
|
|
929
|
+
<p class="sg-h">Footer — <code>footer.site</code> / <code>.foot-grid</code></p>
|
|
930
|
+
<footer class="site" aria-label="Footer sample">
|
|
931
|
+
<div class="foot-grid">
|
|
932
|
+
<div><b>{t.name}</b><p class="copyright">Footer composition sample.</p></div>
|
|
933
|
+
<div><h3>Shop</h3><ul><li><a href="#">New arrivals</a></li><li><a href="#">Best sellers</a></li></ul></div>
|
|
934
|
+
<div><h3>Help</h3><ul><li><a href="#">Shipping</a></li><li><a href="#">Contact</a></li></ul></div>
|
|
935
|
+
</div>
|
|
936
|
+
</footer>
|
|
937
|
+
</section>
|
|
938
|
+
|
|
926
939
|
<section class="sg-block">
|
|
927
940
|
<p class="sg-h">CTA band — <code>.cta-band</code></p>
|
|
928
941
|
<div class="cta-band">
|
|
@@ -942,7 +955,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
942
955
|
products so this works with no live catalog. These are STANDARD components:
|
|
943
956
|
fidelity comes from theme tokens + variant props, never a per-tenant fork.
|
|
944
957
|
See playbook/site-migration/shared-chrome.md. */}
|
|
945
|
-
<div class="sg-commerce" style={componentVarsInline}>
|
|
958
|
+
<div class="sg-commerce" data-tot-platform-sample style={componentVarsInline}>
|
|
946
959
|
<section class="sg-block">
|
|
947
960
|
<p class="sg-h">Page sections — the site rethemed</p>
|
|
948
961
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Representative storefront sections rendered from theme tokens only. Swap the theme and this whole slice re-skins — hero, promos, category tiles, carousels, and chrome — with no per-tenant component fork.</p>
|
|
@@ -955,9 +968,9 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
955
968
|
</div>
|
|
956
969
|
<div class="promo">
|
|
957
970
|
<div>
|
|
958
|
-
<span class="kick"
|
|
959
|
-
<h4
|
|
960
|
-
<p
|
|
971
|
+
<span class="kick">Featured</span>
|
|
972
|
+
<h4>Right-rail promo tile</h4>
|
|
973
|
+
<p>Two-up hero: banner + promo.</p>
|
|
961
974
|
</div>
|
|
962
975
|
</div>
|
|
963
976
|
</div>
|
|
@@ -973,39 +986,39 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
973
986
|
<p class="sg-h">Semantic text & icon tokens (v1.1)</p>
|
|
974
987
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Each swatch reads one contract token. A theme passes the quality bar by supplying these — or inheriting the platform default — so every text and icon role resolves and re-skins from tokens alone.</p>
|
|
975
988
|
|
|
976
|
-
<p class="
|
|
989
|
+
<p class="sg-cap" style="margin:18px 0 8px">Text roles</p>
|
|
977
990
|
<div class="sg-tok-grid">
|
|
978
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-text)">Primary body text</span><span class="lab">--color-text</span></div>
|
|
979
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-muted)">Secondary / caption</span><span class="lab">--color-muted</span></div>
|
|
980
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-primary)">Brand / link anchor</span><span class="lab">--color-primary</span></div>
|
|
981
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-accent-ink)">Accent text (AA)</span><span class="lab">--color-accent-ink</span></div>
|
|
982
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-success)">In stock · savings</span><span class="lab">--color-success</span></div>
|
|
983
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-sale)">Sale price</span><span class="lab">--color-sale</span></div>
|
|
984
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-warning)">Low stock</span><span class="lab">--color-warning</span></div>
|
|
985
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-error)">Error · out of stock</span><span class="lab">--color-error</span></div>
|
|
986
|
-
<div class="sg-tok"><span class="txt" style="color:var(--color-info)">Informational</span><span class="lab">--color-info</span></div>
|
|
991
|
+
<div class="sg-tok" data-token-sample="--color-text"><span class="txt" style="color:var(--color-text)">Primary body text</span><span class="lab">--color-text</span></div>
|
|
992
|
+
<div class="sg-tok" data-token-sample="--color-muted"><span class="txt" style="color:var(--color-muted)">Secondary / caption</span><span class="lab">--color-muted</span></div>
|
|
993
|
+
<div class="sg-tok" data-token-sample="--color-primary"><span class="txt" style="color:var(--color-primary)">Brand / link anchor</span><span class="lab">--color-primary</span></div>
|
|
994
|
+
<div class="sg-tok" data-token-sample="--color-accent-ink"><span class="txt" style="color:var(--color-accent-ink)">Accent text (AA)</span><span class="lab">--color-accent-ink</span></div>
|
|
995
|
+
<div class="sg-tok" data-token-sample="--color-success"><span class="txt" style="color:var(--color-success)">In stock · savings</span><span class="lab">--color-success</span></div>
|
|
996
|
+
<div class="sg-tok" data-token-sample="--color-sale"><span class="txt" style="color:var(--color-sale)">Sale price</span><span class="lab">--color-sale</span></div>
|
|
997
|
+
<div class="sg-tok" data-token-sample="--color-warning"><span class="txt" style="color:var(--color-warning)">Low stock</span><span class="lab">--color-warning</span></div>
|
|
998
|
+
<div class="sg-tok" data-token-sample="--color-error"><span class="txt" style="color:var(--color-error)">Error · out of stock</span><span class="lab">--color-error</span></div>
|
|
999
|
+
<div class="sg-tok" data-token-sample="--color-info"><span class="txt" style="color:var(--color-info)">Informational</span><span class="lab">--color-info</span></div>
|
|
987
1000
|
</div>
|
|
988
1001
|
|
|
989
|
-
<p class="
|
|
1002
|
+
<p class="sg-cap" style="margin:22px 0 8px">Icon roles (<code>currentColor</code> tinted by token)</p>
|
|
990
1003
|
<div class="sg-tok-grid">
|
|
991
|
-
<div class="sg-tok"><span class="txt" style="
|
|
1004
|
+
<div class="sg-tok" data-token-sample="--color-star"><span class="txt" style="--sg-ico:var(--color-star)">
|
|
992
1005
|
<svg class="ico" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M10 1.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L10 15l-5.2 2.6 1-5.8L1.5 7.7l5.9-.9L10 1.5z"/></svg>
|
|
993
1006
|
Rating star</span><span class="lab">--color-star</span></div>
|
|
994
|
-
<div class="sg-tok"><span class="txt" style="
|
|
1007
|
+
<div class="sg-tok" data-token-sample="--color-success"><span class="txt" style="--sg-ico:var(--color-success)">
|
|
995
1008
|
<svg class="ico" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 10.5l4 4 8-9"/></svg>
|
|
996
1009
|
Success check</span><span class="lab">--color-success</span></div>
|
|
997
|
-
<div class="sg-tok"><span class="txt" style="
|
|
1010
|
+
<div class="sg-tok" data-token-sample="--color-warning"><span class="txt" style="--sg-ico:var(--color-warning)">
|
|
998
1011
|
<svg class="ico" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2.5L18.5 17H1.5L10 2.5z"/><path d="M10 8v3.5"/><path d="M10 14.4v.1"/></svg>
|
|
999
1012
|
Warning</span><span class="lab">--color-warning</span></div>
|
|
1000
|
-
<div class="sg-tok"><span class="txt" style="
|
|
1013
|
+
<div class="sg-tok" data-token-sample="--color-error"><span class="txt" style="--sg-ico:var(--color-error)">
|
|
1001
1014
|
<svg class="ico" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M5 5l10 10M15 5L5 15"/></svg>
|
|
1002
1015
|
Error</span><span class="lab">--color-error</span></div>
|
|
1003
|
-
<div class="sg-tok"><span class="txt" style="
|
|
1016
|
+
<div class="sg-tok" data-token-sample="--color-info"><span class="txt" style="--sg-ico:var(--color-info)">
|
|
1004
1017
|
<svg class="ico" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10" cy="10" r="8"/><path d="M10 9v5"/><path d="M10 6v.1"/></svg>
|
|
1005
1018
|
Info</span><span class="lab">--color-info</span></div>
|
|
1006
1019
|
</div>
|
|
1007
1020
|
|
|
1008
|
-
<p class="
|
|
1021
|
+
<p class="sg-cap" style="margin:22px 0 8px">Interaction states — CTA hover, disabled, loading, focus ring, tap-target</p>
|
|
1009
1022
|
<div class="sg-tok-state">
|
|
1010
1023
|
<button class="sg-tok-btn" type="button">Primary CTA</button>
|
|
1011
1024
|
<button class="sg-tok-btn" type="button" style="background:var(--color-primary-hover)">Hover</button>
|
|
@@ -1016,7 +1029,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1016
1029
|
<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 3h2l1.6 9.2a1 1 0 001 .8h7.6a1 1 0 001-.8L18 6H5"/><circle cx="8" cy="17" r="1"/><circle cx="15" cy="17" r="1"/></svg>
|
|
1017
1030
|
</button>
|
|
1018
1031
|
</div>
|
|
1019
|
-
<p class="
|
|
1032
|
+
<p class="sg-cap" style="margin-top:10px;color:var(--color-muted)">Fill/hover read <code>--color-primary</code>/<code>--color-primary-hover</code>; disabled reads <code>--color-disabled</code> + <code>--color-disabled-contrast</code>; the field outline reads <code>--color-field-border</code>; Tab shows the <code>--color-focus-ring</code> ring; the icon button is sized to <code>--tap-target</code> (≥44px).</p>
|
|
1020
1033
|
</section>
|
|
1021
1034
|
|
|
1022
1035
|
<section class="sg-block">
|
|
@@ -1128,7 +1141,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1128
1141
|
allHref="#"
|
|
1129
1142
|
allActive={false}
|
|
1130
1143
|
/>
|
|
1131
|
-
<p class="
|
|
1144
|
+
<p class="sg-cap" style="margin-top:8px;color:var(--color-muted)">Active chip is filled + <code>aria-current</code>; each chip is a plain link so filtering works server-side.</p>
|
|
1132
1145
|
</section>
|
|
1133
1146
|
|
|
1134
1147
|
<section class="sg-block">
|
|
@@ -1172,9 +1185,9 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1172
1185
|
<section class="sg-block">
|
|
1173
1186
|
<p class="sg-h">Chrome — MegaMenu / NavDropdown (multi-column + caret + NEW badge)</p>
|
|
1174
1187
|
<div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:8px;padding:8px 16px">
|
|
1175
|
-
<MegaMenu items={sampleNav} class="!block" />
|
|
1188
|
+
<MegaMenu items={sampleNav} ariaLabel="Primary (MegaMenu sample)" class="!block" />
|
|
1176
1189
|
</div>
|
|
1177
|
-
<p class="
|
|
1190
|
+
<p class="sg-cap" style="margin-top:8px;color:var(--color-muted)">Hover/focus a caret item to reveal its dropdown (CSS-only).</p>
|
|
1178
1191
|
</section>
|
|
1179
1192
|
|
|
1180
1193
|
<section class="sg-block">
|
|
@@ -1192,7 +1205,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1192
1205
|
))}
|
|
1193
1206
|
</ul>
|
|
1194
1207
|
</div>
|
|
1195
|
-
<p class="
|
|
1208
|
+
<p class="sg-cap" style="margin-top:8px;color:var(--color-muted)">Same nav items in the mobile menu: mega columns become inline <code><details></code> accordions (keyboard + touch operable). Toggle a caret item to expand.</p>
|
|
1196
1209
|
</section>
|
|
1197
1210
|
|
|
1198
1211
|
<section class="sg-block">
|
|
@@ -1219,20 +1232,25 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1219
1232
|
<p class="sg-h">Compliance notices — <code>components/compliance/</code></p>
|
|
1220
1233
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Data-driven regulated-commerce notices with fixed/mandated legal wording. Rendered here from sample config; each is invisible when its tenant.compliance field is absent.</p>
|
|
1221
1234
|
|
|
1222
|
-
<p class="
|
|
1223
|
-
|
|
1224
|
-
|
|
1235
|
+
<p class="sg-cap" style="margin:18px 0 8px">NicotineWarning — <code>data-compliance="nicotine-warning"</code> (FDA 21 CFR 1143.3, fixed wording; one row per validated <code>compliance.nicotineWarning.preset</code>)</p>
|
|
1236
|
+
{Object.keys(NICOTINE_WARNING_PRESETS).map((preset) => (
|
|
1237
|
+
<div class="mt-3">
|
|
1238
|
+
<p class="sg-cap" style="margin:0 0 4px"><code>"preset": "{preset}"</code></p>
|
|
1239
|
+
<NicotineWarning variant="bar" declaration={{ preset }} />
|
|
1240
|
+
<div class="mt-3"><NicotineWarning variant="block" declaration={{ preset }} /></div>
|
|
1241
|
+
</div>
|
|
1242
|
+
))}
|
|
1225
1243
|
|
|
1226
|
-
<p class="
|
|
1244
|
+
<p class="sg-cap" style="margin:22px 0 8px">PactActNotice — <code>data-compliance="pact-act"</code> (bar / block / footer)</p>
|
|
1227
1245
|
<PactActNotice enabled minAge={21} variant="bar" />
|
|
1228
1246
|
<div class="mt-3"><PactActNotice enabled minAge={21} variant="block" /></div>
|
|
1229
1247
|
<div class="mt-3"><PactActNotice enabled minAge={21} variant="footer" /></div>
|
|
1230
1248
|
|
|
1231
|
-
<p class="
|
|
1249
|
+
<p class="sg-cap" style="margin:22px 0 8px">AdultSignatureNotice — <code>data-compliance="adult-signature"</code> (inline / block)</p>
|
|
1232
1250
|
<AdultSignatureNotice enabled minAge={21} variant="inline" />
|
|
1233
1251
|
<div class="mt-3"><AdultSignatureNotice enabled minAge={21} variant="block" /></div>
|
|
1234
1252
|
|
|
1235
|
-
<p class="
|
|
1253
|
+
<p class="sg-cap" style="margin:22px 0 8px">Prop65Warning — <code>data-compliance="prop65"</code> (short + long form, mandated skeleton)</p>
|
|
1236
1254
|
<Prop65Warning config={true} variant="block" />
|
|
1237
1255
|
<div class="mt-3">
|
|
1238
1256
|
<Prop65Warning
|
|
@@ -1242,7 +1260,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1242
1260
|
</div>
|
|
1243
1261
|
<div class="mt-3"><Prop65Warning config={true} variant="bar" /></div>
|
|
1244
1262
|
|
|
1245
|
-
<p class="
|
|
1263
|
+
<p class="sg-cap" style="margin:22px 0 8px">PurchaseLimitNotice — <code>data-compliance="purchase-limit"</code> (display only; enforcement is product-owned)</p>
|
|
1246
1264
|
<PurchaseLimitNotice
|
|
1247
1265
|
config={{ text: "2 units per order", reason: "per state law" }}
|
|
1248
1266
|
variant="inline"
|
|
@@ -1254,7 +1272,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1254
1272
|
/>
|
|
1255
1273
|
</div>
|
|
1256
1274
|
|
|
1257
|
-
<p class="
|
|
1275
|
+
<p class="sg-cap" style="margin:22px 0 8px">StateEligibilityNotice — <code>data-compliance="state-eligibility"</code> (display only; the eligibility decision is product-owned)</p>
|
|
1258
1276
|
<StateEligibilityNotice
|
|
1259
1277
|
config={{ restrictedStates: ["UT", "AR", "VT"] }}
|
|
1260
1278
|
variant="block"
|
|
@@ -1266,7 +1284,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1266
1284
|
/>
|
|
1267
1285
|
</div>
|
|
1268
1286
|
|
|
1269
|
-
<p class="
|
|
1287
|
+
<p class="sg-cap" style="margin:22px 0 8px">ShippingRestrictionNotice — <code>data-compliance="shipping-restriction"</code> (the platform footer band; display only)</p>
|
|
1270
1288
|
<ShippingRestrictionNotice
|
|
1271
1289
|
text="Adult signature (21+) required on delivery. Not shipped via USPS."
|
|
1272
1290
|
variant="footer"
|
|
@@ -1278,7 +1296,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1278
1296
|
/>
|
|
1279
1297
|
</div>
|
|
1280
1298
|
|
|
1281
|
-
<p class="
|
|
1299
|
+
<p class="sg-cap" style="margin:22px 0 8px">ExciseTaxNotice — <code>data-compliance="excise-tax"</code> (display cue only; the tax calculation is product-owned)</p>
|
|
1282
1300
|
<ExciseTaxNotice
|
|
1283
1301
|
config={{ note: "Applicable state vapor excise taxes are calculated at checkout." }}
|
|
1284
1302
|
variant="inline"
|
|
@@ -1309,7 +1327,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1309
1327
|
<p class="sg-h">Membership tiers — <code>components/membership/</code></p>
|
|
1310
1328
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Education-only tier comparison with a first-class illustrative-figures affordance. Guest shows a real $0; Member/Autopilot figures are illustrative examples, so the guide exercises both the affordance and the opt-out.</p>
|
|
1311
1329
|
|
|
1312
|
-
<p class="
|
|
1330
|
+
<p class="sg-cap" style="margin:18px 0 8px">TierCards — <code>data-widget="tier-cards"</code> (illustrative badge + "e.g." + footnote; featured ribbon)</p>
|
|
1313
1331
|
<TierCards
|
|
1314
1332
|
eyebrow="Membership"
|
|
1315
1333
|
heading="Choose how you shop"
|
|
@@ -1317,7 +1335,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1317
1335
|
tiers={sampleTiers}
|
|
1318
1336
|
/>
|
|
1319
1337
|
|
|
1320
|
-
<p class="
|
|
1338
|
+
<p class="sg-cap" style="margin:28px 0 8px">TierComparisonTable — <code>data-widget="tier-comparison-table"</code> (feature matrix; check/dash/text/em-dash cells)</p>
|
|
1321
1339
|
<TierComparisonTable
|
|
1322
1340
|
eyebrow="Compare"
|
|
1323
1341
|
heading="What each tier includes"
|
|
@@ -1337,19 +1355,19 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1337
1355
|
<p class="sg-h">Structured content — <code>components/content/</code></p>
|
|
1338
1356
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Data-driven framework widgets (F4): a policy page rendered from structured <code>sections</code> with no HTML/CSS to copy. Accessibility lives in the components; tenant content is pure data.</p>
|
|
1339
1357
|
|
|
1340
|
-
<p class="
|
|
1358
|
+
<p class="sg-cap" style="margin:18px 0 8px">TrustStrip — <code>data-widget="trust-strip"</code> (f09 real-or-absent: 2 claims + 1 real rating shown; a "Based on 369 reviews" claim + a half-populated rating are dropped, never fabricated)</p>
|
|
1341
1359
|
<TrustStrip items={sampleTrustStrip} />
|
|
1342
1360
|
|
|
1343
|
-
<p class="
|
|
1361
|
+
<p class="sg-cap" style="margin:28px 0 8px">Callout — <code>data-widget="callout"</code> (tones: info / warning / legal / success; role="note", token-tinted, mirrors f05 .disclaimer/.warn-band)</p>
|
|
1344
1362
|
<Callout callout={{ tone: "info", title: "Heads up", body: "An informational aside rendered from data." }} />
|
|
1345
1363
|
<Callout callout={{ tone: "warning", body: "A caution — check this before you rely on it." }} />
|
|
1346
1364
|
<Callout callout={{ tone: "legal", body: "Restricted to adults 21+ where lawful. Void where prohibited." }} />
|
|
1347
1365
|
<Callout callout={{ tone: "success", body: "Your terminal is verified and signed in." }} />
|
|
1348
1366
|
|
|
1349
|
-
<p class="
|
|
1367
|
+
<p class="sg-cap" style="margin:28px 0 8px">NeedsReviewCallout — <code>data-widget="needs-review"</code> (reviewer-only; a placeholder pending human sign-off before go-live — never shown to shoppers)</p>
|
|
1350
1368
|
<NeedsReviewCallout flag={{ reason: "Refund window (14 vs 30 days) not confirmed with merchant.", severity: "blocker", owner: "ops", href: "#" }} />
|
|
1351
1369
|
|
|
1352
|
-
<p class="
|
|
1370
|
+
<p class="sg-cap" style="margin:28px 0 8px">ProseToc — <code>data-widget="prose-toc"</code> + ProseSections — <code>data-widget="prose-sections"</code> (a full structured policy body: headings, rich-text links, list, glossary <dl>, callouts, <address> contact; needs-review shown here because the guide is preview)</p>
|
|
1353
1371
|
<ProseToc sections={sampleProseSections} min={2} />
|
|
1354
1372
|
<ProseSections sections={sampleProseSections} includeNeedsReview={true} />
|
|
1355
1373
|
</section>
|
|
@@ -1365,7 +1383,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1365
1383
|
<p class="sg-h">Subscription/Autopilot education — <code>components/subscription/</code></p>
|
|
1366
1384
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Education-only widgets that explain recurring/Autopilot ordering and hand off to the tenant's own manage-subscription flow. No subscription, billing, or scheduling mechanics of their own.</p>
|
|
1367
1385
|
|
|
1368
|
-
<p class="
|
|
1386
|
+
<p class="sg-cap" style="margin:18px 0 8px">HowItWorksSteps — <code>data-widget="subscription-how-it-works"</code></p>
|
|
1369
1387
|
<HowItWorksSteps
|
|
1370
1388
|
eyebrow="Autopilot"
|
|
1371
1389
|
heading="How Autopilot works"
|
|
@@ -1373,7 +1391,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1373
1391
|
steps={sampleSubscriptionSteps}
|
|
1374
1392
|
/>
|
|
1375
1393
|
|
|
1376
|
-
<p class="
|
|
1394
|
+
<p class="sg-cap" style="margin:28px 0 8px">SavingsExplainer — <code>data-widget="subscription-savings-explainer"</code> (illustrative badge + "e.g." + footnote)</p>
|
|
1377
1395
|
<SavingsExplainer
|
|
1378
1396
|
eyebrow="Autopilot savings"
|
|
1379
1397
|
heading="Save on every order"
|
|
@@ -1382,7 +1400,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1382
1400
|
cta={{ label: "How Autopilot works", href: "#" }}
|
|
1383
1401
|
/>
|
|
1384
1402
|
|
|
1385
|
-
<p class="
|
|
1403
|
+
<p class="sg-cap" style="margin:28px 0 8px">ManageSubscriptionEntry — <code>data-widget="subscription-manage-entry"</code></p>
|
|
1386
1404
|
<ManageSubscriptionEntry
|
|
1387
1405
|
eyebrow="Manage"
|
|
1388
1406
|
heading="Manage your Autopilot"
|
|
@@ -1398,10 +1416,10 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1398
1416
|
<p class="sg-h">Islands — <code>components/islands/</code></p>
|
|
1399
1417
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Client-hydrated Preact islands exercised with fixture data — no live catalog, cart, or ToT calls.</p>
|
|
1400
1418
|
|
|
1401
|
-
<p class="
|
|
1419
|
+
<p class="sg-cap" style="margin:18px 0 8px">AgeGate — full-viewport 21+ affirmation (real overlay; dismiss it once to keep browsing the guide, same as a real visitor)</p>
|
|
1402
1420
|
<AgeGate client:load minAge={21} brand={t.name} tenantId={tenant ?? "style-guide"} />
|
|
1403
1421
|
|
|
1404
|
-
<p class="
|
|
1422
|
+
<p class="sg-cap" style="margin:22px 0 8px">VariantSelector — PDP option picker (radiogroup + live price/SKU/stock region)</p>
|
|
1405
1423
|
<VariantSelector
|
|
1406
1424
|
client:load
|
|
1407
1425
|
variants={sampleFromProduct.variants}
|
|
@@ -1410,24 +1428,24 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1410
1428
|
locale="en-US"
|
|
1411
1429
|
/>
|
|
1412
1430
|
|
|
1413
|
-
<p class="
|
|
1431
|
+
<p class="sg-cap" style="margin:22px 0 8px">QuickView — global peek dialog (opens from any <code>[data-quickview]</code> button, e.g. a ProductCard above)</p>
|
|
1414
1432
|
<QuickView client:idle locale="en-US" />
|
|
1415
1433
|
|
|
1416
|
-
<p class="
|
|
1434
|
+
<p class="sg-cap" style="margin:22px 0 8px">SearchTypeahead — header search combobox (debounced, ARIA listbox)</p>
|
|
1417
1435
|
<div style="max-width:22rem">
|
|
1418
|
-
<SearchTypeahead client:idle />
|
|
1436
|
+
<SearchTypeahead client:idle label="Search (typeahead sample)" />
|
|
1419
1437
|
</div>
|
|
1420
1438
|
|
|
1421
|
-
<p class="
|
|
1439
|
+
<p class="sg-cap" style="margin:22px 0 8px">MobileNav — hamburger + slide-in drawer (mobile-only chrome, hidden ≥768px by design; resize below 768px or use responsive dev tools to preview the drawer)</p>
|
|
1422
1440
|
<div style="max-width:20rem">
|
|
1423
1441
|
<MobileNav client:idle nav={sampleMobileNav} announcement="Free US shipping on orders over $100" />
|
|
1424
1442
|
</div>
|
|
1425
1443
|
|
|
1426
|
-
<p class="
|
|
1444
|
+
<p class="sg-cap" style="margin:22px 0 8px">RecentlyViewed — localStorage discovery rail, seeded here for preview (renders empty on a real first visit until a product is viewed)</p>
|
|
1427
1445
|
<script is:inline nonce={cspNonce} set:html={`localStorage.setItem("tot:recently-viewed", ${JSON.stringify(JSON.stringify(sampleRecentlyViewed))}); localStorage.setItem("tot:wishlist", ${JSON.stringify(JSON.stringify(sampleRecentlyViewed.slice(0, 2)))});`} />
|
|
1428
1446
|
<RecentlyViewed client:idle locale="en-US" />
|
|
1429
1447
|
|
|
1430
|
-
<p class="
|
|
1448
|
+
<p class="sg-cap" style="margin:22px 0 8px">SavedList — the <code>/saved</code> wishlist, seeded here for preview (empty state shown until an item is saved)</p>
|
|
1431
1449
|
<SavedList client:only="preact" locale="en-US" />
|
|
1432
1450
|
</section>
|
|
1433
1451
|
|
|
@@ -1442,12 +1460,12 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1442
1460
|
<FacetSidebar facets={sampleFacets} query={samplePlpQuery} basePath="#" />
|
|
1443
1461
|
<div>
|
|
1444
1462
|
<div class="sg-row" style="justify-content:space-between;margin-bottom:14px">
|
|
1445
|
-
<p class="
|
|
1463
|
+
<p class="sg-cap" style="margin:0">SortSelect</p>
|
|
1446
1464
|
<SortSelect query={samplePlpQuery} basePath="#" />
|
|
1447
1465
|
</div>
|
|
1448
|
-
<p class="
|
|
1466
|
+
<p class="sg-cap" style="margin:0 0 8px">ActiveFilters</p>
|
|
1449
1467
|
<ActiveFilters query={samplePlpQuery} basePath="#" />
|
|
1450
|
-
<p class="
|
|
1468
|
+
<p class="sg-cap" style="margin:22px 0 8px">Pagination</p>
|
|
1451
1469
|
<Pagination query={samplePlpQuery} basePath="#" page={2} pageSize={12} total={58} />
|
|
1452
1470
|
</div>
|
|
1453
1471
|
</div>
|
|
@@ -1461,13 +1479,13 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1461
1479
|
<p class="sg-h">Home hero — <code>components/home/Hero.astro</code></p>
|
|
1462
1480
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">The homepage "thesis" moment. Bold is the default; light matches merchants whose own site favors a light page with brand-color accents.</p>
|
|
1463
1481
|
|
|
1464
|
-
<p class="
|
|
1482
|
+
<p class="sg-cap" style="margin:18px 0 8px">Bold (default)</p>
|
|
1465
1483
|
{setHeroVariant("bold")}
|
|
1466
|
-
<Hero block={sampleHeroBlock} featureProduct={sampleHeroFeatureProduct} />
|
|
1484
|
+
<Hero block={sampleHeroBlock} featureProduct={sampleHeroFeatureProduct} headingLevel={2} />
|
|
1467
1485
|
|
|
1468
|
-
<p class="
|
|
1486
|
+
<p class="sg-cap" style="margin:22px 0 8px">Light</p>
|
|
1469
1487
|
{setHeroVariant("light")}
|
|
1470
|
-
<Hero block={sampleHeroBlock} featureProduct={sampleHeroFeatureProduct} />
|
|
1488
|
+
<Hero block={sampleHeroBlock} featureProduct={sampleHeroFeatureProduct} headingLevel={2} />
|
|
1471
1489
|
</section>
|
|
1472
1490
|
|
|
1473
1491
|
{/* ── Marketing blocks (components/marketing/) ────────────────────────
|
|
@@ -1483,15 +1501,8 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1483
1501
|
</div>
|
|
1484
1502
|
</main>
|
|
1485
1503
|
|
|
1486
|
-
<footer class="
|
|
1487
|
-
<
|
|
1488
|
-
<div class="foot-grid">
|
|
1489
|
-
<div><b>{t.name}</b><p class="copyright">Footer chrome sample · theme preview only.</p></div>
|
|
1490
|
-
<div><h3>Platform</h3><ul><li><a href="#">Identity Verification</a></li><li><a href="#">Age Assurance</a></li></ul></div>
|
|
1491
|
-
<div><h3>Industries</h3><ul><li><a href="#">Alcohol & Tobacco</a></li><li><a href="#">Marketplaces</a></li></ul></div>
|
|
1492
|
-
<div><h3>Company</h3><ul><li><a href="#">Pricing</a></li><li><a href="#">Contact Sales</a></li></ul></div>
|
|
1493
|
-
</div>
|
|
1494
|
-
</div>
|
|
1504
|
+
<footer class="sg-foot">
|
|
1505
|
+
<p>{t.name} · theme preview only · noindex</p>
|
|
1495
1506
|
</footer>
|
|
1496
1507
|
</body>
|
|
1497
1508
|
</html>
|