From 8f324bb573c1bea9e81089ab2c91a7b6a2195825 Mon Sep 17 00:00:00 2001 From: Damian Date: Thu, 28 May 2026 17:55:45 +0200 Subject: [PATCH] docs(readme): polish for public release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure and tighten the root README for publication while keeping every existing piece of accurate technical content. What changed: - Stronger lead: one-line tagline + a row of shields.io badges for Next, React, Sanity, TypeScript, Tailwind, Biome, license. No emoji. - New "Two flavours" section right under the lead — surfaces the variant/document-level branch and links to PR #62 (the permanent side-by-side comparison and decision guide). - "What you get" reflows the previous dense bullet sprawl into themed paragraphs (Next.js app, Studio, Media, Revalidation, SEO, Hardened defaults, Typed GROQ, Tailwind v4). Each block reads like a feature card, not a checklist. - Quickstart split into clean steps instead of one bash block with inline numbered comments. - "Architecture in brief" replaces the long "Core APIs & modules" tables; depth moves into the per-folder READMEs (already linked). - New "License" footer; the "Requirements" block moves to the bottom where it belongs (you don't read it before you're sold on the repo). - Fixed an orphan link to `packages/sanity-dataset-resolve/README.md` (file doesn't exist; resolver is documented inline in `src/index.ts`). - The strip-readmes utility gets one explicit mention so consumers know the documentation density is opt-in. Net result: 271 → 213 lines, 0 emoji, all links resolve. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 266 +++++++++++++++++++++--------------------------------- 1 file changed, 104 insertions(+), 162 deletions(-) diff --git a/README.md b/README.md index be2d2810..12800426 100644 --- a/README.md +++ b/README.md @@ -1,209 +1,132 @@ -# Next.js + Sanity monorepo +# next-sanity-boilerplate -Opinionated boilerplate for a **multi-language, CMS-driven site** built on **Next.js 16 (App Router, React 19)** and **Sanity Studio v5**, with optional **Mux** video and **Netlify** hosting integrations. Designed to stay slim: no unused features, production-grade defaults, and a clear path from `git clone` → first page. +> A production-shaped starting point for a multi-language, CMS-driven site — **Next.js 16** App Router, **React 19**, **Sanity Studio v5**, with optional **Mux** video and **Netlify** hosting. + +[![Next.js 16](https://img.shields.io/badge/Next.js-16.2-000?logo=next.js&logoColor=white)](https://nextjs.org) +[![React 19](https://img.shields.io/badge/React-19.2-149eca?logo=react&logoColor=white)](https://react.dev) +[![Sanity v5](https://img.shields.io/badge/Sanity-5.27-f03e2f?logo=sanity&logoColor=white)](https://www.sanity.io) +[![TypeScript 6](https://img.shields.io/badge/TypeScript-6-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org) +[![Tailwind v4](https://img.shields.io/badge/Tailwind-4-38bdf8?logo=tailwindcss&logoColor=white)](https://tailwindcss.com) +[![Biome](https://img.shields.io/badge/Biome-2.4-60a5fa?logo=biome&logoColor=white)](https://biomejs.dev) +[![License: ISC](https://img.shields.io/badge/license-ISC-green)](LICENSE) + +It stays slim on purpose: no unused features, production-grade defaults, and a clear path from `git clone` to first published page. Documentation lives next to the code that needs it — strip the per-folder READMEs with `pnpm strip-readmes` once you're ready to ship. --- -## Table of contents +## Two flavours + +This boilerplate ships in **two parallel variants** so you can pick the internationalisation model that matches your editorial workflow: + +| Branch | i18n strategy | Pick when | +|---|---|---| +| **[`main`](../../tree/main)** | Field-level via `sanity-plugin-internationalized-array` | All translations of one piece of content live in one document with language tabs per field; short, UI-shaped translations. | +| **[`variant/document-level`](../../tree/variant/document-level)** | Document-level via `@sanity/document-internationalization` | Each language is its own document — different slugs, modules, SEO per locale. GROQ does the locale matching; no runtime resolver. | -- [Monorepo layout](#monorepo-layout) -- [Feature highlights](#feature-highlights) -- [Requirements](#requirements) -- [Quickstart](#quickstart) -- [Environment & dataset resolution](#environment--dataset-resolution) -- [Core APIs & modules](#core-apis--modules) -- [Scripts reference](#scripts-reference) -- [Tooling](#tooling) -- [Deployment notes](#deployment-notes) -- [Learn more](#learn-more) +[**PR #62**](../../pull/62) keeps a permanent side-by-side comparison + decision guide for adopters. Neither branch is a downgrade of the other; both are production-shaped. --- -## Monorepo layout +## What you get -Managed with **pnpm workspaces** (`pnpm-workspace.yaml`: `web`, `studio`, `packages/*`). +**Next.js app** — App Router with locale-aware routing (`[locale]/[slug]`), `generateStaticParams`, ISR-style revalidation via cache tags, fully wired Sanity Draft Mode + Visual Editing (`SanityLive`, Presentation, stega). `SanityLive` only mounts when it's actually useful (read token present or draft mode active). -| Package | Path | Role | -|---------|------|------| -| **Web** | `web/` | Next.js 16 App Router app — i18n routing, GROQ data fetching, Portable Text, Mux, sitemap/robots, cache-tag revalidation | -| **Studio** | `studio/` | Sanity Studio v5 — schema, plugins, Presentation (Visual Editing), dev/prod dataset sync | -| **`@repo/sanity-dataset-resolve`** | `packages/sanity-dataset-resolve/` | Shared dev/prod dataset resolution used by **both** web and Studio | -| **`@repo/strip-readmes`** | `packages/strip-readmes/` | Internal utility to bulk-clean documentation during exports | +**Sanity Studio v5** — Vision, Dashboard, Presentation with configurable preview origin, runtime language tabs driven by a `siteLanguageSettings` singleton, deploy-on-publish via Netlify plugin, safe production → development dataset clone. ---- +**Media pipeline** — Native `` with deterministic Sanity CDN URLs, full responsive `srcset`/`sizes`, hotspot-aware `object-position`, LQIP and zero hydration drift. Mux video via the official `` imported `/lazy`, plus a lightweight `hls.js` background-loop player that only loads when the element enters the viewport and respects `prefers-reduced-motion`. -## Feature highlights +**Hardened revalidation** — `POST /api/revalidate` does HMAC-SHA256 signature verification (Sanity signed webhooks), payload validation, a document-type allow-list, in-memory rate limiting, and is fail-closed in production. -### Next.js web app -- **App Router** with nested `[locale]/[slug]` routing, static generation (`generateStaticParams`) and ISR-style revalidation via cache tags. -- **Localization** driven by a Sanity singleton (`siteLanguageSettings`). The schema seeds **English + German** on first create (`initialValue`); editors own the list afterward. Routing, ``, `hreflang` alternates, and Portable Text fallbacks read from Studio; a **minimal code fallback** (`en` only) applies only when the document is missing or invalid (CI, first deploy). -- **Draft Mode + Visual Editing** wired through `next-sanity` (`SanityLive`, Presentation overlays, stega). `` only mounts when a read token is present or draft mode is active. -- **Webhook-hardened revalidation** at `POST /api/revalidate` — HMAC-SHA256 signature check (Sanity signed webhooks), payload validation, document-type allowlist, in-memory rate limiter, fail-closed in production. -- **SEO out of the box** — `sitemap.ts` with per-locale `alternates` + `x-default`, staging-aware `robots.ts`, `resolveSanityMetadata` → canonical + `hreflang` metadata for every page. -- **Security headers** via `netlify.toml` — CSP with `frame-ancestors` (Studio-friendly), HSTS preload, `Permissions-Policy`, `Referrer-Policy`. Netlify `build.ignore` skips web builds on Studio-only commits. -- **Tailwind CSS v4** + PostCSS pipeline (`@import`, `calc()`, nested ancestors, custom `rem()` helper). Design tokens live in `web/src/assets/styles/`. +**SEO out of the box** — `sitemap.ts` with per-locale `alternates` and `x-default`, staging-aware `robots.ts`, `resolveSanityMetadata` builds canonical + `hreflang` metadata for every route. -### Media pipeline (Sanity + Mux) -- **`MediaImage`** — native `` with deterministic Sanity CDN URLs, full responsive `srcset`/`sizes`, crop/hotspot-aware `object-position`, LQIP, zero hydration drift. Lazy fade-in via a tiny inline script. -- **`MediaVideo`** — the official Mux React element **``** imported from `@mux/mux-player-react/lazy` (viewport-deferred JS). Poster image comes from Sanity (hotspot-aware) or Mux's `thumbnail.jpg` sized to the container. -- **`MediaVideoLoop`** — lightweight native `