+ {product.name} +
+{product.blurb}
+diff --git a/src/app/about/page.module.css b/src/app/about/page.module.css new file mode 100644 index 0000000..5f74edc --- /dev/null +++ b/src/app/about/page.module.css @@ -0,0 +1,32 @@ +@reference '../../styles/globals.css'; + +.page { + @apply mx-auto max-w-3xl px-10 py-12; +} + +.title { + @apply font-display text-4xl text-fg; +} + +.subtitle { + @apply mb-3 mt-10 font-display text-2xl text-fg; +} + +.lead { + @apply mt-4 text-lg text-fg; +} + +.body { + @apply mt-4 leading-relaxed text-muted; +} + +.inlineCode { + @apply rounded bg-surface2 px-1 py-0.5 text-sm text-fg; + font-family: var(--font-mono); +} + +.code { + @apply mt-2 overflow-x-auto rounded bg-surface2 p-4 text-sm text-fg; + font-family: var(--font-mono); + border: 1px solid var(--color-line); +} diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx new file mode 100644 index 0000000..96cff0e --- /dev/null +++ b/src/app/about/page.tsx @@ -0,0 +1,63 @@ +import { store } from '@config/store'; +import { stores } from '@config/stores'; +import styles from './page.module.css'; + +const exampleCss = `/* ProductCard.module.css — one file, every storefront */ +.cta { + @apply mt-5 inline-block text-sm; + color: var(--color-accent); +} + +@store executive { .cta { @apply text-[10px] uppercase tracking-[0.28em]; } } +@store crypto { .cta { @apply w-full rounded-lg bg-accent py-3 font-bold; } } +@store supper { .cta { @apply rounded-full bg-accent px-5 py-2.5; } } +@store collector { .cta { @apply border px-4 py-2; } }`; + +const examplePlugin = `// postcss-storestyles keeps only the active store's blocks. +// shopSystem = NEXT_PUBLIC_STORE_CODE.split('_')[0] // e.g. "crypto" +if (atRule.params !== shopSystem && !atRule.params.startsWith(shopSystem + '_')) { + atRule.remove(); // dropped from the build +} else { + atRule.replaceWith(atRule.nodes); // unwrapped into plain CSS +}`; + +export default function AboutPage() { + return ( +
+ You are looking at {store.brandName} — the{' '}
+ {store.code} storefront. The other three —{' '}
+ {stores
+ .filter((s) => s.code !== store.code)
+ .map((s) => s.label)
+ .join(', ')}{' '}
+ — are the same React components and the same CSS files. No component knows which store it is.
+
+ Every visual difference — colour, type, spacing, even layout — lives inside{' '}
+ @store blocks in the CSS. A small PostCSS plugin,{' '}
+ postcss-storestyles, runs at build time and keeps only the blocks
+ that match NEXT_PUBLIC_STORE_CODE. Every other store's styles
+ are stripped before they reach the browser, so each build ships one lean stylesheet with zero runtime branching.
+
+ {exampleCss}
+
+
+
+ {examplePlugin}
+
+
+ + Each storefront is its own build, deployed to its own Cloudflare Worker. One codebase, four storefronts, each + maintained in the file it belongs to. +
+{store.featured.body}
+ +{store.hero.body}
+ +{product.blurb}
+{product.blurb}
+ +“{review.q}”+