@tokenoftrust/storefront-runner 1.3.4-rc.3 → 1.4.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/astro.config.mjs +15 -0
- package/apps/storefront/dev-plugins/dev-publish.mjs +55 -0
- package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +86 -7
- package/apps/storefront/drizzle.config.apps.ts +13 -0
- package/apps/storefront/env.d.ts +10 -0
- package/apps/storefront/migrations/README.md +13 -7
- package/apps/storefront/migrations-apps/0000_fast_millenium_guard.sql +129 -0
- package/apps/storefront/migrations-apps/meta/0000_snapshot.json +843 -0
- package/apps/storefront/migrations-apps/meta/_journal.json +13 -0
- package/apps/storefront/package.json +13 -1
- package/apps/storefront/perf/README.md +64 -0
- package/apps/storefront/perf/assert-budgets.ts +159 -0
- package/apps/storefront/playwright.config.ts +23 -0
- package/apps/storefront/public/js/dashboard-apps.js +173 -0
- package/apps/storefront/public/shared/commerce-marketing.css +221 -0
- package/apps/storefront/src/components/CollectionCard.astro +1 -0
- package/apps/storefront/src/components/ProductCard.astro +1 -0
- package/apps/storefront/src/components/admin/AdminPublishTab.astro +1959 -0
- package/apps/storefront/src/components/apps/AppWidgetFrame.astro +30 -0
- package/apps/storefront/src/components/chrome/NavDropdown.astro +6 -3
- package/apps/storefront/src/components/chrome/SiteFooter.astro +10 -0
- package/apps/storefront/src/components/chrome/SiteHeader.astro +10 -0
- package/apps/storefront/src/components/commerce/RatingStars.astro +3 -2
- package/apps/storefront/src/components/content/Callout.astro +75 -0
- package/apps/storefront/src/components/content/NeedsReviewCallout.astro +66 -0
- package/apps/storefront/src/components/content/ProseSections.astro +121 -0
- package/apps/storefront/src/components/content/ProseToc.astro +34 -0
- package/apps/storefront/src/components/content/RichText.astro +44 -0
- package/apps/storefront/src/components/content/TrustStrip.astro +46 -0
- package/apps/storefront/src/components/home/Hero.astro +14 -0
- package/apps/storefront/src/components/islands/CheckoutComplianceGate.tsx +295 -0
- package/apps/storefront/src/components/islands/ImageGallery.tsx +42 -21
- package/apps/storefront/src/components/islands/VariantSelector.tsx +62 -12
- package/apps/storefront/src/components/plp/FacetSidebar.astro +2 -2
- package/apps/storefront/src/components/subscription/ManageSubscriptionEntry.astro +1 -0
- package/apps/storefront/src/config/compliance/rulesets.ts +79 -0
- package/apps/storefront/src/config/storeName.ts +34 -0
- package/apps/storefront/src/layouts/Layout.astro +97 -23
- package/apps/storefront/src/lib/analytics/budgets.json +69 -0
- package/apps/storefront/src/lib/analytics/lighthouseReport.ts +109 -0
- package/apps/storefront/src/lib/analytics/perfBudgets.ts +452 -0
- package/apps/storefront/src/lib/analytics/rumAlert.ts +179 -0
- package/apps/storefront/src/lib/analytics/webVitals.ts +269 -0
- package/apps/storefront/src/lib/apps/adminService.ts +106 -0
- package/apps/storefront/src/lib/apps/adminSession.ts +205 -0
- package/apps/storefront/src/lib/apps/apiAuth.ts +91 -0
- package/apps/storefront/src/lib/apps/apiRoute.ts +35 -0
- package/apps/storefront/src/lib/apps/catalogMapper.ts +39 -0
- package/apps/storefront/src/lib/apps/credentials.ts +153 -0
- package/apps/storefront/src/lib/apps/gatewayKeys.ts +156 -0
- package/apps/storefront/src/lib/apps/healthAggregate.ts +66 -0
- package/apps/storefront/src/lib/apps/orders/attributionService.ts +206 -0
- package/apps/storefront/src/lib/apps/orders/customerHash.ts +28 -0
- package/apps/storefront/src/lib/apps/orders/foxyOrderClient.ts +203 -0
- package/apps/storefront/src/lib/apps/orders/idempotency.ts +100 -0
- package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +117 -0
- package/apps/storefront/src/lib/apps/orders/orderMapper.ts +91 -0
- package/apps/storefront/src/lib/apps/orders/ordersStore.ts +181 -0
- package/apps/storefront/src/lib/apps/registryService.ts +579 -0
- package/apps/storefront/src/lib/apps/scopes.ts +79 -0
- package/apps/storefront/src/lib/apps/tokenIssuer.ts +121 -0
- package/apps/storefront/src/lib/apps/tokenVerifier.ts +148 -0
- package/apps/storefront/src/lib/apps/widgets/eligibility.ts +18 -0
- package/apps/storefront/src/lib/apps/widgets/frameProps.ts +52 -0
- package/apps/storefront/src/lib/apps/widgets/launchToken.ts +84 -0
- package/apps/storefront/src/lib/apps/widgets/placements.ts +57 -0
- package/apps/storefront/src/lib/apps/widgets/renderSlot.ts +111 -0
- package/apps/storefront/src/lib/auth/adminEntry.ts +119 -0
- package/apps/storefront/src/lib/auth/identityToken.ts +21 -2
- package/apps/storefront/src/lib/auth/loginGate.ts +102 -18
- package/apps/storefront/src/lib/auth/mcpClientAssertion.ts +215 -0
- package/apps/storefront/src/lib/auth/route.ts +16 -1
- package/apps/storefront/src/lib/auth/session.ts +8 -0
- package/apps/storefront/src/lib/auth/stepUpChallenge.ts +107 -0
- package/apps/storefront/src/lib/auth/totAccessClient.ts +208 -0
- package/apps/storefront/src/lib/blog/provider.ts +39 -0
- package/apps/storefront/src/lib/blog/types.ts +26 -0
- package/apps/storefront/src/lib/checkoutCommerce.ts +39 -1
- package/apps/storefront/src/lib/chrome/model.ts +11 -0
- package/apps/storefront/src/lib/compliance/enforcement.ts +95 -0
- package/apps/storefront/src/lib/content/callout.ts +78 -0
- package/apps/storefront/src/lib/content/index.ts +27 -0
- package/apps/storefront/src/lib/content/needsReview.ts +58 -0
- package/apps/storefront/src/lib/content/prose.ts +186 -0
- package/apps/storefront/src/lib/content/richtext.ts +76 -0
- package/apps/storefront/src/lib/content/trustStrip.ts +74 -0
- package/apps/storefront/src/lib/content-edit/client.ts +70 -14
- package/apps/storefront/src/lib/d1/catalog.ts +12 -0
- package/apps/storefront/src/lib/d1/schema-apps.ts +213 -0
- package/apps/storefront/src/lib/dev/apiBase.ts +8 -2
- package/apps/storefront/src/lib/dev/cliSignInCode.ts +65 -115
- package/apps/storefront/src/lib/dev/cockpitStore.ts +65 -0
- package/apps/storefront/src/lib/dev/obstacleStore.ts +214 -0
- package/apps/storefront/src/lib/dev/previewStatus.ts +112 -0
- package/apps/storefront/src/lib/dev/rendezvousBroker.ts +241 -0
- package/apps/storefront/src/lib/dev/subjectReissue.ts +67 -0
- package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +10 -10
- package/apps/storefront/src/lib/env.ts +12 -0
- package/apps/storefront/src/lib/jsonld.ts +12 -17
- package/apps/storefront/src/lib/membership/eligibility.ts +37 -0
- package/apps/storefront/src/lib/monitoring/manifest.ts +302 -0
- package/apps/storefront/src/lib/privacy/emailHint.ts +13 -5
- package/apps/storefront/src/lib/publish/apex-readiness.ts +337 -0
- package/apps/storefront/src/lib/publish/dispatchHealth.ts +269 -0
- package/apps/storefront/src/lib/publish/domainState.ts +351 -0
- package/apps/storefront/src/lib/publish/shipWorkspace.ts +362 -0
- package/apps/storefront/src/lib/rawChrome.ts +34 -3
- package/apps/storefront/src/lib/storyblok/content-model.ts +34 -2
- package/apps/storefront/src/lib/storyblok/provider.ts +11 -4
- package/apps/storefront/src/lib/subscription/model.ts +114 -0
- package/apps/storefront/src/lib/tot/ToTClient.ts +3 -3
- package/apps/storefront/src/lib/tot/query.ts +32 -0
- package/apps/storefront/src/lib/webhooks/cloudflareQueueDispatcher.ts +82 -0
- package/apps/storefront/src/lib/webhooks/deliveryEngine.ts +245 -0
- package/apps/storefront/src/lib/webhooks/deliveryMapper.ts +34 -0
- package/apps/storefront/src/lib/webhooks/deliveryStore.ts +668 -0
- package/apps/storefront/src/lib/webhooks/dispatcher.ts +168 -0
- package/apps/storefront/src/lib/webhooks/emit.ts +167 -0
- package/apps/storefront/src/lib/webhooks/endpointGuard.ts +135 -0
- package/apps/storefront/src/lib/webhooks/events.ts +98 -0
- package/apps/storefront/src/lib/webhooks/getDispatcher.ts +49 -0
- package/apps/storefront/src/lib/webhooks/signing.ts +29 -0
- package/apps/storefront/src/lib/webhooks/webhookSigningKey.ts +146 -0
- package/apps/storefront/src/middleware/index.ts +28 -13
- package/apps/storefront/src/pages/404.astro +21 -9
- package/apps/storefront/src/pages/[...slug].astro +36 -2
- package/apps/storefront/src/pages/admin.astro +29 -3
- package/apps/storefront/src/pages/api/apps/admin/credentials/rotate.ts +60 -0
- package/apps/storefront/src/pages/api/apps/admin/health.ts +44 -0
- package/apps/storefront/src/pages/api/apps/admin/install.ts +100 -0
- package/apps/storefront/src/pages/api/apps/admin/list.ts +26 -0
- package/apps/storefront/src/pages/api/apps/admin/resume.ts +56 -0
- package/apps/storefront/src/pages/api/apps/admin/suspend.ts +57 -0
- package/apps/storefront/src/pages/api/apps/admin/uninstall.ts +74 -0
- package/apps/storefront/src/pages/api/apps/admin/update.ts +103 -0
- package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries/[deliveryId]/replay.ts +59 -0
- package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries.ts +51 -0
- package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +172 -0
- package/apps/storefront/src/pages/api/apps/oauth/token.ts +87 -0
- package/apps/storefront/src/pages/api/apps/v1/attribution.ts +142 -0
- package/apps/storefront/src/pages/api/apps/v1/catalog/products/[handle].ts +39 -0
- package/apps/storefront/src/pages/api/apps/v1/catalog/products.ts +49 -0
- package/apps/storefront/src/pages/api/apps/v1/health.ts +32 -0
- package/apps/storefront/src/pages/api/apps/v1/inventory.ts +59 -0
- package/apps/storefront/src/pages/api/apps/v1/orders/[id].ts +48 -0
- package/apps/storefront/src/pages/api/apps/v1/orders.ts +73 -0
- package/apps/storefront/src/pages/api/apps/v1/reports.ts +21 -0
- package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries/[deliveryId]/replay.ts +62 -0
- package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries.ts +47 -0
- package/apps/storefront/src/pages/api/auth/magic-exchange.ts +48 -1
- package/apps/storefront/src/pages/api/auth/step-up-send.ts +57 -0
- package/apps/storefront/src/pages/api/auth/step-up-verify.ts +129 -0
- package/apps/storefront/src/pages/api/auth/verify.ts +23 -0
- package/apps/storefront/src/pages/api/compliance/preflight.ts +206 -0
- package/apps/storefront/src/pages/api/rum/vitals.ts +54 -0
- package/apps/storefront/src/pages/api/test/dev-session.ts +133 -0
- package/apps/storefront/src/pages/auth/login.astro +197 -41
- package/apps/storefront/src/pages/auth/magic.astro +75 -43
- package/apps/storefront/src/pages/blog/[slug].astro +107 -0
- package/apps/storefront/src/pages/blog/index.astro +98 -0
- package/apps/storefront/src/pages/capabilities.astro +8 -0
- package/apps/storefront/src/pages/cockpit.astro +496 -74
- package/apps/storefront/src/pages/collections/[handle].astro +8 -0
- package/apps/storefront/src/pages/collections/index.astro +10 -2
- package/apps/storefront/src/pages/dashboard/[appDomain]/apps/index.astro +119 -0
- package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +5 -0
- package/apps/storefront/src/pages/index.astro +57 -0
- package/apps/storefront/src/pages/llms.txt.ts +31 -10
- package/apps/storefront/src/pages/products/[handle].astro +100 -9
- package/apps/storefront/src/pages/sitemap.xml.ts +21 -4
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +198 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +7 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +7 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +7 -0
- package/apps/storefront/src/pages/style-guide/index.astro +10 -0
- package/apps/storefront/src/styles/fonts.css +54 -0
- package/apps/storefront/src/styles/global.css +22 -2
- package/apps/storefront/src/themes/schema.ts +3 -25
- package/apps/storefront/tsconfig.json +1 -1
- package/apps/storefront/vitest.config.ts +4 -1
- package/package.json +1 -1
- package/packages/public-runtime/src/candidate-index.ts +311 -0
- package/packages/public-runtime/src/checkout.ts +94 -2
- package/packages/public-runtime/src/compliance/evaluate.ts +265 -0
- package/packages/public-runtime/src/compliance/evidence-signals.ts +81 -0
- package/packages/public-runtime/src/compliance/index.ts +22 -0
- package/packages/public-runtime/src/compliance/pact-report.ts +94 -0
- package/packages/public-runtime/src/compliance/profile.ts +198 -0
- package/packages/public-runtime/src/compliance/ruleset.ts +117 -0
- package/packages/public-runtime/src/compliance/verification.ts +81 -0
- package/packages/public-runtime/src/csp.ts +27 -3
- package/packages/public-runtime/src/customization-reconcile.ts +35 -0
- package/packages/public-runtime/src/customization-runtime.ts +8 -0
- package/packages/public-runtime/src/customization-versioning.ts +17 -0
- package/packages/public-runtime/src/extension-contract.ts +2 -1
- package/packages/public-runtime/src/hash.ts +25 -0
- package/packages/public-runtime/src/index.ts +6 -0
- package/packages/public-runtime/src/membership.ts +353 -0
- package/packages/public-runtime/src/product.ts +24 -2
- package/packages/public-runtime/src/review-trust-proof.ts +194 -0
- package/packages/public-runtime/src/tenant-assets.ts +40 -5
- package/packages/public-runtime/src/tenant.ts +236 -0
- package/packages/public-runtime/src/widget-postmessage.ts +205 -0
- package/scripts/dev/publish.mjs +158 -0
- package/scripts/dev/transient-files.mjs +2 -1
- package/tenants/home/public/fonts/inter-latin-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-ext-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-ext-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-ext-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-ext-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-ext-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-700-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-800-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-700-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-800-normal.woff2 +0 -0
- package/tenants/home/public/pages/storefront.css +23 -0
- package/apps/storefront/src/lib/dev/hostedCockpit.ts +0 -169
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
* (buttons, eyebrow, proof strip, footer, card) using the theme's real classes.
|
|
9
9
|
* noindex, never in the sitemap, never production marketing publishing. It does
|
|
10
10
|
* NOT reskin the live marketing pages — it only previews the theme in isolation.
|
|
11
|
+
*
|
|
12
|
+
* Left on-demand — NOT prerendered (audit finding "selective-prerender"). A dynamic
|
|
13
|
+
* [tenant]/[theme] route reading Astro.locals.cspNonce and depending on the middleware
|
|
14
|
+
* CSP + security headers; prerendering would need getStaticPaths AND lose those headers,
|
|
15
|
+
* for a dev/preview-only noindex surface with no production traffic (zero perf upside).
|
|
11
16
|
*/
|
|
17
|
+
export const prerender = false;
|
|
18
|
+
|
|
12
19
|
// Commerce + chrome component library preview. global.css brings the Tailwind
|
|
13
20
|
// utilities + reference theme-token fallbacks so the (token-styled) components
|
|
14
21
|
// render here without the app Layout. The `.sg-commerce` wrapper pins the
|
|
@@ -45,6 +52,13 @@ import ShippingRestrictionNotice from "@/components/compliance/ShippingRestricti
|
|
|
45
52
|
import ExciseTaxNotice from "@/components/compliance/ExciseTaxNotice.astro";
|
|
46
53
|
import TierCards from "@/components/membership/TierCards.astro";
|
|
47
54
|
import TierComparisonTable from "@/components/membership/TierComparisonTable.astro";
|
|
55
|
+
import ProseSections from "@/components/content/ProseSections.astro";
|
|
56
|
+
import ProseToc from "@/components/content/ProseToc.astro";
|
|
57
|
+
import Callout from "@/components/content/Callout.astro";
|
|
58
|
+
import NeedsReviewCallout from "@/components/content/NeedsReviewCallout.astro";
|
|
59
|
+
import TrustStrip from "@/components/content/TrustStrip.astro";
|
|
60
|
+
import type { ProseSection } from "@/lib/content/prose";
|
|
61
|
+
import type { TrustStripItem } from "@/lib/content/trustStrip";
|
|
48
62
|
import HowItWorksSteps from "@/components/subscription/HowItWorksSteps.astro";
|
|
49
63
|
import SavingsExplainer from "@/components/subscription/SavingsExplainer.astro";
|
|
50
64
|
import ManageSubscriptionEntry from "@/components/subscription/ManageSubscriptionEntry.astro";
|
|
@@ -222,6 +236,73 @@ const sampleComparisonRows: ComparisonRow[] = [
|
|
|
222
236
|
{ label: "Cancel anytime", cells: [null, true, true] },
|
|
223
237
|
];
|
|
224
238
|
|
|
239
|
+
// --- Sample structured content (F4) — the DATA a policy page is driven by,
|
|
240
|
+
// replacing a hand-authored HTML/CSS fragment. Exercises headings (TOC),
|
|
241
|
+
// rich-text links, lists, a definition glossary, tone callouts, a contact
|
|
242
|
+
// block, and a needs-review flag (reviewer-only). ---------------------------
|
|
243
|
+
const sampleProseSections: ProseSection[] = [
|
|
244
|
+
{ kind: "heading", text: "Overview" },
|
|
245
|
+
{
|
|
246
|
+
kind: "paragraph",
|
|
247
|
+
text: [
|
|
248
|
+
{ kind: "text", text: "This page is rendered from " },
|
|
249
|
+
{ kind: "text", text: "structured data", strong: true },
|
|
250
|
+
{ kind: "text", text: ", not an HTML blob. See our " },
|
|
251
|
+
{ kind: "link", text: "privacy policy", href: "/policies/privacy" },
|
|
252
|
+
{ kind: "text", text: " and the " },
|
|
253
|
+
{ kind: "link", text: "framework docs", href: "https://tokenoftrust.com" },
|
|
254
|
+
{ kind: "text", text: " for details." },
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
kind: "callout",
|
|
259
|
+
tone: "info",
|
|
260
|
+
title: "Good to know",
|
|
261
|
+
body: "Every color here comes from the theme tokens — reskin it by swapping tokens, not markup.",
|
|
262
|
+
},
|
|
263
|
+
{ kind: "heading", text: "What we collect" },
|
|
264
|
+
{
|
|
265
|
+
kind: "list",
|
|
266
|
+
items: ["Contact details you provide", "Order history", "Age-verification status"],
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
kind: "definitions",
|
|
270
|
+
items: [
|
|
271
|
+
{ term: "PII", description: "Personal information that identifies you." },
|
|
272
|
+
{ term: "Age gate", description: "The 21+ affirmation shown before browsing." },
|
|
273
|
+
],
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
kind: "callout",
|
|
277
|
+
tone: "legal",
|
|
278
|
+
body: "Sales are restricted to adults 21+ where lawful. Void where prohibited.",
|
|
279
|
+
},
|
|
280
|
+
{ kind: "heading", text: "Contact us" },
|
|
281
|
+
{
|
|
282
|
+
kind: "contact",
|
|
283
|
+
heading: "Support",
|
|
284
|
+
email: "support@example.com",
|
|
285
|
+
phone: "+1 (555) 010-2030",
|
|
286
|
+
address: ["123 Market St", "Suite 200", "Denver, CO 80202"],
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
kind: "needs_review",
|
|
290
|
+
reason: "Refund window (14 vs 30 days) not yet confirmed with the merchant.",
|
|
291
|
+
severity: "blocker",
|
|
292
|
+
owner: "ops",
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
// Trust strip (F4, f09-guarded): mixes real claims + a real rating with
|
|
297
|
+
// fabrication vectors that MUST be dropped — the guide proves real-or-absent.
|
|
298
|
+
const sampleTrustStrip: TrustStripItem[] = [
|
|
299
|
+
{ kind: "claim", label: "Ships from USA" },
|
|
300
|
+
{ kind: "claim", label: "Lab-tested" },
|
|
301
|
+
{ kind: "rating", average: 4.9, count: 369, label: "avg rating" },
|
|
302
|
+
{ kind: "claim", label: "Based on 369 reviews" }, // fabricated → dropped by f09
|
|
303
|
+
{ kind: "rating", average: 5, count: 0 }, // half-populated → dropped
|
|
304
|
+
];
|
|
305
|
+
|
|
225
306
|
// --- Sample subscription/Autopilot education content (preview-only) -----------
|
|
226
307
|
const sampleSubscriptionSteps: SubscriptionStep[] = [
|
|
227
308
|
{ title: "Choose your products", description: "Pick anything in the catalog to add to your Autopilot." },
|
|
@@ -411,6 +492,14 @@ const REFERENCE_COMPONENT_VARS: Record<string, string> = {
|
|
|
411
492
|
"--color-muted": "#5c6663", "--color-primary": "#1f3a34", "--color-primary-contrast": "#f4f1ea",
|
|
412
493
|
"--color-accent": "#b5612f", "--color-border": "#dcd6c9", "--color-success": "#3f6b4f",
|
|
413
494
|
"--color-sale": "#9e3b2e",
|
|
495
|
+
// F1 semantic + F6 quality-bar interaction tokens — reference (Northwind)
|
|
496
|
+
// values so the text/icon-token samples render concretely and re-skin when a
|
|
497
|
+
// descriptor overrides them via preview.componentVars.
|
|
498
|
+
"--color-warning": "#8a5717", "--color-error": "#a22014", "--color-info": "#2c5b73",
|
|
499
|
+
"--color-accent-ink": "#8a481f",
|
|
500
|
+
"--color-focus-ring": "#b5612f", "--color-disabled": "#e4dfd4",
|
|
501
|
+
"--color-disabled-contrast": "#8b938f", "--color-field-border": "#8f887a",
|
|
502
|
+
"--color-star": "#b5612f", "--tap-target": "44px",
|
|
414
503
|
"--radius-sm": "3px", "--radius-md": "6px", "--radius-lg": "12px", "--radius-full": "999px",
|
|
415
504
|
"--shadow-sm": "0 1px 2px rgba(28,38,36,.06)", "--shadow-md": "0 6px 24px -8px rgba(28,38,36,.14)",
|
|
416
505
|
"--shadow-lg": "0 24px 60px -20px rgba(28,38,36,.22)", "--container-max": "1240px",
|
|
@@ -520,6 +609,31 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
520
609
|
}
|
|
521
610
|
.sg-commerce .sg-h { color: var(--color-primary); }
|
|
522
611
|
.sg-commerce .sg-block { border-top-color: var(--color-border); }
|
|
612
|
+
|
|
613
|
+
/* Semantic text & icon token samples (v1.1 · unit F6). Each swatch reads
|
|
614
|
+
ONE contract token so the guide proves text/icon roles resolve + re-skin
|
|
615
|
+
from tokens alone — never a hard-coded color. */
|
|
616
|
+
.sg-tok-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
|
|
617
|
+
.sg-tok { border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 12px 14px; background: var(--color-surface); }
|
|
618
|
+
.sg-tok .lab { display: block; font-size: .7rem; letter-spacing: .04em; color: var(--color-muted); font-family: var(--font-mono, ui-monospace, Menlo, monospace); margin-top: 6px; }
|
|
619
|
+
.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; }
|
|
620
|
+
.sg-tok .ico { width: 1.15em; height: 1.15em; flex: none; }
|
|
621
|
+
.sg-tok-state { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
|
|
622
|
+
/* Token-driven CTA + disabled/loading control (mirrors the shared button
|
|
623
|
+
contract: fill=--color-primary, hover=--color-primary-hover). */
|
|
624
|
+
.sg-tok-btn { display: inline-flex; align-items: center; justify-content: center; gap: .5em; min-height: var(--tap-target); padding: 0 1.4em; border-radius: var(--radius-full); border: 0; font-family: var(--font-display); font-weight: 700; font-size: .95rem; background: var(--color-primary); color: var(--color-primary-contrast); cursor: pointer; }
|
|
625
|
+
.sg-tok-btn:hover:not([disabled]) { background: var(--color-primary-hover); }
|
|
626
|
+
.sg-tok-btn[disabled] { background: var(--color-disabled); color: var(--color-disabled-contrast); cursor: not-allowed; }
|
|
627
|
+
.sg-tok-btn.is-loading { color: transparent; position: relative; }
|
|
628
|
+
.sg-tok-btn.is-loading::after { content: ""; position: absolute; width: 1.1em; height: 1.1em; border-radius: 999px; border: 2px solid var(--color-primary-contrast); border-top-color: transparent; animation: sg-spin .7s linear infinite; }
|
|
629
|
+
@keyframes sg-spin { to { transform: rotate(360deg); } }
|
|
630
|
+
@media (prefers-reduced-motion: reduce) { .sg-tok-btn.is-loading::after { animation: none; } }
|
|
631
|
+
/* Accessible field: stronger --color-field-border + token focus ring. */
|
|
632
|
+
.sg-tok-field { min-height: var(--tap-target); width: min(320px, 100%); padding: 0 12px; border-radius: var(--radius-md); border: var(--border-medium, 1.5px) solid var(--color-field-border); background: var(--color-surface); color: var(--color-text); font: inherit; }
|
|
633
|
+
.sg-tok-field:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
|
|
634
|
+
/* Tap-target demo: an icon button sized to the WCAG minimum. */
|
|
635
|
+
.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; }
|
|
636
|
+
.sg-tap svg { width: 20px; height: 20px; }
|
|
523
637
|
</style>
|
|
524
638
|
</head>
|
|
525
639
|
<body>
|
|
@@ -838,6 +952,62 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
838
952
|
</div>
|
|
839
953
|
</section>
|
|
840
954
|
|
|
955
|
+
{/* ── Semantic text & icon tokens (v1.1 · unit F6) ────────────────────
|
|
956
|
+
The quality-bar coverage sample: every text role, icon tint, and
|
|
957
|
+
interaction state renders from a NAMED contract token — nothing here
|
|
958
|
+
hard-codes a color or borrows `accent`. Swap the theme (or a
|
|
959
|
+
descriptor's preview.componentVars) and this whole slice re-skins,
|
|
960
|
+
which is exactly the bar a future tenant theme must clear. */}
|
|
961
|
+
<section class="sg-block">
|
|
962
|
+
<p class="sg-h">Semantic text & icon tokens (v1.1)</p>
|
|
963
|
+
<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>
|
|
964
|
+
|
|
965
|
+
<p class="form-help" style="margin:18px 0 8px">Text roles</p>
|
|
966
|
+
<div class="sg-tok-grid">
|
|
967
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-text)">Primary body text</span><span class="lab">--color-text</span></div>
|
|
968
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-muted)">Secondary / caption</span><span class="lab">--color-muted</span></div>
|
|
969
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-primary)">Brand / link anchor</span><span class="lab">--color-primary</span></div>
|
|
970
|
+
<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>
|
|
971
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-success)">In stock · savings</span><span class="lab">--color-success</span></div>
|
|
972
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-sale)">Sale price</span><span class="lab">--color-sale</span></div>
|
|
973
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-warning)">Low stock</span><span class="lab">--color-warning</span></div>
|
|
974
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-error)">Error · out of stock</span><span class="lab">--color-error</span></div>
|
|
975
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-info)">Informational</span><span class="lab">--color-info</span></div>
|
|
976
|
+
</div>
|
|
977
|
+
|
|
978
|
+
<p class="form-help" style="margin:22px 0 8px">Icon roles (<code>currentColor</code> tinted by token)</p>
|
|
979
|
+
<div class="sg-tok-grid">
|
|
980
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-star)">
|
|
981
|
+
<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>
|
|
982
|
+
Rating star</span><span class="lab">--color-star</span></div>
|
|
983
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-success)">
|
|
984
|
+
<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>
|
|
985
|
+
Success check</span><span class="lab">--color-success</span></div>
|
|
986
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-warning)">
|
|
987
|
+
<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>
|
|
988
|
+
Warning</span><span class="lab">--color-warning</span></div>
|
|
989
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-error)">
|
|
990
|
+
<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>
|
|
991
|
+
Error</span><span class="lab">--color-error</span></div>
|
|
992
|
+
<div class="sg-tok"><span class="txt" style="color:var(--color-info)">
|
|
993
|
+
<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>
|
|
994
|
+
Info</span><span class="lab">--color-info</span></div>
|
|
995
|
+
</div>
|
|
996
|
+
|
|
997
|
+
<p class="form-help" style="margin:22px 0 8px">Interaction states — CTA hover, disabled, loading, focus ring, tap-target</p>
|
|
998
|
+
<div class="sg-tok-state">
|
|
999
|
+
<button class="sg-tok-btn" type="button">Primary CTA</button>
|
|
1000
|
+
<button class="sg-tok-btn" type="button" style="background:var(--color-primary-hover)">Hover</button>
|
|
1001
|
+
<button class="sg-tok-btn is-loading" type="button" aria-busy="true" aria-label="Loading">Loading</button>
|
|
1002
|
+
<button class="sg-tok-btn" type="button" disabled>Disabled</button>
|
|
1003
|
+
<input class="sg-tok-field" type="email" placeholder="you@example.com — Tab here for the focus ring" aria-label="Focus-ring + field-border sample" />
|
|
1004
|
+
<button class="sg-tap" type="button" aria-label="Add to cart (min tap-target)">
|
|
1005
|
+
<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>
|
|
1006
|
+
</button>
|
|
1007
|
+
</div>
|
|
1008
|
+
<p class="form-help" 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>
|
|
1009
|
+
</section>
|
|
1010
|
+
|
|
841
1011
|
<section class="sg-block">
|
|
842
1012
|
<p class="sg-h">Promo cards</p>
|
|
843
1013
|
<div class="sg-promos">
|
|
@@ -1137,6 +1307,34 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1137
1307
|
/>
|
|
1138
1308
|
</section>
|
|
1139
1309
|
|
|
1310
|
+
{/* ── Structured content widgets (components/content/, spec §F4) ───────
|
|
1311
|
+
The DATA-driven promotion of repeated raw-page patterns. A tenant
|
|
1312
|
+
authors a policy/about/compliance page as structured `sections`
|
|
1313
|
+
(JSON) instead of copying an HTML/CSS fragment; these components
|
|
1314
|
+
render it with the a11y (headings, <dl>, <address>, roles, tap
|
|
1315
|
+
targets) baked in and every color from f06 tokens. The trust strip is
|
|
1316
|
+
f09-guarded — real-or-absent, fabricated proof dropped. */}
|
|
1317
|
+
<section class="sg-block">
|
|
1318
|
+
<p class="sg-h">Structured content — <code>components/content/</code></p>
|
|
1319
|
+
<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>
|
|
1320
|
+
|
|
1321
|
+
<p class="form-help" 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>
|
|
1322
|
+
<TrustStrip items={sampleTrustStrip} />
|
|
1323
|
+
|
|
1324
|
+
<p class="form-help" 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>
|
|
1325
|
+
<Callout callout={{ tone: "info", title: "Heads up", body: "An informational aside rendered from data." }} />
|
|
1326
|
+
<Callout callout={{ tone: "warning", body: "A caution — check this before you rely on it." }} />
|
|
1327
|
+
<Callout callout={{ tone: "legal", body: "Restricted to adults 21+ where lawful. Void where prohibited." }} />
|
|
1328
|
+
<Callout callout={{ tone: "success", body: "Your terminal is verified and signed in." }} />
|
|
1329
|
+
|
|
1330
|
+
<p class="form-help" 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>
|
|
1331
|
+
<NeedsReviewCallout flag={{ reason: "Refund window (14 vs 30 days) not confirmed with merchant.", severity: "blocker", owner: "ops", href: "#" }} />
|
|
1332
|
+
|
|
1333
|
+
<p class="form-help" 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>
|
|
1334
|
+
<ProseToc sections={sampleProseSections} min={2} />
|
|
1335
|
+
<ProseSections sections={sampleProseSections} includeNeedsReview={true} />
|
|
1336
|
+
</section>
|
|
1337
|
+
|
|
1140
1338
|
{/* ── Subscription/Autopilot education widgets (components/subscription/)
|
|
1141
1339
|
Education-only: explains the Autopilot concept and hands off to the
|
|
1142
1340
|
tenant's product-owned subscribe/manage flow — no scheduling,
|
|
@@ -17,7 +17,14 @@
|
|
|
17
17
|
* as the component guide ([theme].astro): reference tokens overridden by the
|
|
18
18
|
* descriptor's preview.componentVars, emitted on a scoping wrapper.
|
|
19
19
|
* noindex, never in the sitemap, never production publishing.
|
|
20
|
+
*
|
|
21
|
+
* Left on-demand — NOT prerendered (audit finding "selective-prerender"). A dynamic
|
|
22
|
+
* [tenant]/chrome/[theme] route reading Astro.locals.cspNonce and depending on the
|
|
23
|
+
* middleware CSP + security headers; prerendering would need getStaticPaths AND lose
|
|
24
|
+
* those headers, for a dev/preview-only noindex surface with no production traffic.
|
|
20
25
|
*/
|
|
26
|
+
export const prerender = false;
|
|
27
|
+
|
|
21
28
|
const { tenant, theme } = Astro.params;
|
|
22
29
|
const cspNonce = Astro.locals.cspNonce;
|
|
23
30
|
|
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
* has ONE maintained home. A persistent left sidebar (StyleGuideNav) makes the
|
|
10
10
|
* guide reachable in one click from the tenant hub and links across the other
|
|
11
11
|
* style-guide surfaces. noindex, never in the sitemap, never production publishing.
|
|
12
|
+
*
|
|
13
|
+
* Left on-demand — NOT prerendered (audit finding "selective-prerender"). A dynamic
|
|
14
|
+
* [tenant]/guide/[theme] route reading Astro.locals.cspNonce and depending on the
|
|
15
|
+
* middleware CSP + security headers; prerendering would need getStaticPaths AND lose
|
|
16
|
+
* those headers, for a dev/preview-only noindex surface with no production traffic.
|
|
12
17
|
*/
|
|
18
|
+
export const prerender = false;
|
|
19
|
+
|
|
13
20
|
import "@/styles/global.css";
|
|
14
21
|
import type { MarkdownInstance } from "astro";
|
|
15
22
|
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
* This is a review surface only: noindex, never in the sitemap, never part of
|
|
9
9
|
* production marketing publishing. Tenant-agnostic route; theme data is
|
|
10
10
|
* tenant-local (tenants/<tenant>/content/themes/*.json).
|
|
11
|
+
*
|
|
12
|
+
* Left on-demand — NOT prerendered (audit finding "selective-prerender"). A dynamic
|
|
13
|
+
* [tenant] route reading Astro.locals.cspNonce and depending on the middleware CSP +
|
|
14
|
+
* security headers; prerendering would need getStaticPaths AND lose those headers, for
|
|
15
|
+
* a dev/preview-only noindex surface with no production traffic (zero perf upside).
|
|
11
16
|
*/
|
|
17
|
+
export const prerender = false;
|
|
18
|
+
|
|
12
19
|
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
13
20
|
|
|
14
21
|
const { tenant } = Astro.params;
|
|
@@ -6,7 +6,17 @@
|
|
|
6
6
|
* discoverable from one place. Review surface only: noindex, never in the
|
|
7
7
|
* sitemap, never part of production marketing publishing. Tenant-agnostic —
|
|
8
8
|
* theme data is tenant-local (tenants/<tenant>/content/themes/*.json).
|
|
9
|
+
*
|
|
10
|
+
* Left on-demand — NOT prerendered (audit finding "selective-prerender"). Though its
|
|
11
|
+
* theme data is build-time (import.meta.glob, tenant-independent), it still reads
|
|
12
|
+
* Astro.locals.cspNonce and relies on the middleware to emit the enforced CSP +
|
|
13
|
+
* security headers; a prerendered copy (served as a static asset, bypassing the
|
|
14
|
+
* worker) would carry NEITHER (no static _headers fallback). This is a dev/preview-only
|
|
15
|
+
* noindex review surface with no production traffic, so prerendering buys ~zero perf
|
|
16
|
+
* while downgrading its header posture — net negative.
|
|
9
17
|
*/
|
|
18
|
+
export const prerender = false;
|
|
19
|
+
|
|
10
20
|
const cspNonce = Astro.locals.cspNonce;
|
|
11
21
|
|
|
12
22
|
// All tenant-local theme descriptors, grouped by tenant. Colocated repo-root
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Self-hosted web fonts (audit finding 6).
|
|
3
|
+
*
|
|
4
|
+
* Previously the Layout loaded a render-blocking third-party Google Fonts
|
|
5
|
+
* stylesheet (with its gstatic woff2). We now vendor the exact families +
|
|
6
|
+
* weights every theme actually uses via @fontsource, so the woff2 are bundled
|
|
7
|
+
* by Vite and served SAME-ORIGIN ('self' in the CSP). font-display: swap is
|
|
8
|
+
* preserved (it's @fontsource's default in every file below).
|
|
9
|
+
*
|
|
10
|
+
* These @font-face rules are declared for ALL tenants, but browsers lazy-load a
|
|
11
|
+
* woff2 only when a rendered element actually uses that font-family — so a tenant
|
|
12
|
+
* still downloads only its own 2–3 families, same as before. No typeface changes.
|
|
13
|
+
*
|
|
14
|
+
* Families/weights (keep in sync with the themes in src/themes/*):
|
|
15
|
+
* Reference (PVC, sample-store-2, home): Space Grotesk 500/600/700 (display),
|
|
16
|
+
* Source Serif 4 400/500/600 (body), Space Mono 400 (mono)
|
|
17
|
+
* sample-store-3.com: Montserrat 600/700/800 (display), Inter 400/500/600 (body)
|
|
18
|
+
* tokenoftrust.com: Plus Jakarta Sans 500/600/700/800 (display),
|
|
19
|
+
* Inter 400/500/600 (body), JetBrains Mono 400/500 (mono)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/* Space Grotesk — reference display */
|
|
23
|
+
@import "@fontsource/space-grotesk/500.css";
|
|
24
|
+
@import "@fontsource/space-grotesk/600.css";
|
|
25
|
+
@import "@fontsource/space-grotesk/700.css";
|
|
26
|
+
|
|
27
|
+
/* Source Serif 4 — reference body */
|
|
28
|
+
@import "@fontsource/source-serif-4/400.css";
|
|
29
|
+
@import "@fontsource/source-serif-4/500.css";
|
|
30
|
+
@import "@fontsource/source-serif-4/600.css";
|
|
31
|
+
|
|
32
|
+
/* Space Mono — reference mono (also sample-store-3' inherited mono) */
|
|
33
|
+
@import "@fontsource/space-mono/400.css";
|
|
34
|
+
|
|
35
|
+
/* Montserrat — sample-store-3 display */
|
|
36
|
+
@import "@fontsource/montserrat/600.css";
|
|
37
|
+
@import "@fontsource/montserrat/700.css";
|
|
38
|
+
@import "@fontsource/montserrat/800.css";
|
|
39
|
+
|
|
40
|
+
/* Inter — sample-store-3 + tokenoftrust body */
|
|
41
|
+
@import "@fontsource/inter/400.css";
|
|
42
|
+
@import "@fontsource/inter/500.css";
|
|
43
|
+
@import "@fontsource/inter/600.css";
|
|
44
|
+
|
|
45
|
+
/* Plus Jakarta Sans — tokenoftrust display */
|
|
46
|
+
@import "@fontsource/plus-jakarta-sans/500.css";
|
|
47
|
+
@import "@fontsource/plus-jakarta-sans/600.css";
|
|
48
|
+
@import "@fontsource/plus-jakarta-sans/700.css";
|
|
49
|
+
@import "@fontsource/plus-jakarta-sans/800.css";
|
|
50
|
+
|
|
51
|
+
/* JetBrains Mono — tokenoftrust mono + the auth/cockpit chrome pages */
|
|
52
|
+
@import "@fontsource/jetbrains-mono/400.css";
|
|
53
|
+
@import "@fontsource/jetbrains-mono/500.css";
|
|
54
|
+
@import "@fontsource/jetbrains-mono/600.css";
|
|
@@ -46,6 +46,19 @@
|
|
|
46
46
|
--color-primary-hover: var(--color-primary-hover, color-mix(in srgb, var(--color-primary) 88%, #000));
|
|
47
47
|
--color-accent-hover: var(--color-accent-hover, color-mix(in srgb, var(--color-accent) 88%, #000));
|
|
48
48
|
|
|
49
|
+
/* Interaction/quality-bar tokens (token-contract.md · unit F6). Each carries a
|
|
50
|
+
derived default so a component may read it unconditionally; a theme sets one
|
|
51
|
+
only to brand-tune it (emit --color-<k> via themeToCssVars).
|
|
52
|
+
- focus-ring keyboard focus outline (defaults to the accent spark)
|
|
53
|
+
- disabled/-contrast disabled+loading control fill / text-on-disabled
|
|
54
|
+
- field-border stronger ≥3:1 input outline than the hairline border
|
|
55
|
+
- star review/rating star fill (trust/UGC surfaces) */
|
|
56
|
+
--color-focus-ring: var(--color-focus-ring, var(--color-accent));
|
|
57
|
+
--color-disabled: var(--color-disabled, color-mix(in srgb, var(--color-muted) 26%, var(--color-surface)));
|
|
58
|
+
--color-disabled-contrast: var(--color-disabled-contrast, var(--color-muted));
|
|
59
|
+
--color-field-border: var(--color-field-border, color-mix(in srgb, var(--color-border) 52%, var(--color-text)));
|
|
60
|
+
--color-star: var(--color-star, var(--color-accent));
|
|
61
|
+
|
|
49
62
|
--font-display: var(--font-display, "Space Grotesk"), system-ui, sans-serif;
|
|
50
63
|
--font-body: var(--font-body, "Source Serif 4"), Georgia, serif;
|
|
51
64
|
--font-mono: var(--font-mono, "Space Mono"), ui-monospace, monospace;
|
|
@@ -67,6 +80,11 @@
|
|
|
67
80
|
:root {
|
|
68
81
|
/* Fluid modular type scale; overridden by injected --fs-* when present. */
|
|
69
82
|
color-scheme: light;
|
|
83
|
+
/* Minimum interactive tap-target (WCAG 2.2 §2.5.8). Non-@theme token (a size,
|
|
84
|
+
not a Tailwind color) so it lives here with a self-referential default: the
|
|
85
|
+
injected --tap-target (schema.ts, from shape.tapTarget) wins when present,
|
|
86
|
+
else 44px. Components size touch controls with var(--tap-target). (F6.) */
|
|
87
|
+
--tap-target: var(--tap-target, 44px);
|
|
70
88
|
}
|
|
71
89
|
|
|
72
90
|
html {
|
|
@@ -102,9 +120,11 @@
|
|
|
102
120
|
text-decoration: none;
|
|
103
121
|
}
|
|
104
122
|
|
|
105
|
-
/* Visible keyboard focus everywhere (WCAG 2.2 AA, brief §8).
|
|
123
|
+
/* Visible keyboard focus everywhere (WCAG 2.2 AA, brief §8). Reads the
|
|
124
|
+
dedicated --color-focus-ring token (defaults to the accent spark) so a theme
|
|
125
|
+
can brand-tune the ring without touching the accent used elsewhere. */
|
|
106
126
|
:focus-visible {
|
|
107
|
-
outline: var(--border-thick, 2px) solid var(--color-
|
|
127
|
+
outline: var(--border-thick, 2px) solid var(--color-focus-ring);
|
|
108
128
|
outline-offset: 2px;
|
|
109
129
|
border-radius: 2px;
|
|
110
130
|
}
|
|
@@ -81,31 +81,9 @@ export function themeToCssVars(t: ThemeTokens): string {
|
|
|
81
81
|
push("shadow-sm", t.shape.shadow.sm);
|
|
82
82
|
push("shadow-md", t.shape.shadow.md);
|
|
83
83
|
push("shadow-lg", t.shape.shadow.lg);
|
|
84
|
+
// Minimum tap-target (WCAG 2.2 §2.5.8). Optional in the shape tokens; when a
|
|
85
|
+
// theme omits it the `:root` base default (44px) in global.css applies. (F6.)
|
|
86
|
+
if (t.shape.tapTarget) push("tap-target", t.shape.tapTarget);
|
|
84
87
|
|
|
85
88
|
return `:root{\n${lines.join("\n")}\n}`;
|
|
86
89
|
}
|
|
87
|
-
|
|
88
|
-
/** Google Fonts <link> for a theme's display+body+mono families (if Google-hosted). */
|
|
89
|
-
export function themeFontHref(t: ThemeTokens): string | null {
|
|
90
|
-
const families = new Map<string, number[]>();
|
|
91
|
-
families.set(t.type.display.family, t.type.display.weights);
|
|
92
|
-
families.set(t.type.body.family, t.type.body.weights);
|
|
93
|
-
if (t.type.mono) families.set(t.type.mono.family, t.type.mono.weights);
|
|
94
|
-
|
|
95
|
-
const params = [...families]
|
|
96
|
-
.filter(([fam]) => !SYSTEM_FONTS.has(fam))
|
|
97
|
-
.map(([fam, weights]) => {
|
|
98
|
-
const w = [...new Set(weights)].sort((a, b) => a - b).join(";");
|
|
99
|
-
return `family=${encodeURIComponent(fam).replace(/%20/g, "+")}:wght@${w}`;
|
|
100
|
-
});
|
|
101
|
-
if (!params.length) return null;
|
|
102
|
-
return `https://fonts.googleapis.com/css2?${params.join("&")}&display=swap`;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const SYSTEM_FONTS = new Set([
|
|
106
|
-
"system-ui",
|
|
107
|
-
"-apple-system",
|
|
108
|
-
"Arial",
|
|
109
|
-
"Helvetica",
|
|
110
|
-
"Georgia",
|
|
111
|
-
]);
|
|
@@ -16,7 +16,10 @@ export default defineConfig({
|
|
|
16
16
|
},
|
|
17
17
|
},
|
|
18
18
|
test: {
|
|
19
|
-
|
|
19
|
+
// src/** = the app's unit tests; e2e/a11y/**/*.test.ts = the F15 a11y-matrix
|
|
20
|
+
// route-map validation (a pure, server-less smoke test — the Playwright
|
|
21
|
+
// *.spec.ts matrix runs separately via playwright.a11y.config.ts).
|
|
22
|
+
include: ["src/**/*.test.ts", "e2e/a11y/**/*.test.ts"],
|
|
20
23
|
environment: "node",
|
|
21
24
|
},
|
|
22
25
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
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",
|