open-design/apps/landing-page/app/_components
Jane 9d65e26c0f
feat(landing-page): card grid + share popover for /plugins/templates/ (#3185)
* feat(landing-page): YouMind-style grid + share popover for /plugins/templates/

The list-style catalog rows that landed in PR #3010 read as a long
table of items rather than a discoverable grid. Product feedback (after
benchmarking against youmind.com/zh-CN/seedance-2-0-prompts) wanted:

- A YouMind-shape card with a top accent band, video / poster preview
  area, author + attribution row, an excerpt frame, and a primary CTA
  paired with a share button.
- Hover-autoplay on the 46 video templates whose manifest carries a
  Cloudflare Stream MP4. The data was already there since PR #3010;
  the catalog row just rendered the poster as a static `<img>`.
- A counter chip on the right of the hero that surfaces the live total
  (`Total · 231`) instead of baking the number into the H1
  ("231 runnable templates."). The hero now reads as
  `OPEN SOURCE CLAUDE DESIGN` eyebrow + `Templates.` static H1, which
  also threads the brand keyword into the page's SEO surface.
- A six-question FAQ block below the grid covering license, BYOK keys,
  contribution, and the "open source Claude Design alternative"
  positioning explicitly.

Implementation:

- `_components/template-card.astro` — new card component. Accent band
  hue is derived from `od.mode` so artifacts of the same kind get a
  consistent color (video green, prototype blue, deck mustard, image
  wisteria, hyperframes coral, audio amber, live-artifact teal),
  falling back to a stable per-index hue for unrecognized modes.
  Featured tag (yellow, on-brand) is visible when the manifest tag
  list contains `featured`; the rest of the card is locale-resolved
  via the same `resolveBundledTitle` / `resolveBundledDescription`
  helpers PR #3010 added.

- `pages/plugins/templates/index.astro` + `[kind]/index.astro` — grid
  layout (`.tpl-grid`, `repeat(auto-fill, minmax(340px, 1fr))`),
  hero with counter chip, FAQ section on the parent only. Adjacent
  filter strips share a single divider rather than drawing one each,
  so the kind + scene chip block reads as one filter unit instead of
  three stacked horizontal cuts.

- Hover-autoplay observer + share button click handler bundled into
  one `<script>` per page so they share the same boot lifecycle. The
  earlier split version dispatched `astro:page-load` from the autoplay
  block before the share block's listener attached, which dropped
  the share click on the floor; the merged init() runs eagerly when
  DOM is ready, re-runs idempotently on `astro:page-load` (Astro view
  transition), and uses `data-tpl-init` / `data-tpl-share-bound`
  markers to prevent double-binding.

- Card share is a popover, not a system share sheet. The detail page's
  `<dialog class="detail-share-dialog">` UI is reused (single instance
  per page populated per click), but `<dialog>.show()` runs in
  non-modal mode and JS positions it via `getBoundingClientRect()` to
  unfold above-right of the trigger button. Outside-click and Escape
  close the popover; the existing `data-share-copy` / `data-copy-link`
  handlers in `header-enhancer.astro` wire Copy text + Copy link
  automatically. Width tuned to 420px so it fits next to a 340px-wide
  card without spilling onto the next column.

- `_redirects` already covers retired Skills + Craft routes (PR #3010)
  so this grid pivot doesn't need new redirects.

Out of scope for this PR (kept lean):
- Multi-locale hero + FAQ copy. Hero / FAQ render in English on every
  locale right now; the `pcopy.tileTemplates` chip rail and per-card
  title/description still localize per PR #3010. Locale rollout for
  the hero + FAQ is a follow-up.
- Sort + filter buttons in the YouMind reference top-right (we still
  show artifact-kind chips only). Sort by featured weight is the
  most likely next step.
- `od.featured` weight as a featured proxy. We currently key off
  `tags?.includes('featured')` which is 0-match across the catalog
  today; promoting the numeric weight into `BundledPluginRecord` is a
  separate small commit.

`pnpm --filter @open-design/landing-page typecheck` clean (0 errors).

* feat(landing-page): localize templates chrome + FAQPage JSON-LD + hover-only autoplay

Three follow-ups Looper flagged on the YouMind-style grid (PR #3185):

- **Localizable hero / FAQ / card chrome.** PR #3185 wired the grid
  through `pcopy` for record titles + descriptions but hard-coded the
  surrounding chrome — hero eyebrow / lead / counter label, FAQ head,
  Featured tag, "Read full prompt", "Use this template", and the
  share-button `aria-label` — to English. `/ja/plugins/templates/`,
  `/zh-CN/plugins/templates/video/`, etc. now ship those strings via
  `pcopy.*` keys (`templatesHeroEyebrow`, `templatesHeroLead`,
  `templatesCounterLabel`, `cardFeaturedTag`, `cardReadFullPrompt`,
  `cardUseTemplate`, `cardShareAria`, `faqHead`, `faqItems`). English
  is the base; per-locale overrides for hero copy + 6 FAQ Q&A pairs
  remain a follow-up (the PR-#3185 "Out of scope" item), so the 17
  non-English locales fall back to English chrome instead of showing
  undefined values.

- **`FAQPage` JSON-LD entity.** The visible accordion was a SEO
  surface but `jsonLd` was still a single `CollectionPage`. Switched
  it to an array and appended a `FAQPage` whose `mainEntity` is each
  question + answer from `pcopy.faqItems`, so the structured-data
  payload search engines see and the visible <details> share one
  source of truth — drift between them is now mechanical, not
  editorial.

- **Hover-only autoplay (not viewport autoplay).** The previous
  observer played every video the moment its card scrolled into the
  viewport, which contradicted the PR's stated hover-autoplay
  contract and spawned N simultaneous decoders on a casual scroll.
  The IntersectionObserver now hydrates `data-src` -> `src` lazily
  (one-shot, then unobserve) at a 300px rootMargin; `play()` and
  `pause()` are gated to `pointerenter` / `pointerleave` (plus
  `focusin` / `focusout` for keyboard users) on the parent
  `.tpl-media` host so hovering anywhere on the preview frame
  triggers playback. Same change applied to the `[kind]` route so
  faceted pages behave identically.

Validation: pnpm --filter @open-design/landing-page typecheck -> 0
errors / 0 warnings; local dev (port 3061) renders 231 cards / 46
data-tpl-autoplay markers / FAQPage entity present in jsonLd / 6 FAQ
summaries; zh-CN locale falls back to English chrome (expected, the
locale routes themselves remain out of scope per PR #3185).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 11:17:56 +00:00
..
favicon-links.astro feat(landing-page): SEO surfaces, schema upgrades, manifest — cherry-pick from #2469 (#2596) 2026-05-21 23:03:21 +08:00
google-analytics.astro fix(landing): wire GA4 rollout config (#2615) 2026-05-22 14:56:58 +08:00
header-enhancer.astro feat(landing-page): detail pages — interactive preview, share row, dual CTAs (#2679) 2026-05-22 20:47:59 +08:00
header.tsx feat(landing): add Community link + first-party Ambassadors page (#3066) 2026-05-27 11:33:45 +00:00
home-enhancer.astro perf(landing): preconnect api.github.com + rAF-throttle scroll listener (#2666) 2026-05-22 14:06:39 +08:00
lazy-img.astro perf(landing): edge-cache HTML and precise-load thumbnails (#2235) 2026-05-19 19:14:25 +08:00
locale-switcher-enhancer.astro feat(landing): add 19-locale URL routing with full home translations (#2408) 2026-05-21 11:36:15 +08:00
locale-switcher-script.astro feat(landing-page): replicate #2469 SEO content with deploy + regression fixes (#2605) 2026-05-22 00:59:11 +08:00
plugin-row.astro feat(landing-page): localize plugins library across 18 locales (#3010) 2026-05-27 09:30:59 +00:00
precise-lazyload.astro feat(landing-page): rebuild plugins library to mirror in-app taxonomy (#2926) 2026-05-26 02:49:58 +00:00
resource-hints.astro perf(landing): preconnect api.github.com + rAF-throttle scroll listener (#2666) 2026-05-22 14:06:39 +08:00
seo-head.astro ci(landing): split landing deploy into staging gate + manual production (#2994) 2026-05-26 14:05:04 +00:00
site-footer.astro feat(landing-page): localize plugins library across 18 locales (#3010) 2026-05-27 09:30:59 +00:00
skill-row.astro feat(landing-page): rebuild plugins library to mirror in-app taxonomy (#2926) 2026-05-26 02:49:58 +00:00
sub-page-layout.astro fix(landing): wire GA4 rollout config (#2615) 2026-05-22 14:56:58 +08:00
system-card.astro feat(landing-page): replicate #2469 SEO content with deploy + regression fixes (#2605) 2026-05-22 00:59:11 +08:00
template-card.astro feat(landing-page): card grid + share popover for /plugins/templates/ (#3185) 2026-05-28 11:17:56 +00:00
topbar.astro feat(landing-page): replicate #2469 SEO content with deploy + regression fixes (#2605) 2026-05-22 00:59:11 +08:00
wire.tsx fix: sync landing source-of-truth paths (#2066) 2026-05-20 11:44:04 +08:00