Skip to content

feat(marketing): improve marketing starter template - #3058

Open
khoinguyenpham04 wants to merge 20 commits into
mainfrom
improve/marketing-template
Open

feat(marketing): improve marketing starter template#3058
khoinguyenpham04 wants to merge 20 commits into
mainfrom
improve/marketing-template

Conversation

@khoinguyenpham04

@khoinguyenpham04 khoinguyenpham04 commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Ports the visual language and frontend component structure of emdashcms.com into the public Node and Cloudflare marketing templates, while keeping the templates generic and reusable.

This includes:

  • a neutral navy and blue palette with light, dark, and system themes
  • responsive header, footer, hero, feature, testimonial, FAQ, and pricing components
  • complete homepage, pricing, contact, and 404 experiences
  • CMS-driven copy, menus, links, plans, testimonials, and optional media
  • matching Node and Cloudflare frontend trees with five queries on the logged-out route
  • refreshed template screenshots for desktop and mobile states

EmDash branding, dashboard imagery, announcement content, GitHub stars, playground links, and product-specific copy are intentionally excluded so generated sites remain suitable for public use.

Closes: Not applicable.

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable; these template-only changes use black-box browser acceptance and committed visual evidence)
  • User-visible strings in the admin UI are wrapped for translation (not applicable: the admin UI is unchanged). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added and reviewed the user-facing changeset (not applicable: no published package changed)
  • New features link to an approved Discussion: not linked; this draft is for maintainer design review before it is marked ready
  • I have included screenshots below if this PR changes the UI

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: OpenAI Codex (GPT-5)

Screenshots / test output

Homepage — light desktop

Full marketing template homepage in light mode on desktop

Homepage — dark mobile

Full marketing template homepage in dark mode on mobile

Pricing — light desktop

image

Blog

image

Contact — dark mobile

Marketing template contact page in dark mode on mobile

Verified locally:

  • pnpm build
  • pnpm typecheck
  • pnpm typecheck:templates
  • pnpm lint
  • Node and Cloudflare browser matrices across desktop/mobile and light/dark/system themes
  • menu open, Escape, focus restoration, no-JavaScript navigation, reduced motion, RTL, and long-content fixtures
  • contact idle, validation error, and success behavior
  • no browser console errors or horizontal overflow
  • five queries on the logged-out homepage

@changeset-bot

changeset-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 01cbe76

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 10, 2026

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://improve-marketing-template.try.emdashcms.com, https://improve-marketing-template-emdash-playground.emdash-cms.workers.dev (commit 01cbe76)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://954cdc32.try.emdashcms.com, https://954cdc32-emdash-playground.emdash-cms.workers.dev 01cbe76 2026-09-11T08:37:44.558Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://26f96c7e.try.emdashcms.com, https://26f96c7e-emdash-playground.emdash-cms.workers.dev 8ceb7f5 2026-09-11T01:00:01.673Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://7edae386.try.emdashcms.com, https://7edae386-emdash-playground.emdash-cms.workers.dev f1032ba 2026-09-11T00:46:53.198Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://dbaecf0b.try.emdashcms.com, https://dbaecf0b-emdash-playground.emdash-cms.workers.dev d24be02 2026-09-11T00:15:01.502Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://f2ba79fd.try.emdashcms.com, https://f2ba79fd-emdash-playground.emdash-cms.workers.dev ec325ff 2026-09-10T21:58:45.982Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://4eff4756.try.emdashcms.com, https://4eff4756-emdash-playground.emdash-cms.workers.dev 2f9838c 2026-09-10T21:30:36.274Z Visit the dashboard ↗

@github-actions

Copy link
Copy Markdown
Contributor

Scope check

This PR changes 6,104 lines across 45 files. Large PRs are harder to review and more likely to be closed without review.

If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs.

See CONTRIBUTING.md for contribution guidelines.

@pkg-pr-new

pkg-pr-new Bot commented Sep 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@3058

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@3058

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@3058

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@3058

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@3058

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@3058

emdash

npm i https://pkg.pr.new/emdash@3058

create-emdash

npm i https://pkg.pr.new/create-emdash@3058

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@3058

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@3058

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@3058

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@3058

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@3058

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/@emdash-cms/registry-moderation@3058

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@3058

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@3058

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@3058

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@3058

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@3058

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@3058

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@3058

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@3058

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@3058

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@3058

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@3058

commit: 01cbe76

@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

@khoinguyenpham04
khoinguyenpham04 marked this pull request as ready for review September 11, 2026 01:47
@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Sep 11, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR ports the public emdashcms.com visual language into the Node and Cloudflare marketing templates. The overall approach is sound: a componentized set of Portable Text blocks (hero/features/pricing/faq/testimonials/CTA), a small editorial blog, a contact page, matching Node/Cloudflare trees, an updated seed file, agent docs, and a regression smoke test. The rendering code is safe, uses EmDash’s locale-aware helpers, and the tests cover the new archive/cursor paths.

I reviewed the changed template files, seed, docs, and smoke test. I did not run the test suite or build; everything below is based on static inspection.

There are no logic bugs or security vulnerabilities in the rendering path, but there are several issues that should be addressed before merge:

  1. Logged-out query-count regression. Base.astro now pays for five menu/settings round-trips on every logged-out render (getSiteSettings + four getMenu calls). AGENTS.md is explicit: “Never add queries to the logged-out hot path” and treats increases as presumed wrong. The footer menus should be collapsed into a single hierarchical footer menu instead of three separate menus.

  2. EmDash branding remains in the public footer. The PR says EmDash branding was intentionally excluded, but SiteFooter.astro still links to emdashcms.com. That should be removed or made configurable before the template is used for public sites.

  3. Inaccurate color documentation. AGENTS.md and AGENTS-template.md list specific hex values for --color-bg, --color-surface, and --color-primary that do not match the actual tokens.css fallback palette, so agents following those docs will pick the wrong colors.

  4. Permanent redirect for /pricing. Returning a 301 from /pricing to /#pricing will be cached by browsers and search engines, which makes it hard for users to later create a real /pricing page. A 302/307 is safer for a starter template.

  5. Contact page caches POST responses. contact.astro calls Astro.cache.set(cacheHint) unconditionally and swallows errors, which means a POST submission may also try to write a cache entry. It should only cache the GET response.

  6. Comment discipline. src/plugins/marketing-blocks/index.ts, MarketingBlocks.astro, and contact.astro contain reviewer-facing notes, TODOs, and narrative that violate AGENTS.md’s comment rules. Move the demo-form caveats into the template docs and keep the code comments evergreen.

The same issues exist in the Cloudflare mirror templates (the relevant files are byte-for-byte copies in this PR), so any fixes should be applied to both templates/marketing/* and templates/marketing-cloudflare/*.


Findings

  • [needs fixing] templates/marketing/src/layouts/Base.astro:27

    Base.astro now issues five menu/settings round-trips on every logged-out page (getSiteSettings + getMenu("primary") + three footer menus). AGENTS.md says “Never add queries to the logged-out hot path” and that an increase is presumed wrong. The footer menus are a good candidate to collapse: create one hierarchical footer menu with Product, Company, and Support as top-level items and children underneath, then load only getMenu("primary") and getMenu("footer") here.

    const [menu, footerMenu] = await Promise.all([
    	getMenu("primary"),
    	getMenu("footer"),
    ]);
    
  • [needs fixing] templates/marketing/src/components/SiteFooter.astro:93

    The PR description says EmDash branding was intentionally excluded from the public templates, but the footer still hard-codes a “Powered by EmDash” link to emdashcms.com. Generated sites based on this template will ship with EmDash branding, which contradicts the stated goal. Remove this block (and the matching .footer-powered style) or make it a configurable site setting.

    			<div class="footer-legal">
    				<p>&copy; {currentYear} {siteTitle}.</p>
    			</div>
    
  • [suggestion] templates/marketing/src/pages/pricing.astro:2

    A 301 redirect is cached permanently by browsers and search engines. Because this is a starter template, a consumer may later want to turn /pricing into a real page; a cached 301 to /#pricing would make that painful. Use a non-permanent redirect such as 302 or 307.

    return Astro.redirect("/#pricing", 302);
    
  • [suggestion] templates/marketing/src/pages/contact.astro:11-12

    Astro.cache.set(cacheHint) is called unconditionally and errors are swallowed, which means the POST submission path also attempts to write a cache entry. Cache hints should only apply to GET responses. Replace the defensive try/catch with an explicit method check.

    if (Astro.request.method === "GET" && Astro.cache?.enabled) {
    	Astro.cache.set(cacheHint);
    }
    
  • [needs fixing] templates/marketing/AGENTS.md:99-101

    These documented hex values are wrong for the template’s actual fallback palette in src/styles/tokens.css. --color-bg dark is #0a0a0aff (--background-base), --color-surface dark is #171717ff (--surface), and --color-primary is #0075deff (--heat-100). Publishing incorrect color values in agent instructions will lead users to the wrong palette. Either list the real token values or remove the hard-coded hexes and point readers to tokens.css.

    - `--color-bg: var(--background-base)` (`#f7f9fc` / `#0a0a0a`) -- the light and dark canvas
    - `--color-surface: var(--surface)` (`#ffffff` / `#171717`) -- bordered cards and panels
    - `--color-primary: var(--heat-100)` (`#0075de` / `#0075de`) -- links, focus, and selected states
    
  • [needs fixing] templates/marketing/AGENTS-template.md:55-57

    Same issue as AGENTS.md: the documented color hexes do not match the fallback values in src/styles/tokens.css.

    - `--color-bg: var(--background-base)` (`#f7f9fc` / `#0a0a0a`) -- the light and dark canvas
    - `--color-surface: var(--surface)` (`#ffffff` / `#171717`) -- bordered cards and panels
    - `--color-primary: var(--heat-100)` (`#0075de` / `#0075de`) -- links, focus, and selected states
    
  • [suggestion] templates/marketing/src/plugins/marketing-blocks/index.ts:1-22

    This block comment is mostly PR-level narrative and rejected-alternative commentary (“Block Kit has no …”, “componentsEntry auto-wiring is a separate cleanup”), which AGENTS.md says comments should not be. Keep any genuinely non-obvious “why” (e.g., why the CTA fields are flattened) and move the rest to the template docs or the PR description.

  • [suggestion] templates/marketing/src/components/MarketingBlocks.astro:1-8

    This JSDoc block restates what the component already says in code (components={{ type: marketingTypes }}). Per AGENTS.md, comments should not repeat the code; remove it or keep only the exported type/interface docs.

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-review No maintainer or bot review yet labels Sep 11, 2026
@khoinguyenpham04 khoinguyenpham04 changed the title feat(marketing): port the public site design to starter templates feat(marketing): improve marketing starter template Sep 11, 2026
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/awaiting-author Reviewed; waiting on the author to respond labels Sep 11, 2026
@khoinguyenpham04 khoinguyenpham04 added the bot:review Trigger an emdashbot code review on this PR label Sep 11, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a sensible refresh of the marketing templates — the component structure is clean, Node and Cloudflare stay in sync, and the author has addressed most of the last review. The logged-out rendering path is still paying for five round-trips before any page-specific content, and the new contact form logs PII to stdout, so two real issues remain.

What I checked:

  • All changed template files (layouts, pages, components, plugin, seed, styles) and their Cloudflare mirrors.
  • packages/core/tests/integration/smoke/site-matrix-smoke.test.ts — the new marketing regression smoke is a useful addition.
  • templates/marketing/AGENTS.md and AGENTS-template.md against src/styles/tokens.css.
  • Root AGENTS.md conventions, especially the rules on logged-out query counts and privacy/PII handling.

What’s fixed from the prior review:

  • EmDash branding removed from SiteFooter.astro (no "Powered by EmDash" / emdashcms.com links remain in rendered output).
  • /pricing redirect changed from 301 to 302.
  • contact.astro now only sets the cache hint on GET.
  • Documented color hex values are now accurate for the fallback palette.
  • The over-long, reviewer-facing comments in marketing-blocks/index.ts and MarketingBlocks.astro are gone.

What’s still open:

  • The base layout still issues getSiteSettings() plus four menu lookups on every logged-out render. Per AGENTS.md this is a clear violation of the "never add queries to the logged-out hot path" rule.
  • The contact form prints the submitter’s name, email, company, and message to console.log, which writes PII into server logs in production.

No new changeset is needed — the only published-package touch is test code.


Findings

  • [needs fixing] templates/marketing/src/layouts/Base.astro:27-30

    On every logged-out render this layout still pays for getSiteSettings() plus four separate menu lookups. That is five round-trips before the page’s own content query, which directly conflicts with AGENTS.md: “Never add queries to the logged-out hot path.” The footer columns are the obvious consolidation target: define one hierarchical footer menu whose top-level items are Product, Company, and Support with children underneath, load only getMenu("primary") and getMenu("footer"), then map children to the existing footerColumns shape.

    const [menu, footerMenu] = await Promise.all([
    	getMenu("primary"),
    	getMenu("footer"),
    ]);
    
    const footerColumns = (footerMenu?.items ?? [])
    	.filter((item) => item.children && item.children.length > 0)
    	.map((item) => ({
    		heading: item.label,
    		menu: { items: item.children },
    	}));
    

    With that change, seed/seed.json should be updated to ship a single footer menu instead of footer_product, footer_company, and footer_support, and AGENTS.md should describe the new menu shape.

  • [needs fixing] templates/marketing-cloudflare/src/layouts/Base.astro:27-30

    Same unresolved logged-out query-count issue as the Node template: getSiteSettings() plus four menu lookups on every render is too many for the logged-out hot path and violates AGENTS.md. Apply the same single hierarchical footer menu fix here.

  • [needs fixing] templates/marketing/src/pages/contact.astro:31-36

    The POST handler prints the submitter’s name, email, company, and message with console.log. In production that writes PII into server stdout/logs, which is unnecessary exposure and will likely break privacy/data-minimization expectations for any site based on this template. Replace it with a wiring comment and do not ship a default sink that logs personal data.

    			// Wire this to an email service or webhook; don't log personal data.
    			formStatus = "success";
    
  • [needs fixing] templates/marketing-cloudflare/src/pages/contact.astro:31-36

    Same console.log PII issue as the Node template: the Cloudflare contact form also writes name, email, company, and message to stdout. Remove the logging here as well.

@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Sep 11, 2026
@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-rereview Author pushed changes since the last review labels Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant