Search documentation

Search pages and headings in the docs.

JustHold MDX Content (CMS)

When to Use

  • Editing the admin contents UI or post actions
  • Changing MDX component registry or article rendering
  • Updating R2 post keys, locales, or lib/posts metadata loading

Instructions

  • Posts are authored in /admin/contents (Monaco + live preview). The index is a CMS workspace with Published | Drafts | Pinned tabs (?tab=published|drafts|pinned; default published). Published/Drafts keep searchable lists (category / locale-completeness via URL params; EN / 中文 chips open or create a locale). The Pinned tab manages homepage slots 1–3 (published posts only). There is no file explorer — list + editor only. Metadata lives in Supabase (posts + post_locales); MDX bodies live in Cloudflare R2.
  • R2 object layout (see lib/r2.ts): posts/<slug>/<locale>/content.mdx where locale is zh-hant or en.
  • Shared fields on posts: slug, category, author, status, pin_order (1–3 or null for blog hero), cover_key (R2), published_at.
  • Locale-specific fields on post_locales: title, excerpt, reading_time. Body is only in R2.
  • Cover image R2 key: posts/<slug>/cover.png (see postCoverKey / publicObjectUrl in lib/r2.ts).
  • Blog listing: getPinnedPosts (hero slots) + getPosts (date-ordered, excludes pins).
  • Public pages load published posts via lib/posts.ts + lib/mdx/render (same component registry as the admin preview).
  • Do not hardcode title/date/category in the MDX body — the public page renders <ArticleHeader post={...} /> from Supabase metadata.
  • All markdown elements are styled via lib/mdx/components.tsx — don't add custom className overrides per-post.
  • Blog TOC is auto-built from ## / ### via extractToc (lib/docs/toc.ts). Heading ids come from HeadingWithId in the shared MDX registry — keep section titles unique so slugs stay stable.
  • Use <Sidenote>text</Sidenote> for tangential commentary/citations (Tufte-style margin note on wide screens, inline toggle on mobile). Do not replace sidenotes with endnotes.
  • Prefer English (en) as the default content locale (matches site / and admin); add zh-hant when a translation is ready.