@tokenoftrust/storefront-runner 1.3.2
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/LICENSE +58 -0
- package/README.md +42 -0
- package/apps/storefront/astro.config.mjs +66 -0
- package/apps/storefront/dev-plugins/dev-loop-state.mjs +147 -0
- package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +238 -0
- package/apps/storefront/env.d.ts +162 -0
- package/apps/storefront/migrations/0000_baseline.sql +54 -0
- package/apps/storefront/migrations/0001_products_fts.sql +9 -0
- package/apps/storefront/migrations/README.md +54 -0
- package/apps/storefront/migrations/meta/0000_snapshot.json +347 -0
- package/apps/storefront/migrations/meta/0001_snapshot.json +347 -0
- package/apps/storefront/migrations/meta/_journal.json +20 -0
- package/apps/storefront/package.json +42 -0
- package/apps/storefront/public/brand/northwind-logo-dark.svg +4 -0
- package/apps/storefront/public/brand/northwind-logo-light.svg +4 -0
- package/apps/storefront/public/brand/northwind-og.svg +13 -0
- package/apps/storefront/public/favicon.svg +5 -0
- package/apps/storefront/public/js/dashboard-team.js +147 -0
- package/apps/storefront/public/js/dashboard-vendor-search.js +115 -0
- package/apps/storefront/public/shared/commerce-chrome.css +369 -0
- package/apps/storefront/src/components/Badge.astro +34 -0
- package/apps/storefront/src/components/Breadcrumbs.astro +45 -0
- package/apps/storefront/src/components/CollectionCard.astro +56 -0
- package/apps/storefront/src/components/EmptyState.astro +55 -0
- package/apps/storefront/src/components/Img.astro +68 -0
- package/apps/storefront/src/components/ProductCard.astro +228 -0
- package/apps/storefront/src/components/Section.astro +39 -0
- package/apps/storefront/src/components/Seo.astro +70 -0
- package/apps/storefront/src/components/WidgetFrame.astro +34 -0
- package/apps/storefront/src/components/admin/AdminAIWorkflowsTab.astro +531 -0
- package/apps/storefront/src/components/admin/AdminCustomersTab.astro +597 -0
- package/apps/storefront/src/components/admin/AdminFoxyCartSettingsPanel.astro +227 -0
- package/apps/storefront/src/components/admin/AdminFulfillmentTab.astro +465 -0
- package/apps/storefront/src/components/admin/AdminProductsTab.astro +901 -0
- package/apps/storefront/src/components/admin/AdminReportingTab.astro +435 -0
- package/apps/storefront/src/components/admin/AdminSettingsTab.astro +782 -0
- package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +1223 -0
- package/apps/storefront/src/components/auth/AuthBadge.astro +44 -0
- package/apps/storefront/src/components/chrome/AnnouncementBar.astro +108 -0
- package/apps/storefront/src/components/chrome/MegaMenu.astro +26 -0
- package/apps/storefront/src/components/chrome/NavDropdown.astro +201 -0
- package/apps/storefront/src/components/chrome/SiteFooter.astro +201 -0
- package/apps/storefront/src/components/chrome/SiteHeader.astro +234 -0
- package/apps/storefront/src/components/chrome/UtilityNav.astro +79 -0
- package/apps/storefront/src/components/commerce/ArticleCard.astro +242 -0
- package/apps/storefront/src/components/commerce/BrandGrid.astro +175 -0
- package/apps/storefront/src/components/commerce/FoxyLoader.astro +23 -0
- package/apps/storefront/src/components/commerce/FoxySidecartStyles.astro +61 -0
- package/apps/storefront/src/components/commerce/PriceDisplay.astro +91 -0
- package/apps/storefront/src/components/commerce/ProductCarousel.astro +197 -0
- package/apps/storefront/src/components/commerce/ProductGrid.astro +75 -0
- package/apps/storefront/src/components/commerce/RatingStars.astro +58 -0
- package/apps/storefront/src/components/commerce/ReviewList.astro +54 -0
- package/apps/storefront/src/components/commerce/ReviewSummary.astro +44 -0
- package/apps/storefront/src/components/commerce/TagFilterCloud.astro +149 -0
- package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +37 -0
- package/apps/storefront/src/components/compliance/ComplianceNotice.astro +99 -0
- package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +45 -0
- package/apps/storefront/src/components/compliance/NicotineWarning.astro +33 -0
- package/apps/storefront/src/components/compliance/PactActNotice.astro +35 -0
- package/apps/storefront/src/components/compliance/Prop65Warning.astro +80 -0
- package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +38 -0
- package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +35 -0
- package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +53 -0
- package/apps/storefront/src/components/home/Hero.astro +164 -0
- package/apps/storefront/src/components/islands/AgeGate.tsx +109 -0
- package/apps/storefront/src/components/islands/ImageGallery.tsx +237 -0
- package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +73 -0
- package/apps/storefront/src/components/islands/MobileNav.tsx +239 -0
- package/apps/storefront/src/components/islands/QuickView.tsx +138 -0
- package/apps/storefront/src/components/islands/RecentlyViewed.tsx +122 -0
- package/apps/storefront/src/components/islands/SavedList.tsx +99 -0
- package/apps/storefront/src/components/islands/SearchTypeahead.tsx +248 -0
- package/apps/storefront/src/components/islands/VariantSelector.tsx +375 -0
- package/apps/storefront/src/components/marketing/CardGrid.astro +72 -0
- package/apps/storefront/src/components/marketing/CodeSample.astro +20 -0
- package/apps/storefront/src/components/marketing/CtaBand.astro +24 -0
- package/apps/storefront/src/components/marketing/Faq.astro +37 -0
- package/apps/storefront/src/components/marketing/Integrations.astro +63 -0
- package/apps/storefront/src/components/marketing/MarketingBlocks.astro +53 -0
- package/apps/storefront/src/components/marketing/MarketingCtas.astro +48 -0
- package/apps/storefront/src/components/marketing/MarketingHero.astro +72 -0
- package/apps/storefront/src/components/marketing/ProofStrip.astro +37 -0
- package/apps/storefront/src/components/marketing/SplitCompare.astro +53 -0
- package/apps/storefront/src/components/marketing/Steps.astro +36 -0
- package/apps/storefront/src/components/marketing/Testimonials.astro +38 -0
- package/apps/storefront/src/components/marketing/TrustBar.astro +22 -0
- package/apps/storefront/src/components/membership/IllustrativeLabel.astro +56 -0
- package/apps/storefront/src/components/membership/TierCards.astro +164 -0
- package/apps/storefront/src/components/membership/TierComparisonTable.astro +148 -0
- package/apps/storefront/src/components/plp/ActiveFilters.astro +79 -0
- package/apps/storefront/src/components/plp/FacetSidebar.astro +199 -0
- package/apps/storefront/src/components/plp/Pagination.astro +99 -0
- package/apps/storefront/src/components/plp/SortSelect.astro +64 -0
- package/apps/storefront/src/components/style-guide/StyleGuideNav.astro +95 -0
- package/apps/storefront/src/components/subscription/HowItWorksSteps.astro +67 -0
- package/apps/storefront/src/components/subscription/ManageSubscriptionEntry.astro +67 -0
- package/apps/storefront/src/components/subscription/SavingsExplainer.astro +101 -0
- package/apps/storefront/src/config/adminTargetTenant.ts +28 -0
- package/apps/storefront/src/config/devTenantSeed.ts +78 -0
- package/apps/storefront/src/config/devTenants.ts +16 -0
- package/apps/storefront/src/config/kvTenantResolver.ts +87 -0
- package/apps/storefront/src/config/resolver.ts +102 -0
- package/apps/storefront/src/config/tenants.ts +87 -0
- package/apps/storefront/src/layouts/Layout.astro +368 -0
- package/apps/storefront/src/lib/admin/README.md +122 -0
- package/apps/storefront/src/lib/admin/ai/approvalMode.ts +21 -0
- package/apps/storefront/src/lib/admin/ai/askEnvelope.ts +48 -0
- package/apps/storefront/src/lib/admin/ai/audit.ts +14 -0
- package/apps/storefront/src/lib/admin/ai/index.ts +6 -0
- package/apps/storefront/src/lib/admin/ai/operationalRuns.ts +155 -0
- package/apps/storefront/src/lib/admin/ai/recommendation.ts +20 -0
- package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +172 -0
- package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +65 -0
- package/apps/storefront/src/lib/admin/envelope.ts +10 -0
- package/apps/storefront/src/lib/admin/evidence/evidenceReference.ts +32 -0
- package/apps/storefront/src/lib/admin/memoizeByEnvelope.ts +27 -0
- package/apps/storefront/src/lib/admin/orderClient.ts +146 -0
- package/apps/storefront/src/lib/admin/seed.ts +54 -0
- package/apps/storefront/src/lib/admin/services/mock/aiWorkflows.ts +59 -0
- package/apps/storefront/src/lib/admin/services/mock/customers.ts +86 -0
- package/apps/storefront/src/lib/admin/services/mock/evidence.ts +99 -0
- package/apps/storefront/src/lib/admin/services/mock/foxyCartSettings.ts +78 -0
- package/apps/storefront/src/lib/admin/services/mock/fulfillment.ts +62 -0
- package/apps/storefront/src/lib/admin/services/mock/index.ts +12 -0
- package/apps/storefront/src/lib/admin/services/mock/orders.ts +184 -0
- package/apps/storefront/src/lib/admin/services/mock/products.ts +105 -0
- package/apps/storefront/src/lib/admin/services/mock/reporting.ts +51 -0
- package/apps/storefront/src/lib/admin/services/mock/settings.ts +70 -0
- package/apps/storefront/src/lib/admin/services/mock/tenants.ts +29 -0
- package/apps/storefront/src/lib/admin/services/orders.ts +300 -0
- package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +67 -0
- package/apps/storefront/src/lib/admin/viewmodels/customers.ts +56 -0
- package/apps/storefront/src/lib/admin/viewmodels/fulfillment.ts +49 -0
- package/apps/storefront/src/lib/admin/viewmodels/orders.ts +92 -0
- package/apps/storefront/src/lib/admin/viewmodels/products.ts +74 -0
- package/apps/storefront/src/lib/admin/viewmodels/reporting.ts +34 -0
- package/apps/storefront/src/lib/admin/viewmodels/settings.ts +64 -0
- package/apps/storefront/src/lib/adminTenantEnvelope.ts +90 -0
- package/apps/storefront/src/lib/analytics/index.ts +47 -0
- package/apps/storefront/src/lib/auth/brokerAssertion.ts +136 -0
- package/apps/storefront/src/lib/auth/devAuth.ts +90 -0
- package/apps/storefront/src/lib/auth/gatePage.ts +81 -0
- package/apps/storefront/src/lib/auth/identityToken.ts +341 -0
- package/apps/storefront/src/lib/auth/loginGate.ts +119 -0
- package/apps/storefront/src/lib/auth/route.ts +146 -0
- package/apps/storefront/src/lib/auth/session.ts +203 -0
- package/apps/storefront/src/lib/auth/totAccessClient.ts +503 -0
- package/apps/storefront/src/lib/basePath.ts +41 -0
- package/apps/storefront/src/lib/cfImage.ts +55 -0
- package/apps/storefront/src/lib/chrome/model.ts +244 -0
- package/apps/storefront/src/lib/chrome/parseConfig.ts +34 -0
- package/apps/storefront/src/lib/colors.ts +97 -0
- package/apps/storefront/src/lib/commerce/foxyCartSettings.ts +253 -0
- package/apps/storefront/src/lib/content-edit/applyDiff.ts +91 -0
- package/apps/storefront/src/lib/content-edit/client.ts +230 -0
- package/apps/storefront/src/lib/content-edit/index.ts +14 -0
- package/apps/storefront/src/lib/content-edit/route.ts +25 -0
- package/apps/storefront/src/lib/content-edit/types.ts +19 -0
- package/apps/storefront/src/lib/cspStaticHashes.ts +24 -0
- package/apps/storefront/src/lib/d1/catalog.ts +366 -0
- package/apps/storefront/src/lib/dashboard/staffAdmission.ts +43 -0
- package/apps/storefront/src/lib/dashboard/staffVendorAccess.ts +449 -0
- package/apps/storefront/src/lib/dashboard/tenantSelection.ts +136 -0
- package/apps/storefront/src/lib/dashboard/vendorQuery.ts +61 -0
- package/apps/storefront/src/lib/demoGate.ts +113 -0
- package/apps/storefront/src/lib/dev/activityIngestToken.ts +78 -0
- package/apps/storefront/src/lib/dev/activityStore.ts +72 -0
- package/apps/storefront/src/lib/dev/ai-widget-client.js +308 -0
- package/apps/storefront/src/lib/dev/apiBase.ts +14 -0
- package/apps/storefront/src/lib/dev/cliSignInCode.ts +155 -0
- package/apps/storefront/src/lib/dev/devDraft.ts +133 -0
- package/apps/storefront/src/lib/dev/hostedCockpit.ts +169 -0
- package/apps/storefront/src/lib/dev/livePreview.ts +77 -0
- package/apps/storefront/src/lib/dev/runtimeStore.ts +120 -0
- package/apps/storefront/src/lib/dev/storeStatus.ts +142 -0
- package/apps/storefront/src/lib/diag/redact.ts +20 -0
- package/apps/storefront/src/lib/edgeCache.ts +128 -0
- package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +62 -0
- package/apps/storefront/src/lib/env.ts +60 -0
- package/apps/storefront/src/lib/fixtures/sampleProducts.ts +130 -0
- package/apps/storefront/src/lib/format.ts +38 -0
- package/apps/storefront/src/lib/foxyCommerce.ts +49 -0
- package/apps/storefront/src/lib/imageAttrs.ts +55 -0
- package/apps/storefront/src/lib/jsonld.ts +166 -0
- package/apps/storefront/src/lib/maintenance.ts +71 -0
- package/apps/storefront/src/lib/membership/model.ts +97 -0
- package/apps/storefront/src/lib/memoryKv.ts +32 -0
- package/apps/storefront/src/lib/messaging/messagesClient.ts +143 -0
- package/apps/storefront/src/lib/placeholder.ts +99 -0
- package/apps/storefront/src/lib/previewReload.ts +125 -0
- package/apps/storefront/src/lib/priceBuckets.ts +33 -0
- package/apps/storefront/src/lib/rawChrome.ts +505 -0
- package/apps/storefront/src/lib/rawMarketingHtml.ts +136 -0
- package/apps/storefront/src/lib/search/index.ts +74 -0
- package/apps/storefront/src/lib/sections.ts +129 -0
- package/apps/storefront/src/lib/securityHeaders.ts +31 -0
- package/apps/storefront/src/lib/storyblok/content-model.ts +289 -0
- package/apps/storefront/src/lib/storyblok/provider.ts +607 -0
- package/apps/storefront/src/lib/subscription/model.ts +68 -0
- package/apps/storefront/src/lib/tenantRouting.ts +91 -0
- package/apps/storefront/src/lib/tot/ToTClient.ts +177 -0
- package/apps/storefront/src/lib/tot/d1Client.ts +62 -0
- package/apps/storefront/src/lib/tot/query.ts +249 -0
- package/apps/storefront/src/lib/tot/totClientInterface.ts +30 -0
- package/apps/storefront/src/lib/url.ts +142 -0
- package/apps/storefront/src/lib/wishlist.ts +63 -0
- package/apps/storefront/src/middleware/index.ts +455 -0
- package/apps/storefront/src/pages/404.astro +61 -0
- package/apps/storefront/src/pages/[...slug].astro +90 -0
- package/apps/storefront/src/pages/admin.astro +1675 -0
- package/apps/storefront/src/pages/api/admin/orders/[id].ts +53 -0
- package/apps/storefront/src/pages/api/admin/orders.ts +71 -0
- package/apps/storefront/src/pages/api/auth/logout.ts +21 -0
- package/apps/storefront/src/pages/api/auth/magic-exchange.ts +107 -0
- package/apps/storefront/src/pages/api/auth/send.ts +85 -0
- package/apps/storefront/src/pages/api/auth/verify.ts +135 -0
- package/apps/storefront/src/pages/api/cache-purge.ts +44 -0
- package/apps/storefront/src/pages/api/checkout-style.css.ts +43 -0
- package/apps/storefront/src/pages/api/cli/policy.ts +70 -0
- package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +164 -0
- package/apps/storefront/src/pages/api/csp-report.ts +25 -0
- package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +124 -0
- package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +120 -0
- package/apps/storefront/src/pages/api/dev/activity.ts +124 -0
- package/apps/storefront/src/pages/api/dev/cli-signin-code.ts +73 -0
- package/apps/storefront/src/pages/api/dev/diff.ts +68 -0
- package/apps/storefront/src/pages/api/dev/file.ts +57 -0
- package/apps/storefront/src/pages/api/dev/locate.ts +125 -0
- package/apps/storefront/src/pages/api/dev/publish.ts +128 -0
- package/apps/storefront/src/pages/api/dev/tree.ts +70 -0
- package/apps/storefront/src/pages/api/dev/write.ts +116 -0
- package/apps/storefront/src/pages/api/newsletter.ts +104 -0
- package/apps/storefront/src/pages/api/request-access.ts +172 -0
- package/apps/storefront/src/pages/auth/login.astro +149 -0
- package/apps/storefront/src/pages/auth/magic.astro +105 -0
- package/apps/storefront/src/pages/capabilities.astro +292 -0
- package/apps/storefront/src/pages/collections/[handle].astro +177 -0
- package/apps/storefront/src/pages/collections/index.astro +59 -0
- package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +100 -0
- package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +154 -0
- package/apps/storefront/src/pages/dashboard/index.astro +160 -0
- package/apps/storefront/src/pages/index.astro +290 -0
- package/apps/storefront/src/pages/llms.txt.ts +92 -0
- package/apps/storefront/src/pages/products/[handle].astro +402 -0
- package/apps/storefront/src/pages/robots.txt.ts +24 -0
- package/apps/storefront/src/pages/saved.astro +35 -0
- package/apps/storefront/src/pages/search.astro +150 -0
- package/apps/storefront/src/pages/sitemap.xml.ts +78 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +1280 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +229 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +144 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +116 -0
- package/apps/storefront/src/pages/style-guide/index.astro +98 -0
- package/apps/storefront/src/pages/tenants/[id]/[...path].ts +57 -0
- package/apps/storefront/src/styles/global.css +292 -0
- package/apps/storefront/src/themes/reference.ts +68 -0
- package/apps/storefront/src/themes/schema.ts +111 -0
- package/apps/storefront/src/themes/tenants/index.ts +51 -0
- package/apps/storefront/tsconfig.json +16 -0
- package/apps/storefront/vitest.config.ts +22 -0
- package/package.json +26 -0
- package/packages/public-runtime/LICENSE +58 -0
- package/packages/public-runtime/package.json +22 -0
- package/packages/public-runtime/src/binary-path.ts +68 -0
- package/packages/public-runtime/src/capabilities.ts +89 -0
- package/packages/public-runtime/src/catalog-api.ts +81 -0
- package/packages/public-runtime/src/catalog-d1.ts +192 -0
- package/packages/public-runtime/src/checkout-style-publish.ts +200 -0
- package/packages/public-runtime/src/checkout-style.ts +375 -0
- package/packages/public-runtime/src/csp.ts +109 -0
- package/packages/public-runtime/src/customization-preview.ts +197 -0
- package/packages/public-runtime/src/customization-reconcile.ts +63 -0
- package/packages/public-runtime/src/customization-runtime.ts +157 -0
- package/packages/public-runtime/src/customization-scripts.ts +64 -0
- package/packages/public-runtime/src/customization-versioning.ts +95 -0
- package/packages/public-runtime/src/foxy-orders.ts +136 -0
- package/packages/public-runtime/src/foxy.ts +196 -0
- package/packages/public-runtime/src/hot-standby-readiness.ts +140 -0
- package/packages/public-runtime/src/index.ts +34 -0
- package/packages/public-runtime/src/product.ts +159 -0
- package/packages/public-runtime/src/search.ts +45 -0
- package/packages/public-runtime/src/tenant-assets.ts +444 -0
- package/packages/public-runtime/src/tenant.ts +384 -0
- package/packages/public-runtime/tsconfig.json +8 -0
- package/packages/public-runtime/vitest.config.ts +8 -0
- package/pnpm-workspace.yaml +7 -0
- package/scripts/build/copy-tenant-assets.mjs +69 -0
- package/scripts/dev/ai-edit.mjs +183 -0
- package/scripts/dev/checkout-watch.mjs +116 -0
- package/scripts/dev/file-browser.mjs +159 -0
- package/scripts/dev/file-writer.mjs +141 -0
- package/scripts/dev/git-status.mjs +171 -0
- package/scripts/dev/locate-handler.mjs +163 -0
- package/scripts/dev/locate.mjs +112 -0
- package/scripts/dev/port-check.mjs +48 -0
- package/scripts/dev/safe-path.mjs +109 -0
- package/scripts/dev/shot.mjs +46 -0
- package/scripts/dev/tenant-source-root.mjs +76 -0
- package/scripts/dev/unified-diff.mjs +81 -0
- package/scripts/tot-dev.mjs +376 -0
- package/tenants/README.md +14 -0
- package/tenants/home/content/chrome.json +7 -0
- package/tenants/home/content/home.html +58 -0
- package/tenants/home/content/home.json +11 -0
- package/tenants/home/public/js/storefront.js +210 -0
- package/tenants/home/public/logo-wordmark.png +0 -0
- package/tenants/home/public/pages/storefront.css +212 -0
- package/tenants/home/theme.json +6 -0
- package/tsconfig.base.json +20 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Preview/dev-only SHARED RAW-CHROME STYLE GUIDE —
|
|
4
|
+
* `/_style-guide/<tenant>/chrome/<theme-id>/` (unit F4).
|
|
5
|
+
*
|
|
6
|
+
* Renders the platform-shipped raw chrome set — the `/shared/commerce-chrome.css`
|
|
7
|
+
* class vocabulary (announcement + utility bar, header + search + actions, primary
|
|
8
|
+
* nav + mega panels, brand/category tiles, compliance strip, age gate, footer) —
|
|
9
|
+
* re-skinned under ONE tenant theme's component tokens. Swap the theme in the URL
|
|
10
|
+
* and the whole chrome re-skins; the CSS never forks. This is the visual counterpart
|
|
11
|
+
* to the style-concept-audit `chromeConcept` gate: the guide shows the shared chrome,
|
|
12
|
+
* the gate proves no tenant re-authors it. Per decision raw-chrome-single-stylesheet.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately links ONLY the theme token sheet + the shared chrome sheet — NOT the
|
|
15
|
+
* tenant's own mkt.css — so what renders is exactly the platform chrome, isolated
|
|
16
|
+
* from any per-tenant CSS. The token re-skin uses the same component-var mechanism
|
|
17
|
+
* as the component guide ([theme].astro): reference tokens overridden by the
|
|
18
|
+
* descriptor's preview.componentVars, emitted on a scoping wrapper.
|
|
19
|
+
* noindex, never in the sitemap, never production publishing.
|
|
20
|
+
*/
|
|
21
|
+
const { tenant, theme } = Astro.params;
|
|
22
|
+
const cspNonce = Astro.locals.cspNonce;
|
|
23
|
+
|
|
24
|
+
// Tenant-local theme descriptors. From src/pages/style-guide/[tenant]/chrome/ the
|
|
25
|
+
// repo root is seven levels up.
|
|
26
|
+
const themeModules = import.meta.glob<Record<string, any>>(
|
|
27
|
+
"../../../../../../../tenants/*/content/themes/*.json",
|
|
28
|
+
{ eager: true, import: "default" },
|
|
29
|
+
);
|
|
30
|
+
const seg = `/tenants/${tenant}/content/themes/`;
|
|
31
|
+
const t = Object.entries(themeModules)
|
|
32
|
+
.filter(([path]) => path.includes(seg))
|
|
33
|
+
.map(([, mod]) => mod)
|
|
34
|
+
.find((m) => m.id === theme);
|
|
35
|
+
|
|
36
|
+
if (!t) return new Response(null, { status: 404 });
|
|
37
|
+
|
|
38
|
+
// Reference component tokens (the "Northwind" pilot identity), overridden per theme
|
|
39
|
+
// by the descriptor's preview.componentVars — the same reskin mechanism the component
|
|
40
|
+
// guide uses. Fonts are intentionally omitted so the theme stylesheet's --font-display
|
|
41
|
+
// (inherited from :root) drives type. Emitted on the .sg-page wrapper so the shared
|
|
42
|
+
// chrome inherits them.
|
|
43
|
+
const REFERENCE_COMPONENT_VARS: Record<string, string> = {
|
|
44
|
+
"--color-bg": "#f4f1ea", "--color-surface": "#fcfaf5", "--color-surface-2": "#efe9dc",
|
|
45
|
+
"--color-text": "#1c2624", "--color-muted": "#5c6663",
|
|
46
|
+
"--color-primary": "#1f3a34", "--color-primary-hover": "#16302b", "--color-primary-contrast": "#f4f1ea",
|
|
47
|
+
// --color-accent darkened from #b5612f (L 0.174) to #9a5228 (L 0.130) — the lighter
|
|
48
|
+
// value read below 4.5:1 against both --color-primary-contrast (as an accent-fill
|
|
49
|
+
// background) and --color-surface (as accent-colored text), which axe caught on any
|
|
50
|
+
// tenant relying on this fallback instead of its own theme override.
|
|
51
|
+
"--color-accent": "#9a5228", "--color-accent-hover": "#804421", "--color-border": "#dcd6c9",
|
|
52
|
+
"--color-success": "#3f6b4f", "--color-sale": "#9e3b2e", "--color-error": "#9e3b2e",
|
|
53
|
+
"--radius-sm": "3px", "--radius-md": "6px", "--radius-lg": "12px", "--radius-full": "999px",
|
|
54
|
+
"--shadow-sm": "0 1px 2px rgba(28,38,36,.06)", "--shadow-md": "0 6px 24px -8px rgba(28,38,36,.14)",
|
|
55
|
+
"--shadow-lg": "0 24px 60px -20px rgba(28,38,36,.22)", "--container-max": "1240px",
|
|
56
|
+
};
|
|
57
|
+
const componentVars: Record<string, string> = {
|
|
58
|
+
...REFERENCE_COMPONENT_VARS,
|
|
59
|
+
...((t.preview?.componentVars ?? {}) as Record<string, string>),
|
|
60
|
+
};
|
|
61
|
+
const componentVarsInline = Object.entries(componentVars)
|
|
62
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
63
|
+
.join(";");
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
<!doctype html>
|
|
67
|
+
<html lang="en">
|
|
68
|
+
<head>
|
|
69
|
+
<meta charset="utf-8" />
|
|
70
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
71
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
72
|
+
<link rel="icon" type="image/png" href={`/tenants/${tenant}/favicon.png`} />
|
|
73
|
+
<title>{t.name} — shared chrome (preview)</title>
|
|
74
|
+
{/* The theme token sheet (fonts + any :root tokens) + the shared chrome sheet.
|
|
75
|
+
NO tenant mkt.css — the chrome renders purely from the platform stylesheet. */}
|
|
76
|
+
<link rel="stylesheet" href={t.stylesheet} />
|
|
77
|
+
<link rel="stylesheet" href="/shared/commerce-chrome.css" />
|
|
78
|
+
{/* Guide-only chrome + preview affordances (distinct .sg-* names). The mega panel
|
|
79
|
+
+ age gate are shown OPEN in normal flow so reviewers see them without hover or
|
|
80
|
+
the fixed overlay covering the page. Every styled selector is authored in this
|
|
81
|
+
component, so component-scoped styles apply. */}
|
|
82
|
+
<style nonce={cspNonce}>
|
|
83
|
+
.sg-bar { position: sticky; top: 0; z-index: 500; 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; }
|
|
84
|
+
.sg-bar .flag { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; background: #f59e0b; color: #221600; font-weight: 800; padding: 4px 8px; border-radius: 5px; }
|
|
85
|
+
.sg-bar .role { font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; background: #0e9f8e; color: #00201b; font-weight: 800; padding: 4px 8px; border-radius: 999px; }
|
|
86
|
+
.sg-bar a { color: #bfe0ff; }
|
|
87
|
+
.sg-bar a.right { margin-left: auto; }
|
|
88
|
+
.sg-page { background: var(--color-bg); color: var(--color-text); min-height: 100vh; padding-bottom: 40px; }
|
|
89
|
+
.sg-lbl { max-width: var(--container-max, 1240px); margin: 26px auto 6px; padding: 0 20px; font: 800 .78rem/1.3 -apple-system, sans-serif; letter-spacing: .12em; text-transform: uppercase; color: var(--color-primary); }
|
|
90
|
+
.sg-frame { max-width: var(--container-max, 1240px); margin: 0 auto 6px; padding: 0 20px; }
|
|
91
|
+
.sg-frame > * { border: 1px dashed var(--color-border); border-radius: 8px; }
|
|
92
|
+
/* Show the demoed mega panel + age gate open, in normal flow, for review. */
|
|
93
|
+
.sg-open .mega { position: static; opacity: 1; visibility: visible; transform: none; box-shadow: var(--shadow-md); margin-top: 6px; }
|
|
94
|
+
.sg-agegate-frame .age-gate { position: static; display: flex; inset: auto; background: color-mix(in srgb, var(--color-text) 10%, transparent); border-radius: 8px; }
|
|
95
|
+
.sg-note { max-width: var(--container-max, 1240px); margin: 8px auto 0; padding: 16px 20px 0; border-top: 1px solid var(--color-border); font-size: .82rem; color: var(--color-muted); }
|
|
96
|
+
</style>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<!-- A toolbar, not page content — a real <header> here would duplicate
|
|
100
|
+
the demoed .site-header's own banner landmark (axe
|
|
101
|
+
landmark-no-duplicate-banner/landmark-unique). -->
|
|
102
|
+
<div class="sg-bar">
|
|
103
|
+
<span class="flag">Preview · shared chrome · noindex</span>
|
|
104
|
+
<span class="role">{t.role}</span>
|
|
105
|
+
<b>{t.name}</b>
|
|
106
|
+
<a class="right" href={`/_style-guide/${tenant}/guide/${t.id}/`}>widget library guide →</a>
|
|
107
|
+
<a href={`/_style-guide/${tenant}/${t.id}/`}>← component guide</a>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<main class="sg-page" style={componentVarsInline}>
|
|
111
|
+
<h1 class="sg-lbl">Shared chrome preview — {t.name}</h1>
|
|
112
|
+
<p class="sg-lbl">Announcement + top utility bar</p>
|
|
113
|
+
<div class="sg-frame">
|
|
114
|
+
<div>
|
|
115
|
+
<div class="topbar-warning"><div class="container"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div></div>
|
|
116
|
+
<div class="announce"><div class="container">Free US shipping on orders over $100</div></div>
|
|
117
|
+
<div class="announce-marquee"><div class="announce-marquee__track"><span>Clearance event — up to 40% off</span><span>Clearance event — up to 40% off</span></div></div>
|
|
118
|
+
<div class="announce-bar"><div class="container"><span class="announce-bar__msg">Members save 10% every day — <a href="#">join free</a></span><button class="announce-bar__close" aria-label="Dismiss">×</button></div></div>
|
|
119
|
+
<nav class="utility-nav" aria-label="Utility"><div class="container">
|
|
120
|
+
<ul><li><a href="#">News</a></li><li><a href="#">About</a></li><li><a href="#">Contact</a></li></ul>
|
|
121
|
+
<div class="utility-nav__right"><a class="member-cue" href="#">Member pricing</a><span class="sel">USD $</span></div>
|
|
122
|
+
</div></nav>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<p class="sg-lbl">Header — brand · search · actions · primary nav + mega panel</p>
|
|
127
|
+
<div class="sg-frame">
|
|
128
|
+
<header class="site-header sg-open">
|
|
129
|
+
<div class="container header-row">
|
|
130
|
+
<a class="brand" href="#"><span class="b-prime">Prime</span><span class="b-vapor">Vapor</span><span class="b-club">Club</span></a>
|
|
131
|
+
<div class="header-search">
|
|
132
|
+
<input type="search" placeholder="Search products…" aria-label="Search" />
|
|
133
|
+
<button aria-label="Search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"></circle><path d="M21 21l-4-4"></path></svg></button>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="header-actions">
|
|
136
|
+
<a href="#" aria-label="Account"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"></circle><path d="M4 21c0-4 4-6 8-6s8 2 8 6"></path></svg></a>
|
|
137
|
+
<a class="cart" href="#" aria-label="Cart"><svg viewBox="0 0 24 24"><path d="M3 3h2l2 13h11l2-8H7"></path></svg><span class="count">2</span></a>
|
|
138
|
+
</div>
|
|
139
|
+
<button class="hamburger" aria-label="Menu"><span></span><span></span><span></span></button>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="primary-nav-bar"><div class="container">
|
|
142
|
+
<nav class="primary-nav" aria-label="Primary"><ul>
|
|
143
|
+
<li><a class="is-flag" href="#">New<span class="new-badge">NEW</span></a></li>
|
|
144
|
+
<li class="nav-item">
|
|
145
|
+
<a href="#">Shop <span class="caret">▾</span></a>
|
|
146
|
+
<div class="mega mega--wide"><div class="mega__cols">
|
|
147
|
+
<div class="mega__col"><h4>Category</h4><a href="#">Disposables</a><a href="#">E-Liquid</a><a href="#">Devices</a></div>
|
|
148
|
+
<div class="mega__col"><h4>Featured</h4><a href="#">Best Sellers</a><a href="#">On Sale</a></div>
|
|
149
|
+
</div></div>
|
|
150
|
+
</li>
|
|
151
|
+
<li><a href="#">Coils & Parts</a></li>
|
|
152
|
+
<li><a href="#">On Sale</a></li>
|
|
153
|
+
</ul></nav>
|
|
154
|
+
</div></div>
|
|
155
|
+
</header>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<p class="sg-lbl">Brand tiles + category cards</p>
|
|
159
|
+
<div class="sg-frame">
|
|
160
|
+
<section class="section container">
|
|
161
|
+
<div class="sec-head"><span class="eyebrow">Shop by</span><h2>Top brands</h2></div>
|
|
162
|
+
<div class="tile-grid">
|
|
163
|
+
<a class="tile" href="#"><span>Northwind</span></a>
|
|
164
|
+
<a class="tile" href="#"><span>Summit Co.</span></a>
|
|
165
|
+
<a class="tile" href="#"><span>Cascade</span></a>
|
|
166
|
+
<a class="tile" href="#"><span>Harbor</span></a>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="cat-grid" style="margin-top:20px">
|
|
169
|
+
<a class="cat-card" href="#"><h3>Disposables</h3></a>
|
|
170
|
+
<a class="cat-card" href="#"><h3>E-Liquid</h3></a>
|
|
171
|
+
<a class="cat-card" href="#"><h3>Devices</h3></a>
|
|
172
|
+
</div>
|
|
173
|
+
</section>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<p class="sg-lbl">Compliance strip</p>
|
|
177
|
+
<div class="sg-frame">
|
|
178
|
+
<div class="compliance-strip"><div class="container"><p>Must be 21+ to purchase. Products intended for adults of legal smoking age only.</p></div></div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<p class="sg-lbl">Age gate (21+ interstitial) — shown open for review</p>
|
|
182
|
+
<div class="sg-frame sg-agegate-frame">
|
|
183
|
+
<div class="age-gate is-open">
|
|
184
|
+
<div class="age-gate__panel">
|
|
185
|
+
<p class="age-gate__mark"><span class="is-red">Prime</span>VaporClub</p>
|
|
186
|
+
<h2>Are you 21 or older?</h2>
|
|
187
|
+
<p class="age-gate__lede">You must be of legal smoking age to enter this store.</p>
|
|
188
|
+
<div class="age-gate__actions">
|
|
189
|
+
<a class="btn btn-primary age-gate__enter" href="#">Yes, I'm 21+</a>
|
|
190
|
+
<a class="btn btn-outline" href="#">No</a>
|
|
191
|
+
</div>
|
|
192
|
+
<p class="age-gate__fine">By entering you agree you are of legal age to purchase these products.</p>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<p class="sg-lbl">Footer — columns · newsletter · payments · trust marks</p>
|
|
198
|
+
<div class="sg-frame">
|
|
199
|
+
<footer class="site-footer">
|
|
200
|
+
<div class="container">
|
|
201
|
+
<div class="footer-grid">
|
|
202
|
+
<div class="footer-brand">
|
|
203
|
+
<a class="brand" href="#"><span class="b-prime">Prime</span><span class="b-vapor">Vapor</span><span class="b-club">Club</span></a>
|
|
204
|
+
<p>Regulated-commerce chrome, one shared stylesheet, re-skinned per tenant theme.</p>
|
|
205
|
+
<div class="footer-news"><div class="footer-news__row"><input type="email" placeholder="Email address" aria-label="Email" /><button>Join</button></div>
|
|
206
|
+
<label class="footer-attest"><input type="checkbox" /> <span>I confirm I am 21 or older.</span></label>
|
|
207
|
+
</div>
|
|
208
|
+
<div class="pay-badges"><span>Visa</span><span>Mastercard</span><span>Amex</span><span>PayPal</span></div>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="footer-col"><h4>Shop</h4><ul><li><a href="#">Disposables</a></li><li><a href="#">E-Liquid</a></li><li><a href="#">Devices</a></li></ul></div>
|
|
211
|
+
<div class="footer-col"><h4>Support</h4><ul><li><a href="#">Contact</a></li><li><a href="#">Shipping</a></li><li><a href="#">Returns</a></li></ul></div>
|
|
212
|
+
<div class="footer-col"><h4>Company</h4><ul><li><a href="#">About</a></li><li><a href="#">Blog</a></li></ul></div>
|
|
213
|
+
</div>
|
|
214
|
+
<div class="trust-marks"><span>🔒 Secure checkout</span><span>✓ Age-verified</span><span>★ 4.9 / 5</span></div>
|
|
215
|
+
<div class="footer-warning"><strong>WARNING:</strong><p>This product contains nicotine. Nicotine is an addictive chemical.</p></div>
|
|
216
|
+
<div class="footer-bottom"><p>© Sample Store. All rights reserved.</p><p><a href="#">Privacy</a> · <a href="#">Terms</a></p></div>
|
|
217
|
+
</div>
|
|
218
|
+
</footer>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<p class="sg-note">
|
|
222
|
+
Every element above is styled solely by <code>/shared/commerce-chrome.css</code> under the
|
|
223
|
+
<b>{t.name}</b> theme's tokens — no tenant chrome CSS is linked here. The
|
|
224
|
+
<code>chromeConcept</code> gate (style-concept-audit + verify-tenant.sh) fails any tenant
|
|
225
|
+
that re-authors or inlines these selectors instead of linking the shared sheet.
|
|
226
|
+
</p>
|
|
227
|
+
</main>
|
|
228
|
+
</body>
|
|
229
|
+
</html>
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Preview/dev-only WIDGET LIBRARY GUIDE —
|
|
4
|
+
* `/_style-guide/<tenant>/guide/<theme-id>/`.
|
|
5
|
+
*
|
|
6
|
+
* Renders `docs/widget-library-guide.md` (the source of truth) as HTML via
|
|
7
|
+
* Astro's native markdown pipeline, inside the tenant's theme so the prose reads
|
|
8
|
+
* under real tokens. The .md file is imported (never duplicated here) so the doc
|
|
9
|
+
* has ONE maintained home. A persistent left sidebar (StyleGuideNav) makes the
|
|
10
|
+
* guide reachable in one click from the tenant hub and links across the other
|
|
11
|
+
* style-guide surfaces. noindex, never in the sitemap, never production publishing.
|
|
12
|
+
*/
|
|
13
|
+
import "@/styles/global.css";
|
|
14
|
+
import type { MarkdownInstance } from "astro";
|
|
15
|
+
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
16
|
+
|
|
17
|
+
const { tenant, theme } = Astro.params;
|
|
18
|
+
const cspNonce = Astro.locals.cspNonce;
|
|
19
|
+
|
|
20
|
+
// Tenant-local theme descriptors. From src/pages/style-guide/[tenant]/guide/ the
|
|
21
|
+
// repo root is seven levels up (same depth as the chrome guide).
|
|
22
|
+
const themeModules = import.meta.glob<Record<string, any>>(
|
|
23
|
+
"../../../../../../../tenants/*/content/themes/*.json",
|
|
24
|
+
{ eager: true, import: "default" },
|
|
25
|
+
);
|
|
26
|
+
const seg = `/tenants/${tenant}/content/themes/`;
|
|
27
|
+
const t = Object.entries(themeModules)
|
|
28
|
+
.filter(([path]) => path.includes(seg))
|
|
29
|
+
.map(([, mod]) => mod)
|
|
30
|
+
.find((m) => m.id === theme);
|
|
31
|
+
|
|
32
|
+
if (!t) return new Response(null, { status: 404 });
|
|
33
|
+
|
|
34
|
+
// The guide markdown — the single maintained source of truth (repo-root docs/).
|
|
35
|
+
// Imported through Astro's markdown pipeline so we render its <Content /> and
|
|
36
|
+
// pull its heading outline for the sidebar TOC; the prose is never copied here.
|
|
37
|
+
const guideModules = import.meta.glob<MarkdownInstance<Record<string, unknown>>>(
|
|
38
|
+
"../../../../../../../docs/widget-library-guide.md",
|
|
39
|
+
{ eager: true },
|
|
40
|
+
);
|
|
41
|
+
const guide = Object.values(guideModules)[0];
|
|
42
|
+
if (!guide) return new Response(null, { status: 404 });
|
|
43
|
+
const { Content } = guide;
|
|
44
|
+
const headings = guide.getHeadings();
|
|
45
|
+
|
|
46
|
+
// Same reskin mechanism as the component/chrome guides: reference tokens (the
|
|
47
|
+
// Northwind pilot identity) overridden by the descriptor's preview.componentVars,
|
|
48
|
+
// emitted on the themed content wrapper so the prose reads under THIS theme.
|
|
49
|
+
const REFERENCE_COMPONENT_VARS: Record<string, string> = {
|
|
50
|
+
"--color-bg": "#f4f1ea", "--color-surface": "#fcfaf5", "--color-surface-2": "#ece7db",
|
|
51
|
+
"--color-text": "#1c2624", "--color-muted": "#5c6663",
|
|
52
|
+
"--color-primary": "#1f3a34", "--color-primary-contrast": "#f4f1ea",
|
|
53
|
+
"--color-accent": "#b5612f", "--color-accent-ink": "#8a481f", "--color-border": "#dcd6c9",
|
|
54
|
+
"--color-success": "#3f6b4f", "--color-sale": "#9e3b2e",
|
|
55
|
+
"--radius-sm": "3px", "--radius-md": "6px", "--radius-lg": "12px", "--radius-full": "999px",
|
|
56
|
+
"--shadow-sm": "0 1px 2px rgba(28,38,36,.06)", "--shadow-md": "0 6px 24px -8px rgba(28,38,36,.14)",
|
|
57
|
+
"--shadow-lg": "0 24px 60px -20px rgba(28,38,36,.22)", "--container-max": "1240px",
|
|
58
|
+
};
|
|
59
|
+
const componentVars: Record<string, string> = {
|
|
60
|
+
...REFERENCE_COMPONENT_VARS,
|
|
61
|
+
...((t.preview?.componentVars ?? {}) as Record<string, string>),
|
|
62
|
+
};
|
|
63
|
+
const componentVarsInline = Object.entries(componentVars)
|
|
64
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
65
|
+
.join(";");
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
<!doctype html>
|
|
69
|
+
<html lang="en">
|
|
70
|
+
<head>
|
|
71
|
+
<meta charset="utf-8" />
|
|
72
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
73
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
74
|
+
<link rel="icon" type="image/png" href={`/tenants/${tenant}/favicon.png`} />
|
|
75
|
+
<title>Widget library guide — {t.name} (preview)</title>
|
|
76
|
+
{/* The tenant's theme sheet so the prose reads under real brand tokens. */}
|
|
77
|
+
<link rel="stylesheet" href={t.stylesheet} />
|
|
78
|
+
<style nonce={cspNonce}>
|
|
79
|
+
body { margin: 0; }
|
|
80
|
+
.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; }
|
|
81
|
+
.sg-bar .flag { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; background: #f59e0b; color: #221600; font-weight: 800; padding: 4px 8px; border-radius: 5px; }
|
|
82
|
+
.sg-bar .role { font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; background: #0e9f8e; color: #00201b; font-weight: 800; padding: 4px 8px; border-radius: 999px; }
|
|
83
|
+
.sg-bar a { color: #bfe0ff; display: inline-flex; align-items: center; min-height: 44px; text-decoration: none; }
|
|
84
|
+
.sg-bar a.right { margin-left: auto; }
|
|
85
|
+
|
|
86
|
+
/* Two-column docs layout: persistent left rail + themed prose. */
|
|
87
|
+
.sg-shell { display: grid; grid-template-columns: 264px minmax(0, 1fr); align-items: start; }
|
|
88
|
+
.sg-side { position: sticky; top: 0; align-self: start; max-height: 100vh; overflow-y: auto; background: #0f1729; color: #e6edf6; padding: 22px 14px 40px; }
|
|
89
|
+
|
|
90
|
+
/* Left-nav (StyleGuideNav markup) — styled here so the component stays CSP-clean. */
|
|
91
|
+
.sg-nav__eyebrow { font: 800 .72rem/1.2 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: #7fe3d4; margin: 0 0 12px; padding: 0 10px; }
|
|
92
|
+
.sg-nav__list { list-style: none; margin: 0; padding: 0; }
|
|
93
|
+
.sg-nav__list li { margin: 0; }
|
|
94
|
+
.sg-nav__link { display: block; padding: 9px 10px; border-radius: 8px; color: #bfe0ff; text-decoration: none; font-size: .92rem; min-height: 40px; }
|
|
95
|
+
.sg-nav__link:hover { background: #16223c; }
|
|
96
|
+
.sg-nav__link.is-active { background: #16223c; color: #fff; font-weight: 700; }
|
|
97
|
+
.sg-nav__link--sub { padding-left: 20px; font-size: .88rem; }
|
|
98
|
+
.sg-nav__toc { list-style: none; margin: 2px 0 8px; padding: 0; border-left: 1px solid #26365a; margin-left: 16px; }
|
|
99
|
+
.sg-nav__toc-link { display: block; padding: 5px 10px 5px 14px; color: #9fb0c8; font-size: .82rem; text-decoration: none; line-height: 1.3; }
|
|
100
|
+
.sg-nav__toc-link:hover { color: #e6edf6; }
|
|
101
|
+
|
|
102
|
+
/* Themed prose column. .rte styles come from global.css; token vars are
|
|
103
|
+
supplied by componentVarsInline on this wrapper so they always resolve. */
|
|
104
|
+
.sg-content { background: var(--color-bg); color: var(--color-text); min-height: 100vh; padding: 34px clamp(20px, 4vw, 56px) 96px; }
|
|
105
|
+
.sg-content .rte { max-width: 900px; }
|
|
106
|
+
.sg-content h1 { font-size: clamp(1.9rem, 4vw, 2.7rem); line-height: 1.1; margin: 0 0 10px; color: var(--color-text); }
|
|
107
|
+
.sg-content .rte h2 { border-top: 1px solid var(--color-border); padding-top: 1.4em; scroll-margin-top: 68px; }
|
|
108
|
+
.sg-content .rte h3 { scroll-margin-top: 68px; }
|
|
109
|
+
.sg-content blockquote { border-left: 3px solid var(--color-accent); margin: 1em 0; padding: 2px 0 2px 16px; color: var(--color-muted); }
|
|
110
|
+
.sg-content pre { background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 14px 16px; overflow-x: auto; font-family: var(--font-mono, ui-monospace, Menlo, monospace); font-size: .84rem; line-height: 1.5; }
|
|
111
|
+
.sg-content pre code { background: none; padding: 0; }
|
|
112
|
+
.sg-content code { font-family: var(--font-mono, ui-monospace, Menlo, monospace); font-size: .88em; }
|
|
113
|
+
.sg-content :not(pre) > code { background: var(--color-surface-2); padding: 1px 5px; border-radius: 4px; }
|
|
114
|
+
.sg-content table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; }
|
|
115
|
+
.sg-content th, .sg-content td { border: 1px solid var(--color-border); padding: 6px 10px; text-align: left; font-size: .9rem; }
|
|
116
|
+
|
|
117
|
+
@media (max-width: 900px) {
|
|
118
|
+
.sg-shell { grid-template-columns: 1fr; }
|
|
119
|
+
.sg-side { position: static; max-height: none; }
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
122
|
+
</head>
|
|
123
|
+
<body>
|
|
124
|
+
<header class="sg-bar">
|
|
125
|
+
<span class="flag">Preview · widget library · noindex</span>
|
|
126
|
+
<span class="role">{t.role}</span>
|
|
127
|
+
<b>{t.name}</b>
|
|
128
|
+
<a class="right" href={`/_style-guide/${tenant}/${t.id}/`}>← component guide</a>
|
|
129
|
+
<a href={`/_style-guide/${tenant}/`}>tenant hub →</a>
|
|
130
|
+
</header>
|
|
131
|
+
|
|
132
|
+
<div class="sg-shell">
|
|
133
|
+
<aside class="sg-side">
|
|
134
|
+
<StyleGuideNav tenant={tenant!} theme={t.id} active="guide" headings={headings} />
|
|
135
|
+
</aside>
|
|
136
|
+
|
|
137
|
+
<main class="sg-content" style={componentVarsInline}>
|
|
138
|
+
<article class="rte">
|
|
139
|
+
<Content />
|
|
140
|
+
</article>
|
|
141
|
+
</main>
|
|
142
|
+
</div>
|
|
143
|
+
</body>
|
|
144
|
+
</html>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Preview/dev-only STYLE-GUIDE HUB for a tenant — `/_style-guide/<tenant>/`.
|
|
4
|
+
*
|
|
5
|
+
* Lists every theme guide (current / candidate / legacy) so reviewers can open
|
|
6
|
+
* them side-by-side WITHOUT reskinning the live marketing site. A persistent
|
|
7
|
+
* left sidebar (StyleGuideNav) puts the Widget Library Guide one click away.
|
|
8
|
+
* This is a review surface only: noindex, never in the sitemap, never part of
|
|
9
|
+
* production marketing publishing. Tenant-agnostic route; theme data is
|
|
10
|
+
* tenant-local (tenants/<tenant>/content/themes/*.json).
|
|
11
|
+
*/
|
|
12
|
+
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
13
|
+
|
|
14
|
+
const { tenant } = Astro.params;
|
|
15
|
+
const cspNonce = Astro.locals.cspNonce;
|
|
16
|
+
|
|
17
|
+
// Tenant-local theme descriptors. Colocated repo-root layout: from
|
|
18
|
+
// src/pages/style-guide/[tenant]/ the repo root is six levels up.
|
|
19
|
+
const themeModules = import.meta.glob<Record<string, any>>(
|
|
20
|
+
"../../../../../../tenants/*/content/themes/*.json",
|
|
21
|
+
{ eager: true, import: "default" },
|
|
22
|
+
);
|
|
23
|
+
const seg = `/tenants/${tenant}/content/themes/`;
|
|
24
|
+
const themes = Object.entries(themeModules)
|
|
25
|
+
.filter(([path]) => path.includes(seg))
|
|
26
|
+
.map(([, mod]) => mod);
|
|
27
|
+
|
|
28
|
+
if (themes.length === 0) return new Response(null, { status: 404 });
|
|
29
|
+
|
|
30
|
+
const ROLE_ORDER: Record<string, number> = { current: 0, candidate: 1, legacy: 2 };
|
|
31
|
+
themes.sort(
|
|
32
|
+
(a, b) => (ROLE_ORDER[a.role] ?? 9) - (ROLE_ORDER[b.role] ?? 9),
|
|
33
|
+
);
|
|
34
|
+
// The current (or first) theme skins the persistent sidebar's per-theme links.
|
|
35
|
+
const navTheme = themes[0]?.id;
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
<!doctype html>
|
|
39
|
+
<html lang="en">
|
|
40
|
+
<head>
|
|
41
|
+
<meta charset="utf-8" />
|
|
42
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
43
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
44
|
+
<link rel="icon" type="image/png" href={`/tenants/${tenant}/favicon.png`} />
|
|
45
|
+
<title>Style guides — {tenant} (preview)</title>
|
|
46
|
+
<style nonce={cspNonce}>
|
|
47
|
+
:root { color-scheme: light; }
|
|
48
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; background: #0f1729; color: #e6edf6; line-height: 1.55; }
|
|
49
|
+
.sg-shell { display: grid; grid-template-columns: 264px minmax(0, 1fr); align-items: start; }
|
|
50
|
+
.sg-side { position: sticky; top: 0; align-self: start; max-height: 100vh; overflow-y: auto; padding: 22px 14px 40px; border-right: 1px solid #1c2a44; }
|
|
51
|
+
.sg-nav__eyebrow { font: 800 .72rem/1.2 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: #7fe3d4; margin: 0 0 12px; padding: 0 10px; }
|
|
52
|
+
.sg-nav__list { list-style: none; margin: 0; padding: 0; }
|
|
53
|
+
.sg-nav__list li { margin: 0; }
|
|
54
|
+
.sg-nav__link { display: block; padding: 9px 10px; border-radius: 8px; color: #bfe0ff; text-decoration: none; font-size: .92rem; min-height: 40px; }
|
|
55
|
+
.sg-nav__link:hover { background: #16223c; }
|
|
56
|
+
.sg-nav__link.is-active { background: #16223c; color: #fff; font-weight: 700; }
|
|
57
|
+
.sg-nav__link--sub { padding-left: 20px; font-size: .88rem; }
|
|
58
|
+
.sg-nav__toc { list-style: none; margin: 2px 0 8px; padding: 0; }
|
|
59
|
+
.sg-nav__toc-link { display: block; padding: 4px 10px 4px 26px; color: #9fb0c8; font-size: .82rem; text-decoration: none; }
|
|
60
|
+
.wrap { max-width: 860px; margin: 0 auto; padding: 40px 24px 80px; }
|
|
61
|
+
.flag { display: inline-block; font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; background: #f59e0b; color: #221600; font-weight: 800; padding: 4px 10px; border-radius: 6px; }
|
|
62
|
+
h1 { font-size: 1.9rem; margin: 18px 0 6px; }
|
|
63
|
+
.sub { color: #9fb0c8; margin: 0 0 32px; }
|
|
64
|
+
.card { display: block; text-decoration: none; color: inherit; background: #16223c; border: 1px solid #24324f; border-radius: 14px; padding: 20px 22px; margin-bottom: 6px; transition: border-color .15s, transform .15s; }
|
|
65
|
+
.card:hover { border-color: #3f5680; transform: translateY(-2px); }
|
|
66
|
+
.card .row { display: flex; align-items: center; gap: 12px; }
|
|
67
|
+
.badge { font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; font-weight: 800; padding: 3px 9px; border-radius: 999px; }
|
|
68
|
+
.badge.current { background: #0e9f8e; color: #001f1a; }
|
|
69
|
+
.badge.candidate { background: #6f7dff; color: #060a26; }
|
|
70
|
+
.badge.legacy { background: #47536e; color: #dfe6f2; }
|
|
71
|
+
.status { margin-left: auto; font-size: .78rem; color: #9fb0c8; font-family: ui-monospace, Menlo, monospace; }
|
|
72
|
+
.name { font-weight: 700; font-size: 1.05rem; }
|
|
73
|
+
.desc { color: #9fb0c8; font-size: .9rem; margin-top: 8px; }
|
|
74
|
+
.sub-links { display: flex; gap: 16px; flex-wrap: wrap; margin: 8px 0 16px 4px; }
|
|
75
|
+
.sub-links a { color: #bfe0ff; font-size: .82rem; text-decoration: none; display: inline-flex; align-items: center; min-height: 32px; }
|
|
76
|
+
.sub-links a:hover { text-decoration: underline; }
|
|
77
|
+
.note { margin-top: 28px; font-size: .82rem; color: #7f8fab; border-top: 1px solid #24324f; padding-top: 16px; }
|
|
78
|
+
@media (max-width: 900px) { .sg-shell { grid-template-columns: 1fr; } .sg-side { position: static; max-height: none; border-right: 0; border-bottom: 1px solid #1c2a44; } }
|
|
79
|
+
</style>
|
|
80
|
+
</head>
|
|
81
|
+
<body>
|
|
82
|
+
<div class="sg-shell">
|
|
83
|
+
<aside class="sg-side">
|
|
84
|
+
<StyleGuideNav tenant={tenant!} theme={navTheme} active="tenant" />
|
|
85
|
+
</aside>
|
|
86
|
+
<main class="wrap">
|
|
87
|
+
<span class="flag">Preview · dev only · noindex</span>
|
|
88
|
+
<p style="margin:14px 0 0"><a href="/_style-guide/" style="color:#bfe0ff;font-size:.85rem;text-decoration:none">← all clients</a></p>
|
|
89
|
+
<h1>{tenant} — theme style guides</h1>
|
|
90
|
+
<p class="sub">Open any guide independently to compare looks side-by-side. Nothing here reskins the live site. The <b>Widget Library Guide</b> (left nav) documents every shared component.</p>
|
|
91
|
+
|
|
92
|
+
{themes.map((t) => (
|
|
93
|
+
<div>
|
|
94
|
+
<a class="card" href={`/_style-guide/${tenant}/${t.id}/`}>
|
|
95
|
+
<div class="row">
|
|
96
|
+
<span class:list={["badge", t.role]}>{t.role}</span>
|
|
97
|
+
<span class="name">{t.name}</span>
|
|
98
|
+
<span class="status">{t.status}</span>
|
|
99
|
+
</div>
|
|
100
|
+
{t.description && <p class="desc">{t.description}</p>}
|
|
101
|
+
</a>
|
|
102
|
+
<div class="sub-links">
|
|
103
|
+
<a href={`/_style-guide/${tenant}/chrome/${t.id}/`}>shared chrome preview →</a>
|
|
104
|
+
<a href={`/_style-guide/${tenant}/guide/${t.id}/`}>widget library guide →</a>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
))}
|
|
108
|
+
|
|
109
|
+
<p class="note">
|
|
110
|
+
These are preview/dev review surfaces — excluded from the sitemap and production marketing
|
|
111
|
+
publishing. Approve the <b>current</b> guide before propagating its style concept across the site.
|
|
112
|
+
</p>
|
|
113
|
+
</main>
|
|
114
|
+
</div>
|
|
115
|
+
</body>
|
|
116
|
+
</html>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Preview/dev-only STYLE-GUIDE ROOT INDEX — `/_style-guide/`.
|
|
4
|
+
*
|
|
5
|
+
* Lists EVERY tenant and each of its theme guides, so all clients' guides are
|
|
6
|
+
* discoverable from one place. Review surface only: noindex, never in the
|
|
7
|
+
* sitemap, never part of production marketing publishing. Tenant-agnostic —
|
|
8
|
+
* theme data is tenant-local (tenants/<tenant>/content/themes/*.json).
|
|
9
|
+
*/
|
|
10
|
+
const cspNonce = Astro.locals.cspNonce;
|
|
11
|
+
|
|
12
|
+
// All tenant-local theme descriptors, grouped by tenant. Colocated repo-root
|
|
13
|
+
// layout: from src/pages/style-guide/ the repo root is five levels up.
|
|
14
|
+
const themeModules = import.meta.glob<Record<string, any>>(
|
|
15
|
+
"../../../../../tenants/*/content/themes/*.json",
|
|
16
|
+
{ eager: true, import: "default" },
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const ROLE_ORDER: Record<string, number> = { current: 0, candidate: 1, legacy: 2 };
|
|
20
|
+
const byTenant = new Map<string, any[]>();
|
|
21
|
+
for (const [path, mod] of Object.entries(themeModules)) {
|
|
22
|
+
const m = /\/tenants\/([^/]+)\/content\/themes\//.exec(path);
|
|
23
|
+
const tenant = m?.[1];
|
|
24
|
+
if (!tenant) continue;
|
|
25
|
+
if (!byTenant.has(tenant)) byTenant.set(tenant, []);
|
|
26
|
+
byTenant.get(tenant)!.push(mod);
|
|
27
|
+
}
|
|
28
|
+
const tenants = [...byTenant.entries()]
|
|
29
|
+
.map(([tenant, themes]) => ({
|
|
30
|
+
tenant,
|
|
31
|
+
themes: themes.sort((a, b) => (ROLE_ORDER[a.role] ?? 9) - (ROLE_ORDER[b.role] ?? 9)),
|
|
32
|
+
}))
|
|
33
|
+
.sort((a, b) => a.tenant.localeCompare(b.tenant));
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
<!doctype html>
|
|
37
|
+
<html lang="en">
|
|
38
|
+
<head>
|
|
39
|
+
<meta charset="utf-8" />
|
|
40
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
41
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
42
|
+
<title>Style guides — all clients (preview)</title>
|
|
43
|
+
<style nonce={cspNonce}>
|
|
44
|
+
:root { color-scheme: light; }
|
|
45
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; background: #0f1729; color: #e6edf6; line-height: 1.55; }
|
|
46
|
+
.wrap { max-width: 920px; margin: 0 auto; padding: 48px 24px 80px; }
|
|
47
|
+
.flag { display: inline-block; font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; background: #f59e0b; color: #221600; font-weight: 800; padding: 4px 10px; border-radius: 6px; }
|
|
48
|
+
h1 { font-size: 1.9rem; margin: 18px 0 6px; }
|
|
49
|
+
.sub { color: #9fb0c8; margin: 0 0 32px; }
|
|
50
|
+
.tenant { margin-bottom: 30px; }
|
|
51
|
+
.tenant > h2 { font-size: 1.05rem; margin: 0 0 12px; display: flex; align-items: baseline; gap: 10px; }
|
|
52
|
+
.tenant > h2 a { color: #bfe0ff; font-size: .82rem; font-weight: 600; text-decoration: none; }
|
|
53
|
+
.card { display: block; text-decoration: none; color: inherit; background: #16223c; border: 1px solid #24324f; border-radius: 14px; padding: 16px 20px; margin-bottom: 12px; transition: border-color .15s, transform .15s; }
|
|
54
|
+
.card:hover { border-color: #3f5680; transform: translateY(-2px); }
|
|
55
|
+
.row { display: flex; align-items: center; gap: 12px; }
|
|
56
|
+
.badge { font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; font-weight: 800; padding: 3px 9px; border-radius: 999px; }
|
|
57
|
+
.badge.current { background: #0e9f8e; color: #001f1a; }
|
|
58
|
+
.badge.candidate { background: #6f7dff; color: #060a26; }
|
|
59
|
+
.badge.legacy { background: #47536e; color: #dfe6f2; }
|
|
60
|
+
.status { margin-left: auto; font-size: .78rem; color: #9fb0c8; font-family: ui-monospace, Menlo, monospace; }
|
|
61
|
+
.name { font-weight: 700; font-size: 1.02rem; }
|
|
62
|
+
.desc { color: #9fb0c8; font-size: .88rem; margin-top: 6px; }
|
|
63
|
+
.note { margin-top: 28px; font-size: .82rem; color: #7f8fab; border-top: 1px solid #24324f; padding-top: 16px; }
|
|
64
|
+
</style>
|
|
65
|
+
</head>
|
|
66
|
+
<body>
|
|
67
|
+
<div class="wrap">
|
|
68
|
+
<span class="flag">Preview · dev only · noindex</span>
|
|
69
|
+
<h1>Client style guides</h1>
|
|
70
|
+
<p class="sub">Every tenant and its theme guides. Open a guide to preview the standard components and page sections re-skinned under that theme. Nothing here re-skins a live site.</p>
|
|
71
|
+
|
|
72
|
+
{tenants.map(({ tenant, themes }) => (
|
|
73
|
+
<section class="tenant">
|
|
74
|
+
<h2>
|
|
75
|
+
{tenant}
|
|
76
|
+
<a href={`/_style-guide/${tenant}/`}>tenant hub →</a>
|
|
77
|
+
{themes[0]?.id && <a href={`/_style-guide/${tenant}/guide/${themes[0].id}/`}>widget library guide →</a>}
|
|
78
|
+
</h2>
|
|
79
|
+
{themes.map((t) => (
|
|
80
|
+
<a class="card" href={`/_style-guide/${tenant}/${t.id}/`}>
|
|
81
|
+
<div class="row">
|
|
82
|
+
<span class:list={["badge", t.role]}>{t.role}</span>
|
|
83
|
+
<span class="name">{t.name}</span>
|
|
84
|
+
<span class="status">{t.status}</span>
|
|
85
|
+
</div>
|
|
86
|
+
{t.description && <p class="desc">{t.description}</p>}
|
|
87
|
+
</a>
|
|
88
|
+
))}
|
|
89
|
+
</section>
|
|
90
|
+
))}
|
|
91
|
+
|
|
92
|
+
<p class="note">
|
|
93
|
+
These are preview/dev review surfaces — excluded from the sitemap and production marketing
|
|
94
|
+
publishing. Approve a tenant's <b>current</b> guide before propagating its style concept across the site.
|
|
95
|
+
</p>
|
|
96
|
+
</div>
|
|
97
|
+
</body>
|
|
98
|
+
</html>
|