Skip to content

Commit e5cf45e

Browse files
committed
fix(landing): document ogImage's local-path expectation, fix CLAUDE.md structure doc
- add a one-line comment on ContentFrontmatterSchema.ogImage documenting that it's rendered without unoptimized and expects a local path, matching the existing avatarUrl comment convention (a reviewer noted ogImage's schema is technically unconstrained and seo.ts has an http-prefix branch, though all current content is local) - add the new hooks/ folder to the (landing) CLAUDE.md structure diagram and name use-lazy-mount.ts directly in the lazy-mount rule
1 parent adf6109 commit e5cf45e

2 files changed

Lines changed: 3 additions & 2 deletions

File tree

apps/sim/app/(landing)/CLAUDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Target: Lighthouse 95+ on mobile, LCP < 2.0s, CLS < 0.05, minimal hydration cost
3737
- **Static rendering.** The page is statically generated with `revalidate` (set in `page.tsx`). Never fetch per-request data in the page tree; anything dynamic (e.g. GitHub stars) is fetched at build/revalidate time or deferred to a client island. A `cookies()`/`headers()`/`unstable_noStore()` call anywhere in the tree - including the root `app/layout.tsx` - silently overrides every page's `revalidate` and forces the whole app dynamic. If a marketing page builds as `ƒ` instead of ``/`` (check `bun run build`'s route table), look upstream, not just at the page itself.
3838
- **Reserve space for everything.** Fixed dimensions or aspect ratios on all media, embeds, and async content. CLS budget is effectively zero.
3939
- **Decorative canvases and animations are non-interactive.** A hand-built product-demo animation or embedded ReactFlow canvas is presentation only - no drag handlers, no `nodesDraggable`/`panOnDrag`/`elementsSelectable` on ReactFlow. A visitor should never be able to click or drag a decorative element.
40-
- **Lazy-mount a heavy client island's second occurrence.** If the same animated component appears twice on a page, only the first (usually the hero) loads eagerly - the rest go through a small `'use client'` mount wrapper: `next/dynamic(..., { ssr: false })` gated by an `IntersectionObserver`. See `components/product-demo/components/product-demo-visual-mount/` for the reference pattern, and `.claude/rules/sim-imports.md` for the barrel-cleanup step that must come with it.
40+
- **Lazy-mount a heavy client island's second occurrence.** If the same animated component appears twice on a page, only the first (usually the hero) loads eagerly - the rest go through a small `'use client'` mount wrapper built on the shared `hooks/use-lazy-mount.ts` hook: `next/dynamic(..., { ssr: false })` gated by the hook's `IntersectionObserver`. See `components/product-demo/components/product-demo-visual-mount/` for the reference pattern, and `.claude/rules/sim-imports.md` for the barrel-cleanup step that must come with it.
4141
- **Don't prefetch authenticated-app routes from an always-visible CTA.** `<Link>` prefetches its target route's JS once it's in the viewport - a navbar/hero CTA to `/signup` or `/login` is always in view, so it downloads that route's bundle on every pageview. Pass `prefetch={false}` there. Leave the default on CTAs that only enter the viewport on scroll (prefetch-on-approach is the desired behavior there).
4242

4343
## SEO
@@ -75,6 +75,7 @@ Follow `.claude/rules/constitution.md` exactly: Sim is "the open-source AI works
7575
├── page.tsx # route entry: metadata + <Landing />
7676
├── landing.tsx # root composition: <main> section order
7777
├── workflows/ # a platform route: page.tsx (metadata) + workflows.tsx (config + shell)
78+
├── hooks/ # cross-page client hooks (useLazyMount, …) - bare files, no folder/barrel
7879
└── components/
7980
├── index.ts # top barrel
8081
├── navbar/{navbar.tsx, index.ts, components/<chip>/…} # <header><nav>: wordmark, dropdowns, stars, auth chips

apps/sim/lib/content/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export const ContentFrontmatterSchema = z
2727
authors: z.array(z.string()).min(1),
2828
readingTime: z.number().int().positive().optional(),
2929
tags: z.array(z.string()).default([]),
30-
ogImage: z.string().min(1),
30+
ogImage: z.string().min(1), // local path (e.g. /blog/<slug>/cover.jpg) - rendered via next/image without `unoptimized`
3131
ogAlt: z.string().optional(),
3232
about: z.array(z.string()).optional(),
3333
timeRequired: z.string().optional(),

0 commit comments

Comments
 (0)