Phase C — Products subtree (empty state + Thalura draft fixture)#12
Merged
Conversation
- 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.
- src/content.config.ts: products schema additions — releaseDate (z.coerce.date().optional()), externalUrl/repo both optional with .refine() requiring at least one. Schema additions are forward-defensive; no product entries exercise them yet (G C.2.b lands the first). - src/lib/products.ts: helper extended to filter on releaseDate > now in production, complementing the draft gate. - src/pages/produkte/[slug].astro + en mirror: minimal-stub detail template (eyebrow + H1 + tagline + description + CTA). Version chip and release-history stack are deliberately deferred to Phase D when real release data exists. - docs/TECH_STACK.md §5.2: documents visibility gates (draft + releaseDate) and the schema refine semantics.
…m tokens Addresses two defects surfaced by G C.2.a code-quality review. BLOCKER fix — dark-mode primary-CTA contrast: - .cta--primary's `color: white` hardcoded in both detail templates fails AA (and AAA) in dark mode: white on #D4A45C ≈ 1.95:1. CLAUDE_DESIGN_BRIEF §4.5 mandates dark text on dark-mode color chips. Replace with var(--color-cta-text) which is already wired in tokens.css to swap #FFFFFF → #1C1C1E by mode (matches the ContactForm precedent). MAJOR fix — undefined CTA hover tokens: - var(--color-primary-hover) → var(--color-bbl-primary-hover) (project's existing semantic alias at tokens.css:115). - var(--color-bg-card) → var(--color-surface-card) (project's semantic alias for bg-card per CLAUDE_DESIGN_BRIEF §4.4 + §4.7, at tokens.css:54). - Originals were undefined; CSS silently dropped the hover declarations. Cheap MINOR fixes folded in: - .product-detail__container declared max-width twice; drop the dead var(--max-width-site) line (the 70ch override was already winning). - rel="noopener" extended to the external-website CTA branch (was only on the GitHub-fallback). Security baseline for third-party links. Verification: - npm run check: 0 errors. - npm run build: succeeds; 13 pages built. - Empty-state regression: /produkte + /en/products still render the BASELINE §5 copy verbatim.
Primary scope:
- src/content/products/thalura-plugin.{de,en}.md: first product entry
(Thalura für Claude Cowork / Thalura for Claude Cowork). draft: true →
visible on dev only, hidden on prod via env-aware filter. CTA falls
back to GitHub repo URL (thalura.app/.de domains registered but not
yet landing-page-live).
Cleanup fold-ins from G C.1 review:
- Tap-target fix on .products-index__more: min-height 44px + flex
alignment so the populated-grid arrow link meets AAA when the branch
goes live with this gate.
- Doc bold-marker restoration in TECH_STACK §1.2 + §13.5 and
DESIGN_BRIEF §7 (G C.1's verbatim plan replacements dropped lead-
clause bold; sibling list items use bold to anchor each rule).
- Dark-mode selector idiom unified: :global([data-theme="dark"]) →
:root[data-theme="dark"] in the Products index pages, matching the
ThemeToggle.astro precedent.
- Breadcrumb aria-label moved to i18n: src/i18n/{de,en}.ts gain
breadcrumb.ariaLabel ('Brotkrümelnavigation' / 'Breadcrumb');
retrofit applied to all 8 breadcrumb-bearing pages (impressum,
datenschutz, en/legal, en/privacy, produkte/index, en/products/index,
produkte/[slug], en/products/[slug]).
Verification:
- Default build (PUBLIC_ENVIRONMENT unset): Thalura visible, locale-
correct breadcrumb labels on all 8 pages, tap-target compliant.
- Production build (PUBLIC_ENVIRONMENT=production): Thalura filtered;
retrofit holds on the 4 live legal pages without regression.
…ed pages Closes the breadcrumb i18n retrofit gap surfaced by both G C.2.b reviewers: my spec said "all 8 breadcrumb-bearing pages" but the site actually has 12. Four pages were left out and continued to hardcode aria-label="Breadcrumb", including two DE pages (ueber, kontakt) that consequently served the English label to German screen-reader users — the locale-mismatch bug fold-in #4 was meant to eliminate. Pages retrofitted: - src/pages/ueber.astro (DE → Brotkrümelnavigation) - src/pages/kontakt.astro (DE → Brotkrümelnavigation) - src/pages/en/about.astro (EN → Breadcrumb, now i18n-driven) - src/pages/en/contact.astro (EN → Breadcrumb, now i18n-driven) Each page gains: - Import: getUiStrings from the appropriate relative path - Const: t = getUiStrings('de'|'en') - aria-label="Breadcrumb" → aria-label={t.breadcrumb.ariaLabel} No other changes; no content/whitespace/CSS drift on these pages. Verification: - npm run check: 0 errors. - npm run build: 15 pages. - All 12 breadcrumb-bearing pages now serve their locale-correct aria-label: 6 DE pages ("Brotkrümelnavigation"), 6 EN pages ("Breadcrumb"). Zero pages still hardcode "Breadcrumb" in DE markup.
…age switcher Two findings from the G C.2.b dev walk, both addressed in one fix-up commit within the gate's reserved fix-up budget. Finding 1 — GitHub fallback CTA points at private repo: The G C.2.a auto-fallback rendered a "View on GitHub" CTA whenever externalUrl was absent. That broke for products with private repos (thalura-plugin is private currently): the CTA pointed at a 404 / sign-in page for unauthenticated visitors. Inverted the default to opt-in: - Schema gains `showGithubLink: z.boolean().optional()`. - Detail template renders the GitHub CTA only when `showGithubLink === true` AND `repo` is set. - Thalura entries don't set the flag → no CTA on detail pages, exactly what we want while the repo is private. Conservative default: forgetting the flag means "no CTA renders," not "broken CTA points at 404." Phase D's release loader is expected to supersede this manual flag with GitHub-API auto-detection of repo visibility — the flag then becomes either redundant or a force-show / force-hide override. Finding 2 — Language switcher dead on product detail pages: src/lib/i18n.ts carried a static counterpart map covering only named pages (homepage, about, products index, etc.). Dynamic detail pages (/produkte/<slug>) had no map entry, so getCounterpartUrl() returned null and the LanguageSwitcher rendered aria-disabled. Since detail-page slugs are deliberately the same across DE and EN (per TECH_STACK §5.2), extended getCounterpartUrl() with a deterministic slug-pattern fallback: /produkte/<slug> ↔ /en/products/<slug> getHreflangAlternates() refactored to call getCounterpartUrl() so both the switcher AND the hreflang link tags benefit from the dynamic logic. Doc: TECH_STACK §5.2 documents `showGithubLink` semantics + the Phase D auto-detect supersedes-this forward note. Verification: - npm run check: 0 errors. - npm run build: 15 pages. - Thalura DE + EN detail pages render WITHOUT a CTA (0 grep matches for "Auf GitHub ansehen" / "View on GitHub" — finding 1 closed). - Thalura DE detail page emits hreflang="en" href=".../thalura-plugin" and EN detail page emits hreflang="de" href=".../thalura-plugin" — finding 2 closed.
blackbrowed-labs
added a commit
that referenced
this pull request
May 12, 2026
…+ J.1 conventions doc) Lifts ~862 LOC of byte-identical scoped CSS out of the four products page templates (produkte/index, produkte/[slug], en/products/index, en/products/[slug]) into a single src/styles/products.css module, imported once via global.css. Closes Pass 2 backlog row #12. Class names stay BEM-namespaced (products-index__*, product-detail__*, release__*, breadcrumb__*, version-chip*, cta*) — no markup churn. All four scoped <style> blocks are deleted in their entirety; no page-private CSS survives because the DE/EN siblings were byte-identical except for documentation comments. Inside the .release__body block, the previous :global() pseudo-wrappers (needed for Astro-scoped <style> to reach raw markdown elements rendered via set:html) are removed — the new module is non-scoped so the selectors target the rendered <h1>/<p>/<ul>/etc. directly. Co-introduces docs/CSS_CONVENTIONS.md (Phase J.1, folded into this commit per the J plan's J.1 standalone-vs-fold decision). The doc records the module-location, class-naming, extraction-scope, specificity, and import- order disciplines that J.2 enforces and J.3 will follow. Verified locally: npm run check 0 errors / 0 warnings, npm run build clean, dist/_astro CSS bundle drops 56,575 → 43,203 bytes (−13.1 KB raw, four per-route _slug_/index@_@astro.*.css chunks merged into BaseLayout's single bundle). Every products class still emits in built HTML (grep); no astro- scoped hashes leak. Real-browser staging walk deferred to Wave 4 integration PR per controller instruction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase C ships the Products subtree on blackbrowedlabs.com:
/produkte+/en/productsrender the BASELINE §5 empty-state copy until a non-draft product launches. Nav and footer gain Products as the first entry on every page.[slug].astro× 2 with eyebrow + H1 + tagline + description + opt-in CTA (primary onexternalUrl; ghost-fallback onrepoonly whenshowGithubLink: true).getStaticPathsreturns[]on prod; renders Thalura on dev.releaseDate(scheduled publishing), optionalexternalUrl/repowith.refine()requiring at least one,showGithubLinkopt-in for GitHub CTA.draft: truetest fixture — visible on dev, hidden on prod. CTA suppressed because the plugin repo is currently private.aria-labeli18n retrofit across all 12 breadcrumb-bearing pages (closing a pre-existing locale-mismatch bug on/ueber+/kontakt).Six commits across three gates (G C.1, G C.2.a, G C.2.b) with three in-gate fix-ups landed within their respective gate windows.
Test plan
/produkteand/en/productsrender the empty-state copy verbatimaria-label(DE: "Brotkrümelnavigation", EN: "Breadcrumb")/produkte/thalura-pluginand/en/products/thalura-pluginreturn 404 on production (draft filter holds)🤖 Generated with Claude Code