Files
summercms/.planning/phases/11.2-ready-to-share-summercms-io-website-and-newsletter-plugin/11.2-01-SUMMARY.md

17 KiB

phase, plan, subsystem, tags, requires, provides, affects, actuals, plan_head_before, plan_head_after, commits_repo, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects actuals plan_head_before plan_head_after commits_repo tech-stack key-files key-decisions patterns-established requirements-completed coverage duration completed status
11.2-ready-to-share-summercms-io-website-and-newsletter-plugin 01 ui
nuxt4
vue
nuxt-i18n
nuxt-seo
nuxt-fonts
ssg
node-test
imagemagick
phase provides
11.1-summercms-documentation-for-humans-and-ai-agents the /docs pages the landing page links to (served by the Go binary, not by Nuxt)
vue-summercmsio-app repository (master, no remote) generating the summercms.io landing page with nuxt generate
.output/public contract for plan 11.2-02: index.html, 200.html, 404.html, _nuxt/, _fonts/, _i18n/<hash>/en/messages.json, _payload.json, flat sitemap.xml, robots.txt, og-image.png, favicons, sun images
app/data/terminal.json: the single source of the six Get started commands (groups[].comment i18n key, groups[].commands)
pure utilities copyPayload (app/utils/terminal.ts) and activeSection/SPY_SECTIONS/SPY_THRESHOLD (app/utils/scrollSpy.ts)
11.2-02 site plugin embed and link check
11.2-02 D-40 terminal command check
11.2-03 unit tests
11.3 Polish locale
tokens tasks commits
13246 3 4
null 17e9f923559f6c2a9f176bdb5ae3aa78af934d9f /media/nvme/dev/golem15/summercms.io/summercms/sm-summercmsio-app/vue-summercmsio-app
added patterns
nuxt 4.4.8
@nuxt/fonts 0.14.0
@nuxtjs/i18n 10.4.0
@nuxtjs/seo 5.2.1
vue 3.5.35
typescript 5.9.3 (dev)
Plain CSS: tokens as :root custom properties (tokens.css), shared shapes in base.css, scoped component styles
All copy in i18n/locales/en.json; inline code inside copy via <i18n-t> named slots, never raw HTML
Width-dependent UI via CSS media queries only, so the server render never depends on the viewport
Pure, erasable-TypeScript utilities under app/utils/ run directly by node --test with .ts specifiers
Output tests read .output/public and en.json, resolving paths from import.meta.url
created modified
../sm-summercmsio-app/vue-summercmsio-app/nuxt.config.ts
../sm-summercmsio-app/vue-summercmsio-app/app/app.config.ts
../sm-summercmsio-app/vue-summercmsio-app/app/pages/index.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/SiteHeader.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/HeroSection.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/WhySection.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/FeaturesSection.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/WinterSection.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/StartSection.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/TerminalCard.vue
../sm-summercmsio-app/vue-summercmsio-app/app/components/SiteFooter.vue
../sm-summercmsio-app/vue-summercmsio-app/app/assets/css/tokens.css
../sm-summercmsio-app/vue-summercmsio-app/app/assets/css/base.css
../sm-summercmsio-app/vue-summercmsio-app/app/data/terminal.json
../sm-summercmsio-app/vue-summercmsio-app/app/utils/terminal.ts
../sm-summercmsio-app/vue-summercmsio-app/app/utils/scrollSpy.ts
../sm-summercmsio-app/vue-summercmsio-app/i18n/locales/en.json
../sm-summercmsio-app/vue-summercmsio-app/scripts/derive-images.sh
../sm-summercmsio-app/vue-summercmsio-app/assets-src/logo.png
../sm-summercmsio-app/vue-summercmsio-app/public/og-image.png
../sm-summercmsio-app/vue-summercmsio-app/tests/output.test.ts
../sm-summercmsio-app/vue-summercmsio-app/tests/terminal.test.ts
../sm-summercmsio-app/vue-summercmsio-app/tests/scrollSpy.test.ts
Page title is 'SummerCMS: A new dawn in content management' with titleTemplate '%s' so the site name is not appended twice; description is the hero paragraph
Header sun is the 30px original scaled 1.12 without the handoff mask (the mask only cropped the screenshot placeholder); hero badge shows the sun at 136px
Header at phone widths: at 720px and below the empty links wrapper is hidden and Docs is pushed right; at 420px and below the row gap is 10px and side padding 16px, because logo + pill + Docs overflowed 375px with the handoff spacing
Copy falls back to a hidden textarea + execCommand('copy') when navigator.clipboard is missing or rejects; a failed copy leaves the label unchanged
Footer link group may wrap (flex-wrap) so the four links never overflow a phone width
en.json leaf check: every message leaf (minus interaction-only keys) must appear HTML-escaped in index.html
terminal.json comment keys resolve in en.json; the output test reads commands from terminal.json, never a second list
id description verification human_judgment
D1 nuxt generate prerenders index.html with header, hero #top, #why, #features, #winter, #start and the footer in handoff order
kind ref status
other pnpm generate (exit 0, no prerender errors) pass
kind ref status
automated_ui tests/output.test.ts#sections appear in handoff order: top, why, features, winter, start, then the footer pass
false
id description verification human_judgment
D2 Every visible string comes from i18n/locales/en.json with the single en locale at /
kind ref status
automated_ui tests/output.test.ts#every en.json string is rendered on the page pass
kind ref status
automated_ui tests/output.test.ts#i18n messages are emitted for the client under /_i18n pass
false
id description verification human_judgment
D3 Roboto and Roboto Mono self-hosted under /_fonts with no Google font host in generated HTML or CSS
kind ref status
automated_ui tests/output.test.ts#fonts are self-hosted under /_fonts pass
kind ref status
automated_ui tests/output.test.ts#no generated HTML or CSS references a Google font host pass
false
id description verification human_judgment
D4 Static SEO: canonical, OG (absolute og:image), Twitter, schema.org JSON-LD, flat sitemap.xml and robots.txt
kind ref status
automated_ui tests/output.test.ts#the page head carries canonical, Open Graph, Twitter and schema.org tags pass
kind ref status
automated_ui tests/output.test.ts#robots.txt points at the flat sitemap.xml pass
false
id description verification human_judgment
D5 All docs, source and credit links: eight extension-less tiles, concept map, installation guide, /docs, Source x2, golem15.com
kind ref status
automated_ui tests/output.test.ts#feature tiles and the concept map link to the docs, extension-less pass
kind ref status
automated_ui tests/output.test.ts#the footer links to the source and credits Golem15 pass
kind ref status
automated_ui tests/output.test.ts#Get started shows the chips, the six commands, their comments and the links pass
false
id description verification human_judgment
D6 Terminal card renders the six terminal.json commands; Copy writes exactly those six lines
kind ref status
unit tests/terminal.test.ts#copyPayload joins the six commands in order pass
kind ref status
unit tests/terminal.test.ts#every terminal.json comment key resolves to a string in en.json pass
false
id description verification human_judgment
D7 Scroll-spy selection: last of why/features/winter/start with top < 140, none above #why
kind ref status
unit tests/scrollSpy.test.ts#the last section above the threshold wins pass
kind ref status
unit tests/scrollSpy.test.ts#a top of exactly the threshold is not active pass
false
id description verification human_judgment rationale
D8 Visual fidelity at 1280/721/720/375px, sticky header while scrolling, live scroll-spy highlight, Copy -> Copied for 1.5s and clipboard contents, hero rays and sun badge vs the handoff
true Pixel and interaction fidelity in a real browser is the end-of-phase UAT backstop (plan must_haves); headless screenshots at 1280/375/360/720/721 were only a sanity check
12min 2026-10-01 complete

Phase 11.2 Plan 01: summercms.io Nuxt landing page Summary

Nuxt 4 static landing page in the new vue-summercmsio-app repo. It has self-hosted Roboto, a single en locale holding every string, static SEO and sitemap output, the original sun in every image, and a Get started terminal card driven by one terminal.json. It is verified by 29 node:test assertions over the utilities and the generated .output/public.

Performance

  • Duration: 12 min
  • Started: 2026-10-01T13:43:15Z
  • Completed: 2026-10-01T13:55:16Z
  • Tasks: 3 (tracer + auto + TDD)
  • Files created: 35 tracked files in vue-summercmsio-app (no summercms.go code changes)

Accomplishments

  • New repository /media/nvme/dev/golem15/summercms.io/summercms/sm-summercmsio-app/vue-summercmsio-app (branch master, no remote). Packages are pinned exactly to the fonoteka versions, pnpm-lock.yaml is committed, and allowBuilds is limited to @parcel/watcher, esbuild and vue-demi.
  • nuxt generate exits 0 and writes real prerendered HTML: the sticky header, the hero #top, #why, #features, #winter, #start and the footer, in that order. /docs is ignored by the prerender crawler.
  • @nuxt/fonts self-hosts 4 woff2 files under /_fonts/. The generated HTML and CSS name no Google font host.
  • @nuxtjs/seo writes the canonical link, OG tags (absolute https://summercms.io/og-image.png), Twitter tags, schema.org @graph, a flat sitemap.xml and a robots.txt with a Sitemap line. ogImage is disabled and a static PNG is shipped instead.
  • scripts/derive-images.sh (ImageMagick only) derives sun-logo.webp (60px), sun-badge.webp (272px), favicon.ico (16/32/48), apple-touch-icon.png (180, on navy) and og-image.png (1200x630: sun, wordmark, tagline) from the committed original assets-src/logo.png (746x744). sun-crop.png is not shipped.
  • app.config.ts has landing.showRays and landing.scrollSpy. Setting showRays: false was checked to remove the rays div from the output.
  • Scroll-spy uses a passive scroll listener, computes on mount and is cleaned up on unmount. The server render has no active link.
  • Copy uses copyPayload (six lines, no $ or comments) with a textarea fallback, and shows Copied for 1500 ms.

Task Commits

All in vue-summercmsio-app:

  1. Task 1: Tracer: scaffold with header, hero, fonts and SEO: c41cdac (feat)
  2. Task 2: Why, Features, From WinterCMS and footer: a29b2d2 (feat)
  3. Task 3 (TDD): terminal card, copy button and scroll-spy: RED d2ffb9b (test), GREEN 17e9f92 (feat). No refactor was needed.

Plan metadata: committed in summercms.go (docs commit for this SUMMARY)

TDD Gate Compliance

  • RED d2ffb9b: tests plus interface-only stubs (correct exports and signatures, placeholder bodies), so the failures are assertion failures, not load crashes. node --test tests/terminal.test.ts tests/scrollSpy.test.ts gave exit 1 with 8 of 13 failing. gsd-tools check tdd-red-evidence returned RED_EVIDENCE_OK for the targets "the last section above the threshold wins" (expected winter, got '') and "copyPayload skips a group without commands" (expected one\ntwo\nthree, got '').
  • GREEN 17e9f92: 29 of 29 pass in pnpm test, and 13 of 13 in the two unit files.

Files Created/Modified

  • nuxt.config.ts: modules, fonts, i18n (prefix_except_default, prerenderMessages), site, ogImage off, flat sitemap, link-checker exclusion, nitro.prerender.ignore: ['/docs'].
  • app/components/*.vue: SiteHeader (sticky bar, scroll-spy, CSS-hidden links at 720px or less), HeroSection (rays behind the flag, glow, badge, gradient H1, CTAs), WhySection (<i18n-t> slots for the file names), FeaturesSection (eight extension-less docs tiles), WinterSection (concept table), StartSection (chips, note, buttons), TerminalCard, SiteFooter (with the Golem15 credit).
  • app/assets/css/tokens.css, base.css: tokens, globals with a reduced-motion scroll override, and the shared heading, button and chip shapes.
  • app/data/terminal.json, app/utils/terminal.ts, app/utils/scrollSpy.ts: the single command source and the pure helpers.
  • i18n/locales/en.json: meta, header, hero, why, features, winter, start, terminal, footer.
  • tests/output.test.ts, tests/terminal.test.ts, tests/scrollSpy.test.ts: node:test, with paths resolved from import.meta.url.

Decisions Made

See key-decisions in the frontmatter. In short: the full page title with a %s template, the unmasked sun scaled 1.12 in the header, the phone-width header fix, the clipboard fallback, and footer links that can wrap.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] The header overflowed phone widths

  • Found during: Task 3 (headless screenshot sanity check at 375px)
  • Issue: With the handoff spacing (an empty flex: 1 links wrapper and three 16px gaps), logo + pill + Docs needed about 414px. At 375px the Docs button was clipped and the right padding was lost. The handoff markup has the same overflow.
  • Fix: At 720px and below, .links-wrap is hidden and .docs gets margin-left: auto. At 420px and below, .bar uses gap: 10px; padding: 0 16px. Above 720px nothing changes.
  • Files modified: app/components/SiteHeader.vue
  • Verification: Headless screenshots at 360, 375, 720 and 721px. The header fits, links are hidden at 720 and visible at 721. 29 of 29 tests pass.
  • Committed in: 17e9f92

2. [Rule 1 - Bug] Footer links could overflow a phone width

  • Found during: Task 2
  • Issue: The D-12 credit makes four footer links. The handoff's non-wrapping link row is close to the 327px content width at 375px.
  • Fix: flex-wrap: wrap on the footer link group. Nothing changes when they fit.
  • Files modified: app/components/SiteFooter.vue
  • Committed in: a29b2d2

3. [Process] Task 3 committed as RED + GREEN instead of one commit

  • The plan asked for one feat(site) commit holding the tests and the implementation. Following the TDD reference, the tests went in a test(site) RED commit (with interface-only stubs so RED fails on assertions) and the implementation in the feat(site) commit with the planned message. pnpm test is red at d2ffb9b by design.

4. [Minor] Small structural choices inside the plan's latitude

  • The en.json leaf-check helper lives inside tests/output.test.ts, not in a separate helper file, so tests/*.test.ts matches only test files. It takes an except list for terminal.copied, which only appears after a click.
  • The Docs → label is two keys (header.docs, header.docsArrow) so the arrow sits in its own span, as in the handoff.
  • <html lang> renders as en-US (from language: 'en-US'). The test matches <html\s+lang="en.

Total deviations: 2 auto-fixed bugs (Rule 1), 1 process deviation (TDD commit split), and minor structural choices. Impact on plan: The responsive fixes keep D-23 fidelity above 720px and make SC1's "responsive down to phone width" true. There is no scope creep.

Issues Encountered

  • A bash pkill -f pattern matched its own shell and killed the screenshot command after the screenshots were written. Later runs stopped the server by PID instead. No effect on the repository.

User Setup Required

None. Creating the vue-summercmsio-app remote on git.golem15.com is a D-43 launch item listed for plan 11.2-02.

Next Phase Readiness

  • Plan 11.2-02 can rsync .output/public/ (not the dist symlink) into the plugin's public/site/ and embed it with all: (the output has _nuxt/, _fonts/, _i18n/, _payload.json and __sitemap__/). _nuxt/builds/ is not content-hashed.
  • app/data/terminal.json is ready for the D-40 Go check and the HTML drift guard. Commands render contiguously after a <span class="prompt">$ </span>.
  • The page uses extension-less /docs/... hrefs (D-47), so the plugin must 301 them to .html.
  • End-of-phase UAT: visual fidelity at 1280, 721, 720 and 375px, the sticky header, the live scroll-spy, and the Copy label and clipboard (coverage D8).

Self-Check: PASSED

  • Files: all 35 tracked files are present in vue-summercmsio-app (git ls-files), including every key-files.created entry.
  • Commits: c41cdac, a29b2d2, d2ffb9b and 17e9f92 are in vue-summercmsio-app master. The commit count of 4 was measured with git rev-list --count master.
  • Plan verification: pnpm install --frozen-lockfile && pnpm generate && pnpm test gives 29 pass and 0 fail. The SITE working tree is clean. summercms.go shows only its pre-existing STATE.md, state.json and zip changes. No co-author trailers.

Phase: 11.2-ready-to-share-summercms-io-website-and-newsletter-plugin Completed: 2026-10-01