From 4244792b435eec1636c722c8d91d5f20b4380bfb Mon Sep 17 00:00:00 2001 From: Lars Weiser Date: Wed, 29 Apr 2026 10:44:23 +0200 Subject: [PATCH 1/6] feat(products): empty-state index + nav/footer + filter helper (G C.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src/pages/produkte/index.astro + en/products/index.astro: empty state from BASELINE_COPY.md §5 verbatim, single-column centered, atmospheric arc bottom-right at low opacity (8% light / 14% dark / 6% mobile). Populated branch wired but unexercised in v1 (no products in the collection). - src/lib/products.ts: getVisibleProducts(lang) helper, interim form — filters by isProduction() + draft. The releaseDate branch lands in G C.2.a alongside the schema field. - SiteHeader / SiteFooter: Products entry first per design bundle order; re-orders existing About/Contact entries. - src/i18n/{de,en}.ts: new productsIndex namespace (h1, breadcrumb, populated arrow label, arc aria-label). - Doc revisions softening "no product names until launch" to "no names on production; dev may carry drafted/scheduled named entries": TECH_STACK §1.2, §13.5; DESIGN_BRIEF §7. --- docs/CLAUDE_DESIGN_BRIEF.md | 2 +- docs/TECH_STACK.md | 4 +- src/components/SiteFooter.astro | 2 + src/components/SiteHeader.astro | 9 + src/i18n/de.ts | 7 + src/i18n/en.ts | 7 + src/lib/products.ts | 24 +++ src/pages/en/products/index.astro | 267 ++++++++++++++++++++++++++++ src/pages/produkte/index.astro | 278 ++++++++++++++++++++++++++++++ 9 files changed, 597 insertions(+), 3 deletions(-) create mode 100644 src/lib/products.ts create mode 100644 src/pages/en/products/index.astro create mode 100644 src/pages/produkte/index.astro diff --git a/docs/CLAUDE_DESIGN_BRIEF.md b/docs/CLAUDE_DESIGN_BRIEF.md index 0f8e14a..0cfd4cf 100644 --- a/docs/CLAUDE_DESIGN_BRIEF.md +++ b/docs/CLAUDE_DESIGN_BRIEF.md @@ -255,7 +255,7 @@ Do not: add a container, tilt, outline, gradient, color-fill with anything outsi - **First person singular, never plural.** "We" implies a team; this is one person. "I" on authored content; brand name everywhere else. - **Lars is not a teacher.** Copy should position him as a developer who builds for teachers, based on listening to them. Do not fabricate classroom experience. The honest framing is more distinctive than the faked one. -- **No product names** until products launch. Reference them by area of focus, not by name. +- No product names in the production website's editorial copy until products formally launch. (Dev may carry drafted/scheduled named entries for in-progress verification.) Reference products by area of focus in editorial text. - **German copy:** clear Hochdeutsch, no buzzwords, no Anglizismen unless the English term is genuinely the term of art (e.g., "Release Notes" is acceptable; "Solution Provider" is not). - **English copy:** plain English. Short sentences. British or American are both fine; be consistent per page. - **Never call teachers "users."** Call them "teachers" or "Lehrkräfte" or address them directly. diff --git a/docs/TECH_STACK.md b/docs/TECH_STACK.md index 347dcef..464cbd1 100644 --- a/docs/TECH_STACK.md +++ b/docs/TECH_STACK.md @@ -32,7 +32,7 @@ Blackbrowed Labs builds tools for classroom management. Two areas are in active - An **iPadOS app** for classroom management (grades, student work, observations, without paperwork). Will launch as the first product on its own domain with an independent website and design system. - A **Claude Cowork plugin** that helps teachers plan units and lessons. -**Product names are deliberately not referenced on this website** until each product formally launches. The website blackbrowedlabs.com acts as the **studio's home page**, not as marketing surface for individual products. When products launch, they get a **minimal presence** here: name, short description, current version, recent release notes (auto-pulled from GitHub), and a prominent link to the product's own site. The marketing depth lives on each product's own website. +Product names are deliberately not surfaced on the production website until each product formally launches. Dev may carry named product entries marked `draft: true` (or with a future `releaseDate`) for in-progress visual verification; these are filtered out of the production build. The website blackbrowedlabs.com acts as the studio's home page, not as marketing surface for individual products. When products launch, they get a **minimal presence** here: name, short description, current version, recent release notes (auto-pulled from GitHub), and a prominent link to the product's own site. The marketing depth lives on each product's own website. ### 1.3 Editorial profile @@ -699,7 +699,7 @@ All fonts, images, and scripts served from the Worker (same origin). No `fonts.g 11. `wrangler.jsonc` with named environments and Custom Domain bindings. 3. **Use the `frontend-design` skill** whenever writing UI components. 4. **Do not invent** company copy, product names, Impressum details, or Datenschutz text. Use exactly what's in `BASELINE_COPY.md`. -5. **Do not reference specific product names** (such as product working titles you may learn from other sources) in any generated copy. The website does not name products until they launch. +5. Do not reference specific product names in editorial copy or page templates. Per-product Markdown files under `src/content/products/` carry the product's name and surface on production only when `draft: false` and any `releaseDate` is in the past (see §1.2 + §5.2). 6. **Do not install a CMS.** v1 is Git-only editing. 7. **Do not swap the palette or typography.** If the design bundle from Claude Design contradicts the brief, stop and surface the conflict. 8. **Do not imply Lars is a teacher** in any generated copy. He's a developer who builds for teachers. diff --git a/src/components/SiteFooter.astro b/src/components/SiteFooter.astro index 1496a7e..e99b859 100644 --- a/src/components/SiteFooter.astro +++ b/src/components/SiteFooter.astro @@ -14,6 +14,7 @@ const path = Astro.url.pathname; const locale = getLocaleFromPath(path); const t = getUiStrings(locale).footer; +const productsHref = locale === 'de' ? '/produkte' : '/en/products'; const aboutHref = locale === 'de' ? '/ueber' : '/en/about'; const contactHref = locale === 'de' ? '/kontakt' : '/en/contact'; const legalHref = locale === 'de' ? '/impressum' : '/en/legal'; @@ -28,6 +29,7 @@ const privacyHref = locale === 'de' ? '/datenschutz' : '/en/privacy';