Skip to content

[variant — do not merge] Document-level translation (alternative to field-level i18n) - #62

Draft
damianrosellen1 wants to merge 71 commits into
mainfrom
variant/document-level
Draft

[variant — do not merge] Document-level translation (alternative to field-level i18n)#62
damianrosellen1 wants to merge 71 commits into
mainfrom
variant/document-level

Conversation

@damianrosellen1

@damianrosellen1 damianrosellen1 commented May 28, 2026

Copy link
Copy Markdown
Collaborator

Important

This PR is intentionally a draft and must never be merged. It exists to document a long-lived parallel variant of the boilerplate that uses a different internationalisation strategy. Use it as a side-by-side reference; keep main as the canonical, field-level variant.

TL;DR

This branch (variant/document-level) is a second flavour of the boilerplate. It swaps the field-level i18n approach used on main (sanity-plugin-internationalized-array) for document-level translation via the official Sanity plugin @sanity/document-internationalization. Pick the flavour that matches your editorial model — both are production-shaped.

References #18 (now closed). The variant branch lives on as a permanent alternative — this PR is a documentation-only side-by-side and is intentionally never merged.


The two strategies in one paragraph each

Field-level (main). Every translatable field stores all languages inside the same document as an array of { language, value } entries. Editors see language tabs inside each field. The web app fetches the document once and runs a JavaScript resolver to pick the right entry for the current locale. Queries are locale-agnostic; the document is the unit of editing.

Document-level (this variant). Every language is its own document with a language field. Sibling translations are connected by a translation.metadata document auto-created by the plugin. Editors see a "Translations" toolbar that switches between language variants. The web app filters at the document level (language == $locale) and consumes plain string / Portable Text fields — no runtime resolver.

Neither approach is universally better. The plugin's docs lay out the trade-offs; this PR exists so you can compare both side by side in real code.


Decision guide for adopters

Use main (field-level) when:

  • You want all translations of one piece of content edited in one place.
  • Translations are short, mostly UI-shaped, and rarely diverge structurally between languages.
  • Editors are non-technical and the language-tabs UI is welcome.
  • You're comfortable with a small JavaScript fallback resolver shipping per-render.

Use this variant (document-level) when:

  • Translations are first-class content pieces and may diverge structurally (different modules, different slug, different SEO).
  • You want GROQ queries to do the locale matching (no JS resolver in the hot path).
  • You plan to integrate a translation workflow (TMS, machine-translation hand-off) that operates per-document.
  • You prefer Sanity's official "Translations" toolbar UX over per-field language tabs.

What changed vs main

1. Plugin swap

  • Removed: internationalizedArray({…}) plugin block from studio/sanity.config.ts.
  • Added: documentInternationalization({ supportedLanguages, schemaTypes, languageField }). supportedLanguages is loaded from the siteLanguageSettings singleton at session start (same source as on main, identical fallback chain).
  • The peer sanity-plugin-internationalized-array stays installed transitively — the document-level plugin uses it internally for its translation.metadata.translations array, but our content schemas no longer touch it.

2. Schemas

All six translatable document types — home, page, errorSettings, siteSettings, siteNav, siteCookieBanner — gain a hidden, read-only language field. Field types convert:

Before (main) After (this branch)
internationalizedArrayString string
internationalizedArrayRichText richText
internationalizedArrayRichTextMedia richTextMedia

The firstLocalizedLabel preview helper is deleted (titles are plain strings now). The slug field on page gains an isUniqueLocaleAgnostic validator so the same slug can exist for different language variants (/about in both en and de).

3. Studio structure & Presentation

  • Singletons that previously used S.document().documentId("home") now use S.documentTypeList("home") so editors see one row per language variant; the plugin's Translations toolbar handles switching inside each document.
  • Presentation mainDocuments registers four routes — /, /:locale, /:slug, /:locale/:slug — with language filters on the locale-prefixed variants.
  • locationsResolver projects language alongside slug.current and emits /{language}/{slug} URLs; the web proxy redirects the default-locale prefix to the canonical unprefixed URL.

4. Web GROQ

  • homeQuery and pageBySlugQuery filter at the document level with language == $locale and project plain title (no array wrapper).
  • The recursive buildRichTextMediaQuery(depth) function is replaced with a static depth-2 inline literal, eliminating the typegen blocker.
  • internationalizedRichTextArrayField(fieldName) helper deleted; errorSettings body fields project plain Portable Text.
  • Sitemap queries carry language so each language variant is emitted as a separate URL.

5. Web types

  • web/sanity/utils/sanityLocalizedText.ts (pickLocalizedString, parseLocalizedText, pickLocalizedPortableTextBlocks, resolveLocalizedPortableTextDeep and the Intl*Entry shapes) is deleted entirely.
  • Hand-maintained module/document types switch from Intl*Entry[] to plain string / PortableTextBlock[].
  • The generated web/sanity/sanity.types.gen.ts now resolves seven queries cleanly — including HomeQueryResult and PageBySlugQueryResult, which main cannot currently type because of the recursive fragment. The typed-GROQ pipeline is therefore fully complete on this variant, vs. hybrid on main.

6. Fetch wrappers & routing

  • Every per-document fetch in fetchSanityData.ts and cachedSanityQuery.ts takes a required locale: string parameter. fetchSiteLanguageSettings stays unparameterised — it is the locale registry itself.
  • Cache keys / tags become locale-specific: home-{locale}, page-{slug}-{locale}.
  • /api/revalidate/route.ts validates language on the webhook payload and emits locale-aware tags.
  • Route pages thread locale through; generateStaticParams for [locale]/[slug] uses each page document's own language instead of a cartesian locale × slug product.

7. Components

Every pickLocalized* call is gone — ModuleText, ModulesRenderer, LocaleNotFoundContent, and resolveSanityMetadata access module.title, data.title, errorSettings.notFoundBody directly. The siteLocale prop drops off the module renderer chain.


Bonus side-effect

Because the typegen-blocking recursive query is gone on this variant, the typed-GROQ pipeline is fully wired — all seven exported queries that the web layer fetches produce generated *QueryResult types. On main the pipeline is hybrid (five queries typed, the module-bearing ones hand-typed). It's the cleanest demonstration of why doc-level i18n composes more naturally with the modern Sanity tooling.


Status

Check Result
pnpm -r run typecheck green (studio + web)
pnpm --filter studio run generate + diff guard idempotent
pnpm --filter web run generate + diff guard idempotent
pnpm --filter studio run build green
pnpm --filter web run build green
pnpm lint green (one pre-existing useOptionalChain warning, unchanged from main)

Known follow-ups (not part of this PR)

  • Hreflang sitemap alternates are not emitted on this variant. Cross-locale relationships live in the plugin's translation.metadata document; the sitemap currently emits one row per language variant without alternates.languages. Re-adding hreflang means joining translation.metadata from sitemapPagesQuery and emitting the language map — a focused follow-up PR, not a blocker.
  • Real-data migration for adopters with existing field-level content is out of scope. The plugin ships a migrateToLanguageField helper for the related v5 transition; documenting a complete content migration is a separate task.

How to try it locally

git fetch origin
git checkout variant/document-level
pnpm install
pnpm -r run typecheck   # green
pnpm studio:dev         # see per-language singletons + Translations toolbar
pnpm web:dev            # /about and /de/about resolve to their own documents

damianrosellen1 and others added 3 commits May 28, 2026 17:21
- Install @sanity/document-internationalization (^6.2.1).
- studio/sanity.config.ts: replace internationalizedArray({...}) with
  documentInternationalization({ supportedLanguages, schemaTypes,
  languageField }).
- studio/config/sync/internationalizedArrayLanguages.ts renamed to
  supportedLanguages.ts (loader signature identical, plus a try/catch
  fallback that addresses the earlier robustness gap).
- All 9 schemas migrated: page, home, errorSettings, siteSettings,
  siteNav, siteCookieBanner gain a hidden `language` field; module
  objects (text/carousel/contentRefs) get plain string/richText/
  richTextMedia field types (no per-field i18n wrapper). Previews use
  plain string access; firstLocalizedLabel helper deleted.

NOTE: this is an intermediate commit on the long-lived variant branch.
typecheck/build are intentionally NOT green here — the queries, web
types, fetch wrappers, components, structure items, and presentation
resolver still assume field-level i18n and will be migrated in the
following commits.
Studio side of the document-level migration is now internally consistent
(studio typecheck green; web side migrates in the next etappe).

Structure items for the five singletons (home, siteSettings, siteNav,
errorSettings, siteCookieBanner) switch from a fixed-id S.document() to
S.documentTypeList(<type>) so the desk shows one row per language
variant of each singleton; the plugin's Translations toolbar handles
sibling switching inside each document.

Slug uniqueness is now language-aware: `studio/utils/validateSlug.ts`
exports `isUniqueLocaleAgnostic` which scopes uniqueness per (_type,
language). `studio/schemas/documents/page.ts` wires it into the slug
field's `options.isUnique`, so /about can exist in en AND de.

Presentation:
- `resolve.ts` `presentationMainDocuments` now registers four routes:
  `/` and `/:slug` (default-locale, no language constraint), plus
  `/:locale` and `/:locale/:slug` (`language == $locale`). Presentation
  prefers the most specific match, so per-locale routes win when the
  iframe URL carries a locale segment.
- `locationsResolver.ts` SLUG_QUERY now selects `language` alongside
  `slug.current` and emits a `/{language}/{slug}` URL. The web proxy
  redirects default-locale prefixes to the canonical unprefixed URL.

schema.json and sanity.types.gen.ts regenerated under the new
schemas (52 types incl. `translation.metadata` from the plugin).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Web is now consistent with the Studio's document-level model:

QUERIES
- `pages/home.ts` and `pages/page.ts` filter by `language == $locale`
  and project plain `title` (no field-level array wrapper). Both wrap
  in `defineQuery` — the typegen-blocking `richTextMediaQuery` recursion
  is gone, so the full pipeline can be typed now.
- `snippets/settings.ts`: every settings/nav query takes `$locale` and
  filters at the document level; `internationalizedRichTextArrayField`
  helper deleted; error-body fields project plain `richText` blocks.
- `snippets/sitemap.ts`: rows carry the document's `language` so each
  language variant is emitted as a separate URL.
- `components/text/richTextMedia.ts`: rewrite from the recursive
  `buildRichTextMediaQuery(depth)` function to a static depth-2 inline
  literal (typegen-friendly, idempotent).
- `components/modules/text.ts`: flatten body — no `{language, value}`
  wrapper.

TYPES
- `web/sanity/utils/sanityLocalizedText.ts` deleted; the utils barrel
  drops its re-exports of `parseLocalizedText`, `pickLocalizedString`,
  `pickLocalizedPortableTextBlocks`, `resolveLocalizedPortableTextDeep`
  and the `Intl*Entry` shapes.
- Hand-written types in `web/sanity/types/{pages,errorSettings,modules/*}`
  switch from `Intl*Entry[]` to plain `string`/`PortableTextBlock[]`,
  and gain a top-level `language` field where the doc carries one.
- `web/sanity/sanity.types.gen.ts` regenerates with 7 typed queries
  (HomeQueryResult and PageBySlugQueryResult now resolve cleanly — the
  full-pipeline bonus promised in the plan).

FETCH WRAPPERS / ROUTES
- `fetchSanityData.ts`: every per-document wrapper takes `locale: string`
  (`fetchHomeDocument`, `fetchPageBySlug`, `fetchErrorSettings`,
  `fetchSiteSettingsTitle`, `fetchSettingsSeoFallback`, `fetchSiteNavMenus`).
  `fetchSiteLanguageSettings` stays unparameterised — it is the locale
  registry itself.
- `cachedSanityQuery.ts`: `cachedPageDocumentBySlug(slug, locale)` and
  `cachedHomeDocument(locale)`; cache keys/tags become
  `page-{slug}-{locale}` / `home-{locale}`.
- `/api/revalidate/route.ts`: payload validation accepts `language`; the
  emitted tags include it for `home` and `page`.
- Route pages (`[locale]/page.tsx`, `[locale]/[slug]/page.tsx`,
  `not-found.tsx`, `sitemap.ts`) thread `locale` through every fetch.
- `generateStaticParams` for `[slug]` now uses each page document's
  declared `language` instead of the previous cartesian locale × slug
  product — only the slugs that actually exist for a language are pre-
  rendered.

COMPONENTS
- `ModuleText`, `ModulesRenderer`, `LocaleNotFoundContent`,
  `resolveSanityMetadata` access `module.title`/`data.title` directly;
  no more `pickLocalized*` calls. The `siteLocale` prop drops off the
  module renderer chain.

VERIFICATION
- `pnpm -r run typecheck`: green on studio AND web.
- `pnpm --filter studio run generate` + `--filter web run generate`:
  both idempotent against the committed artifacts.
- `pnpm --filter studio run build` and `pnpm --filter web run build`:
  green.
- `pnpm lint`: clean (only the pre-existing `useOptionalChain` warning
  on `RichTextMedia.tsx`).

The branch is now functionally complete. Issue #18 remains open as
the tracking issue for the variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MCLWallet added 4 commits May 28, 2026 18:07
… resolution

Updated the dataset resolution logic to exclusively use SANITY_STUDIO_PROJECT_ID, removing the fallback to NEXT_PUBLIC_SANITY_PROJECT_ID in both the resolveStudioDatasetAsync function and getSanityStudioProjectId function. This change simplifies the project ID retrieval process.
Consolidated the project ID retrieval logic in both the resolveStudioDatasetAsync and getSanityStudioProjectId functions by removing unnecessary line breaks. This enhances code readability without altering functionality.
…dability

Streamlined the JSX structure in the MediaImage component by eliminating redundant line breaks, enhancing code clarity without affecting functionality.
@netlify

netlify Bot commented May 28, 2026

Copy link
Copy Markdown

Deploy Preview for next-sanity-boilerplate-test ready!

Name Link
🔨 Latest commit 39292c0
🔍 Latest deploy log https://app.netlify.com/projects/next-sanity-boilerplate-test/deploys/6a2011e25ebd70000812ed28
😎 Deploy Preview https://deploy-preview-62--next-sanity-boilerplate-test.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

damianrosellen1 and others added 18 commits May 28, 2026 18:44
…mbs, autoplay)

Adds CMS-driven carousel behavior fields (loop, showThumbnails, showNavDots,
autoplay, autoplayDelayMs) and a production ModuleCarousel renderer using
embla-carousel-react + embla-carousel-autoplay. Replaces the dev-only
placeholder in ModulesRenderer and supports embeds in RichTextMedia.

Co-authored-by: Cursor <cursoragent@cursor.com>
…hydration mismatch

The boot script synchronously added `.img-loaded` to images already complete
in the browser cache, racing React 19 streaming hydration and producing a
"tree hydrated but attributes didn't match" warning on every page that ships
a non-priority Sanity image. Wrapping the class mutation in
`requestAnimationFrame` lets React reconcile the SSR markup first while still
keeping the fade-in transition imperceptible.

Co-authored-by: Cursor <cursoragent@cursor.com>
…o fix hydration

`syncSanityProjectId` previously read `SANITY_STUDIO_PROJECT_ID`, which Next
does not inline into the client bundle. SSR therefore built transformed Sanity
image URLs (`?w=…&auto=format&q=85`) while the hydrating client had no project
id and fell back to bare `image.asset.url`, producing a hydration mismatch on
every Sanity image.

Read `NEXT_PUBLIC_SANITY_PROJECT_ID` exclusively (and drop the equivalent
server-only `SANITY_STUDIO_DATASET` branch from `syncDataset`) so server and
client always compute identical URLs. Document the new env var requirement in
`.env.example`.

Co-authored-by: Cursor <cursoragent@cursor.com>
…mismatch

Adding the `img-loaded` class from the inline boot script raced React 19's
streaming hydration on cached images and produced "tree hydrated but
attributes didn't match" warnings. `requestAnimationFrame` was not enough
to push the DOM mutation past hydration reliably.

Move the lazy fade-in inside `MediaImage`: a `useRef` + `useEffect` flips a
`loaded` state once the image's `load` event fires (or immediately if the
image is already complete) and React renders the class — no more DOM /
hydration race. Strip the image-handling section from the boot script —
theme + `js-enabled` stay so the CSS opacity gate keeps working.

Co-authored-by: Cursor <cursoragent@cursor.com>
Updated `siteNavQuery` and `siteNavMenusQuery` to utilize a new `siteNavByLocale` query, which retrieves the active locale's `siteNav` document while falling back to a legacy document if no locale-specific document exists. This change improves internationalization handling in the navigation structure.
`web/.env` previously needed both `SANITY_STUDIO_PROJECT_ID` (server / Studio
convention) and `NEXT_PUBLIC_SANITY_PROJECT_ID` (so Client Components could
build matching Sanity image URLs). Same value, two names — confusing and
error-prone (forgetting one half of the pair causes a hydration mismatch).

Use Next's `next.config.ts` `env` map to inline `SANITY_STUDIO_PROJECT_ID`
and `SANITY_STUDIO_DATASET` into the client bundle. `sanitySyncConfig.ts`
now reads the Studio-named vars directly. `.env.example` drops the public
aliases. One env var, one name, identical SSR / CSR Sanity URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
… at opacity:0

`useEffect` only set `loaded=true` synchronously when both `el.complete` and
`naturalWidth > 0` were true. For images that errored before React's passive
effect attached its listeners, the load/error events had already fired and
were lost — `loaded` never flipped, the `img-loaded` class was never added
and the broken image stayed invisible (opacity:0) forever.

Drop the `naturalWidth > 0` guard. Both successful and failed loads need to
reveal the `<img>` (the alt text matters for failed ones); the running
listeners still cover the in-flight case.

Co-authored-by: Cursor <cursoragent@cursor.com>
…a-sanity

Add a `dataAttr` helper that composes `next-sanity`'s `createDataAttribute`
with the resolved `projectId` / `dataset` and the Studio URL, so callers only
need to pass the field path (`{ id, type, path }`). Used in `ModulesRenderer`
to wrap each module with `<div data-sanity={...}>` — Presentation tool can
now reverse-map a rendered module to its `modules[_key=="…"]` GROQ slot and
jump the Studio cursor into the corresponding field.

Skips the attribute when a module has no `_key` (legacy data) — without a
stable key the overlay would target the wrong array slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
Silent failures of the SanityLive socket made it hard to tell whether live
content was syncing during draft mode. Pass an `onError` handler that emits
the error plus the request context (`includeDrafts`, `waitFor`) to
`console.error` — surfaces issues in DevTools without changing behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replaced the inline boot script with a new DocumentBootScript component that sets the theme based on localStorage and adds a 'js-enabled' class to the <html> element. This change enhances the structure and maintainability of the layout while ensuring the theme is applied before the first paint. Updated related comments in animations.css to reflect this change.
…sRenderer

- Introduced dynamic import for ModuleCarousel in ModulesRenderer to optimize loading.
- Updated RichTextMedia to utilize LinkMark from linkResolver, simplifying link management.
- Refactored LinkMark component to improve link resolution and rendering logic.

These changes improve performance and maintainability of link handling across components.
…ering

Introduced a new component, ModulesRendererClient, which wraps server-rendered modules and manages their reordering based on updates from Sanity Visual Editing. This component optimizes client-side rendering while ensuring that newly added modules appear after a refetch. The implementation enhances the user experience by providing instant feedback for reordering and deletion actions.
…ering

Introduced a new component, ModulesRendererClient, which wraps server-rendered modules and manages their reordering based on updates from Sanity Visual Editing. This component optimizes client-side rendering while ensuring that newly added modules appear after a refetch. The implementation enhances the user experience by providing instant feedback for reordering and deletion actions.
`<SanityLive />` is rendered from the server root layout, and Next 16 /
Turbopack rejects passing a function literal as a prop across the RSC
boundary. Extract `handleSanityLiveError` into a "use client" module so
it becomes a client reference the layout can safely import and pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This is the document-level translation branch, where each locale is its
own Sanity document. The Presentation overlay should jump editors to the
modules array as a whole rather than into individual field paths.

- dataAttr helper: drop 'path' from the Required pick so doc-level call
  sites are expressible at the type level. Runtime still rejects empty
  paths, so the shallowest valid scope here is the top-level field name.
- ModulesRenderer: compute one container-scoped data-sanity attribute
  ('modules' path) and pass it to ModulesRendererClient as a prop instead
  of attaching per-module field paths.
- ModulesRendererClient: accept optional containerSanityAttr and apply it
  on the outer flex container, leaving the per-module wrappers attribute-
  free.

The main (field-level i18n) branch keeps per-module deep paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updated the Header component to conditionally display a language switcher based on the number of available languages. Refactored menu entries to exclude the language switch option when not needed. Improved layout by grouping the language switcher and theme toggle for better UI consistency across mobile and desktop views.
…eader

Updated the Header component to enhance the readability of the LanguageSwitch component by formatting its props across multiple lines. This change aims to improve code clarity without altering functionality.
damianrosellen1 added a commit that referenced this pull request May 28, 2026
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) <noreply@anthropic.com>
Rolls out the public-release README from #63 to this branch, adapting the
branch-specific sections for document-level i18n:

- "Two flavours" table marks this branch as the current one
- Studio description points at the Translations toolbar
  (@sanity/document-internationalization) instead of per-field language tabs
- "Typed GROQ pipeline" notes full typegen coverage on this branch
- Get-started flow uses the Translations toolbar + per-locale slugs
- "Architecture → i18n" rewritten for document-per-locale + `language == $locale`
  GROQ filtering (no runtime resolver)

Everything else (stack, env, scripts, tooling, deploy, going-deeper) matches
the main README verbatim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
damianrosellen1 and others added 30 commits June 15, 2026 17:13
…-main

chore(deps): mirror dependabot.yml from main (config-only)
These 5 files (file.svg, globe.svg, next.svg, vercel.svg, window.svg) were
created by 'create-next-app' during initial scaffolding and have never been
imported anywhere in the codebase. They were dormant assets shipped in
web/public/ since project init.

Removing them because Biome 2.5.0 enables the new lint/a11y/noSvgWithoutTitle
rule, which fires on these files and breaks the Biome verify step in CI —
blocking every grouped Dependabot non-major run that bundles the biome bump.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rom main (#117)

These two workflows were added on main via #88 and #100 respectively, but
the variant/document-level branch never received them. GitHub Actions
reads workflow files from the PR's base branch — so Dependabot PRs and
human PRs targeting variant currently bypass both the auto-merge and the
Slack notification pipelines.

Bringing them byte-identical from main so the variant line is treated as
a true parallel main branch. After this lands:
- Dependabot grouped PRs against variant get auto-merged when CI is green
- All PRs against variant post to #github-logs with AI-summary

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…updates (#95)

* chore(deps): bump the all-non-major group across 1 directory with 14 updates

Bumps the all-non-major group with 14 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.4.16` | `2.5.0` |
| [@sanity/client](https://github.com/sanity-io/client) | `7.22.0` | `7.22.1` |
| [next](https://github.com/vercel/next.js) | `16.2.6` | `16.2.9` |
| [next-sanity](https://github.com/sanity-io/next-sanity/tree/HEAD/packages/next-sanity) | `13.0.4` | `13.1.0` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.6` | `19.2.7` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.15` | `19.2.17` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.6` | `19.2.7` |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.3.0` | `4.3.1` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.19.19` | `22.19.21` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.0` | `4.3.1` |
| [@sanity/code-input](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/code-input) | `7.1.2` | `7.1.3` |
| [@sanity/document-internationalization](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/document-internationalization) | `6.2.1` | `6.2.7` |
| [sanity-plugin-internationalized-array](https://github.com/sanity-io/plugins/tree/HEAD/plugins/sanity-plugin-internationalized-array) | `5.1.3` | `5.1.8` |
| [sanity-plugin-media](https://github.com/sanity-io/sanity-plugin-media) | `4.3.0` | `4.3.1` |



Updates `@biomejs/biome` from 2.4.16 to 2.5.0
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.0/packages/@biomejs/biome)

Updates `@sanity/client` from 7.22.0 to 7.22.1
- [Release notes](https://github.com/sanity-io/client/releases)
- [Changelog](https://github.com/sanity-io/client/blob/main/CHANGELOG.md)
- [Commits](sanity-io/client@v7.22.0...v7.22.1)

Updates `next` from 16.2.6 to 16.2.9
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](vercel/next.js@v16.2.6...v16.2.9)

Updates `next-sanity` from 13.0.4 to 13.1.0
- [Release notes](https://github.com/sanity-io/next-sanity/releases)
- [Changelog](https://github.com/sanity-io/next-sanity/blob/main/packages/next-sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/next-sanity/commits/next-sanity@13.1.0/packages/next-sanity)

Updates `react` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react)

Updates `@types/react` from 19.2.15 to 19.2.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom)

Updates `@tailwindcss/postcss` from 4.3.0 to 4.3.1
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.19.19 to 22.19.21
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 19.2.15 to 19.2.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `tailwindcss` from 4.3.0 to 4.3.1
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/tailwindcss)

Updates `@sanity/code-input` from 7.1.2 to 7.1.3
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/code-input/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/code-input@7.1.3/plugins/@sanity/code-input)

Updates `@sanity/document-internationalization` from 6.2.1 to 6.2.7
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/document-internationalization/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/document-internationalization@6.2.7/plugins/@sanity/document-internationalization)

Updates `sanity-plugin-internationalized-array` from 5.1.3 to 5.1.8
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/sanity-plugin-internationalized-array@5.1.8/plugins/sanity-plugin-internationalized-array)

Updates `sanity-plugin-media` from 4.3.0 to 4.3.1
- [Release notes](https://github.com/sanity-io/sanity-plugin-media/releases)
- [Changelog](https://github.com/sanity-io/sanity-plugin-media/blob/main/CHANGELOG.md)
- [Commits](sanity-io/sanity-plugin-media@v4.3.0...v4.3.1)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: "@sanity/client"
  dependency-version: 7.22.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/code-input"
  dependency-version: 7.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/document-internationalization"
  dependency-version: 6.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@types/node"
  dependency-version: 22.19.21
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@types/react"
  dependency-version: 19.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@types/react"
  dependency-version: 19.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: next
  dependency-version: 16.2.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: next-sanity
  dependency-version: 13.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: react
  dependency-version: 19.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: react-dom
  dependency-version: 19.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: sanity-plugin-internationalized-array
  dependency-version: 5.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: sanity-plugin-media
  dependency-version: 4.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: tailwindcss
  dependency-version: 4.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(format): adapt breakpoints.css to biome 2.5.0's CSS formatter

Biome 2.5.0 reformats multi-line @custom-variant @media wrappers into a
single-line inner @media. Pre-applying the new format here so this
grouped non-major Dependabot bump can pass CI on the new biome version.

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Damian <hi@damianrosellen.de>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps [sanity](https://github.com/sanity-io/sanity/tree/HEAD/packages/sanity) from 5.27.0 to 6.0.0.
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.0.0/packages/sanity)

---
updated-dependencies:
- dependency-name: sanity
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [sanity-plugin-mux-input](https://github.com/sanity-io/sanity-plugin-mux-input) from 2.19.0 to 3.0.0.
- [Release notes](https://github.com/sanity-io/sanity-plugin-mux-input/releases)
- [Changelog](https://github.com/sanity-io/sanity-plugin-mux-input/blob/main/CHANGELOG.md)
- [Commits](sanity-io/sanity-plugin-mux-input@v2.19.0...v3.0.0)

---
updated-dependencies:
- dependency-name: sanity-plugin-mux-input
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@sanity/vision](https://github.com/sanity-io/sanity/tree/HEAD/packages/@sanity/vision) from 5.27.0 to 6.0.0.
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/@sanity/vision/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.0.0/packages/@sanity/vision)

---
updated-dependencies:
- dependency-name: "@sanity/vision"
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@sanity/dashboard](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/dashboard) from 5.0.1 to 6.0.0.
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/dashboard/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/dashboard@6.0.0/plugins/@sanity/dashboard)

---
updated-dependencies:
- dependency-name: "@sanity/dashboard"
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the all-non-major group with 14 updates:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.5.0` | `2.5.1` |
| [@sanity/client](https://github.com/sanity-io/client) | `7.22.1` | `7.23.0` |
| [next-sanity](https://github.com/sanity-io/next-sanity/tree/HEAD/packages/next-sanity) | `13.1.0` | `13.1.1` |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.3.1` | `4.3.2` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.19.21` | `22.20.0` |
| [groq-js](https://github.com/sanity-io/groq-js) | `1.30.2` | `1.30.3` |
| [sanity](https://github.com/sanity-io/sanity/tree/HEAD/packages/sanity) | `6.0.0` | `6.3.0` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.1` | `4.3.2` |
| [@sanity/code-input](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/code-input) | `7.1.3` | `7.2.0` |
| [@sanity/dashboard](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/dashboard) | `6.0.0` | `6.0.3` |
| [@sanity/document-internationalization](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/document-internationalization) | `6.2.7` | `6.2.9` |
| [@sanity/vision](https://github.com/sanity-io/sanity/tree/HEAD/packages/@sanity/vision) | `6.0.0` | `6.3.0` |
| [sanity-plugin-internationalized-array](https://github.com/sanity-io/plugins/tree/HEAD/plugins/sanity-plugin-internationalized-array) | `5.1.8` | `5.1.9` |
| [styled-components](https://github.com/styled-components/styled-components) | `6.4.2` | `6.4.3` |


Updates `@biomejs/biome` from 2.5.0 to 2.5.1
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.1/packages/@biomejs/biome)

Updates `@sanity/client` from 7.22.1 to 7.23.0
- [Release notes](https://github.com/sanity-io/client/releases)
- [Changelog](https://github.com/sanity-io/client/blob/main/CHANGELOG.md)
- [Commits](sanity-io/client@v7.22.1...v7.23.0)

Updates `next-sanity` from 13.1.0 to 13.1.1
- [Release notes](https://github.com/sanity-io/next-sanity/releases)
- [Changelog](https://github.com/sanity-io/next-sanity/blob/main/packages/next-sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/next-sanity/commits/next-sanity@13.1.1/packages/next-sanity)

Updates `@tailwindcss/postcss` from 4.3.1 to 4.3.2
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.2/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.19.21 to 22.20.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `groq-js` from 1.30.2 to 1.30.3
- [Release notes](https://github.com/sanity-io/groq-js/releases)
- [Changelog](https://github.com/sanity-io/groq-js/blob/main/CHANGELOG.md)
- [Commits](sanity-io/groq-js@v1.30.2...v1.30.3)

Updates `sanity` from 6.0.0 to 6.3.0
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.3.0/packages/sanity)

Updates `tailwindcss` from 4.3.1 to 4.3.2
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.2/packages/tailwindcss)

Updates `@sanity/code-input` from 7.1.3 to 7.2.0
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/code-input/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/code-input@7.2.0/plugins/@sanity/code-input)

Updates `@sanity/dashboard` from 6.0.0 to 6.0.3
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/dashboard/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/dashboard@6.0.3/plugins/@sanity/dashboard)

Updates `@sanity/document-internationalization` from 6.2.7 to 6.2.9
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/document-internationalization/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/document-internationalization@6.2.9/plugins/@sanity/document-internationalization)

Updates `@sanity/vision` from 6.0.0 to 6.3.0
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/@sanity/vision/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.3.0/packages/@sanity/vision)

Updates `sanity-plugin-internationalized-array` from 5.1.8 to 5.1.9
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/sanity-plugin-internationalized-array@5.1.9/plugins/sanity-plugin-internationalized-array)

Updates `styled-components` from 6.4.2 to 6.4.3
- [Release notes](https://github.com/styled-components/styled-components/releases)
- [Commits](https://github.com/styled-components/styled-components/compare/styled-components@6.4.2...styled-components@6.4.3)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/client"
  dependency-version: 7.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: next-sanity
  dependency-version: 13.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@types/node"
  dependency-version: 22.20.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: groq-js
  dependency-version: 1.30.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: sanity
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: tailwindcss
  dependency-version: 4.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/code-input"
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: "@sanity/dashboard"
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/document-internationalization"
  dependency-version: 6.2.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/vision"
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: sanity-plugin-internationalized-array
  dependency-version: 5.1.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: styled-components
  dependency-version: 6.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Same fix as on main: Dependabot-triggered `pull_request` runs get no Actions
secrets, so `secrets: inherit` passed no SLACK_WEBHOOK_URL/OPENROUTER_API_KEY
and Dependabot PR notifications on this branch failed at the reusable
workflow's required-secret check. `pull_request_target` runs in the base-repo
context with org Actions secrets available, even for Dependabot PRs.

Safe here: pr-slack-summary.yml runs no PR code (API + curl only) and skips
forked heads via head.repo.full_name == github.repository.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the all-non-major group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.5.1` | `2.5.2` |
| [next](https://github.com/vercel/next.js) | `16.2.9` | `16.2.10` |
| [@sanity/code-input](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/code-input) | `7.2.0` | `7.2.5` |
| [@sanity/dashboard](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/dashboard) | `6.0.3` | `6.0.7` |
| [@sanity/document-internationalization](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/document-internationalization) | `6.2.9` | `6.2.15` |
| [sanity-plugin-internationalized-array](https://github.com/sanity-io/plugins/tree/HEAD/plugins/sanity-plugin-internationalized-array) | `5.1.9` | `5.1.15` |


Updates `@biomejs/biome` from 2.5.1 to 2.5.2
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.2/packages/@biomejs/biome)

Updates `next` from 16.2.9 to 16.2.10
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](vercel/next.js@v16.2.9...v16.2.10)

Updates `@sanity/code-input` from 7.2.0 to 7.2.5
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/code-input/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/code-input@7.2.5/plugins/@sanity/code-input)

Updates `@sanity/dashboard` from 6.0.3 to 6.0.7
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/dashboard/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/dashboard@6.0.7/plugins/@sanity/dashboard)

Updates `@sanity/document-internationalization` from 6.2.9 to 6.2.15
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/document-internationalization/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/document-internationalization@6.2.15/plugins/@sanity/document-internationalization)

Updates `sanity-plugin-internationalized-array` from 5.1.9 to 5.1.15
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/sanity-plugin-internationalized-array@5.1.15/plugins/sanity-plugin-internationalized-array)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: next
  dependency-version: 16.2.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/code-input"
  dependency-version: 7.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/dashboard"
  dependency-version: 6.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/document-internationalization"
  dependency-version: 6.2.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: sanity-plugin-internationalized-array
  dependency-version: 5.1.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…es (#135)

* chore(deps): bump the all-major group across 1 directory with 3 updates

Bumps the all-major group with 3 updates in the / directory: [@sanity/icons](https://github.com/sanity-io/icons), [sanity-plugin-media](https://github.com/sanity-io/plugins/tree/HEAD/plugins/sanity-plugin-media) and [sanity-plugin-mux-input](https://github.com/sanity-io/plugins/tree/HEAD/plugins/sanity-plugin-mux-input).


Updates `@sanity/icons` from 3.7.4 to 5.0.0
- [Release notes](https://github.com/sanity-io/icons/releases)
- [Changelog](https://github.com/sanity-io/icons/blob/main/CHANGELOG.md)
- [Commits](sanity-io/icons@v3.7.4...v5.0.0)

Updates `sanity-plugin-media` from 4.3.1 to 5.0.10
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-media/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/sanity-plugin-media@5.0.10/plugins/sanity-plugin-media)

Updates `sanity-plugin-mux-input` from 3.0.0 to 4.1.5
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-mux-input/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/sanity-plugin-mux-input@4.1.5/plugins/sanity-plugin-mux-input)

---
updated-dependencies:
- dependency-name: "@sanity/icons"
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-major
- dependency-name: sanity-plugin-media
  dependency-version: 5.0.10
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-major
- dependency-name: sanity-plugin-mux-input
  dependency-version: 4.1.5
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(studio): migrate @sanity/icons imports for v5 breaking change

@sanity/icons v5 removed deprecated barrel exports. Update all 33
call sites to use per-icon subpath imports (e.g. @sanity/icons/Cog)
so typecheck passes with the dependabot major bump.

* chore(studio): regenerate schema typegen for sanity-plugin-mux-input v4

The mux-input v4 bump adds mux.masterFile to the extracted schema.
Commit regenerated studio/schema.json and typegen outputs so the
schema typegen CI gate passes.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* chore(deps): bump the all-non-major group with 18 updates

Bumps the all-non-major group with 18 updates:

| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.5.2` | `2.5.6` |
| [@mux/mux-player-react](https://github.com/muxinc/elements/tree/HEAD/packages/mux-player-react) | `3.13.0` | `3.13.2` |
| [@sanity/client](https://github.com/sanity-io/client) | `7.23.0` | `7.25.0` |
| [next](https://github.com/vercel/next.js) | `16.2.10` | `16.2.12` |
| [next-sanity](https://github.com/sanity-io/next-sanity/tree/HEAD/packages/next-sanity) | `13.1.1` | `13.2.3` |
| [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.2.7` | `19.2.8` |
| [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.2.7` | `19.2.8` |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.3.2` | `4.3.3` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.20.0` | `22.20.1` |
| [sanity](https://github.com/sanity-io/sanity/tree/HEAD/packages/sanity) | `6.3.0` | `6.7.0` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.2` | `4.3.3` |
| [@sanity/code-input](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/code-input) | `7.2.5` | `7.3.3` |
| [@sanity/dashboard](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/dashboard) | `6.0.7` | `6.0.14` |
| [@sanity/document-internationalization](https://github.com/sanity-io/plugins/tree/HEAD/plugins/@sanity/document-internationalization) | `6.2.15` | `6.2.27` |
| [@sanity/icons](https://github.com/sanity-io/ui/tree/HEAD/packages/icons) | `5.0.0` | `5.2.1` |
| [@sanity/vision](https://github.com/sanity-io/sanity/tree/HEAD/packages/@sanity/vision) | `6.3.0` | `6.7.0` |
| [sanity-plugin-internationalized-array](https://github.com/sanity-io/plugins/tree/HEAD/plugins/sanity-plugin-internationalized-array) | `5.1.15` | `5.1.24` |
| [styled-components](https://github.com/styled-components/styled-components) | `6.4.3` | `6.4.4` |


Updates `@biomejs/biome` from 2.5.2 to 2.5.6
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.6/packages/@biomejs/biome)

Updates `@mux/mux-player-react` from 3.13.0 to 3.13.2
- [Release notes](https://github.com/muxinc/elements/releases)
- [Changelog](https://github.com/muxinc/elements/blob/main/packages/mux-player-react/CHANGELOG.md)
- [Commits](https://github.com/muxinc/elements/commits/@mux/mux-player-react@3.13.2/packages/mux-player-react)

Updates `@sanity/client` from 7.23.0 to 7.25.0
- [Release notes](https://github.com/sanity-io/client/releases)
- [Changelog](https://github.com/sanity-io/client/blob/main/CHANGELOG.md)
- [Commits](sanity-io/client@v7.23.0...v7.25.0)

Updates `next` from 16.2.10 to 16.2.12
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](vercel/next.js@v16.2.10...v16.2.12)

Updates `next-sanity` from 13.1.1 to 13.2.3
- [Release notes](https://github.com/sanity-io/next-sanity/releases)
- [Changelog](https://github.com/sanity-io/next-sanity/blob/main/packages/next-sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/next-sanity/commits/next-sanity@13.2.3/packages/next-sanity)

Updates `react` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react)

Updates `react-dom` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react-dom)

Updates `@tailwindcss/postcss` from 4.3.2 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.20.0 to 22.20.1
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `sanity` from 6.3.0 to 6.7.0
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.7.0/packages/sanity)

Updates `tailwindcss` from 4.3.2 to 4.3.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.3/packages/tailwindcss)

Updates `@sanity/code-input` from 7.2.5 to 7.3.3
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/code-input/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/code-input@7.3.3/plugins/@sanity/code-input)

Updates `@sanity/dashboard` from 6.0.7 to 6.0.14
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/dashboard/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/dashboard@6.0.14/plugins/@sanity/dashboard)

Updates `@sanity/document-internationalization` from 6.2.15 to 6.2.27
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/@sanity/document-internationalization/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/@sanity/document-internationalization@6.2.27/plugins/@sanity/document-internationalization)

Updates `@sanity/icons` from 5.0.0 to 5.2.1
- [Release notes](https://github.com/sanity-io/ui/releases)
- [Changelog](https://github.com/sanity-io/ui/blob/main/packages/icons/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/ui/commits/@sanity/icons@5.2.1/packages/icons)

Updates `@sanity/vision` from 6.3.0 to 6.7.0
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/@sanity/vision/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.7.0/packages/@sanity/vision)

Updates `sanity-plugin-internationalized-array` from 5.1.15 to 5.1.24
- [Release notes](https://github.com/sanity-io/plugins/releases)
- [Changelog](https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/plugins/commits/sanity-plugin-internationalized-array@5.1.24/plugins/sanity-plugin-internationalized-array)

Updates `styled-components` from 6.4.3 to 6.4.4
- [Release notes](https://github.com/styled-components/styled-components/releases)
- [Commits](https://github.com/styled-components/styled-components/compare/styled-components@6.4.3...styled-components@6.4.4)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@mux/mux-player-react"
  dependency-version: 3.13.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/client"
  dependency-version: 7.25.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: next
  dependency-version: 16.2.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: next-sanity
  dependency-version: 13.2.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: react
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: react-dom
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@types/node"
  dependency-version: 22.20.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: sanity
  dependency-version: 6.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: tailwindcss
  dependency-version: 4.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/code-input"
  dependency-version: 7.3.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: "@sanity/dashboard"
  dependency-version: 6.0.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/document-internationalization"
  dependency-version: 6.2.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@sanity/icons"
  dependency-version: 5.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: "@sanity/vision"
  dependency-version: 6.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: sanity-plugin-internationalized-array
  dependency-version: 5.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: styled-components
  dependency-version: 6.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-non-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(studio): pass --force to sanity schema extract

sanity 6.7.0 refuses to overwrite an existing studio/schema.json:

  Error: Schema file already exists at "studio/schema.json".
  Pass `--force` to overwrite it.

Since schema.json is a committed generated artifact, extract always runs
against an existing file — so the CI "schema typegen" gate failed for
this bump. The flag does not exist in 6.3.0 (exit 1), which is why it
ships here with the sanity 6.3.0 -> 6.7.0 bump rather than separately.

Same fix as on main (#139). Verified locally with 6.7.0: schema.json and
sanity.types.gen.ts come out byte-identical to the 6.3.0 output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Damian <hi@damianrosellen.de>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Variant-branch counterpart to #143 on main. From the monthly all-major
group (#142), four of five bumps are safe:

- @portabletext/react 6.2.0 -> 7.0.1 — no API changes; the only BREAKING
  note is that React 19 is now required (we are on 19.2.8).
- sanity-plugin-media 5.0.10 -> 6.0.9
- sanity-plugin-mux-input 4.1.5 -> 5.0.7
  Both only widen their styled-components peer range to ^6.1 (what Studio
  v5+ already requires).

Held back: typescript 6.0.3 -> 7.0.2 breaks `next build`. `tsc --noEmit`
passes, but Next's own TypeScript detection fails on the reorganised
package layout of the native compiler, and Next's transitive
@module-federation/dts-plugin still pins typescript@^4.9 || ^5.

Dropped instead of bumped: groq-js was a direct dependency of web/ that
nothing imports, and every real consumer (sanity, @sanity/schema,
@sanity/codegen, @sanity/cli) carries its own pinned 1.30.3. Bumping it to
2.0.0 would have pulled an ESM-only build requiring Node >= 22.12 into a
repo that declares engines node >=20 and runs CI on Node 20.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Straight `git checkout main --` of both files, per the lockstep rule in
AGENTS.md ("Updating conventions on both branches").

dependabot.yml had drifted further than expected on this branch: it still
carried the old weekly-style schedule (Monday 06:00) and had no
`all-major` group at all. Main's version adds both, plus the new ignore
for typescript major bumps. Dependabot reads this file only from the
default branch, so the variant copy is documentation — but the file itself
asks for the two entries to be kept in lockstep.

biome.json is `biome migrate` output for the 2.5.6 CLI: $schema URL and
`linter.rules.recommended` -> `rules.preset`. Unchanged semantics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cript-variant

build(deps): adopt four majors, hold TypeScript 7, drop unused groq-js (variant)
…pdates (#148)

Bumps the all-non-major group with 4 updates in the / directory: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react), [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom), [sanity](https://github.com/sanity-io/sanity/tree/HEAD/packages/sanity) and [@sanity/vision](https://github.com/sanity-io/sanity/tree/HEAD/packages/@sanity/vision).


Updates `@types/react` from 19.2.17 to 19.2.18
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.2.3 to 19.2.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `sanity` from 6.7.0 to 6.8.0
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/sanity/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.8.0/packages/sanity)

Updates `@sanity/vision` from 6.7.0 to 6.8.0
- [Release notes](https://github.com/sanity-io/sanity/releases)
- [Changelog](https://github.com/sanity-io/sanity/blob/main/packages/@sanity/vision/CHANGELOG.md)
- [Commits](https://github.com/sanity-io/sanity/commits/v6.8.0/packages/@sanity/vision)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.2.18
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: "@types/react-dom"
  dependency-version: 19.2.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-non-major
- dependency-name: sanity
  dependency-version: 6.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
- dependency-name: "@sanity/vision"
  dependency-version: 6.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-non-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Mirrors the same fix on `main`. `sanity-plugin-internationalized-array@5.1.24`
declares `@sanity/language-filter: ^5.0.13` as a non-optional peer, but the
lockfile still pinned the 5.0.1 that pnpm auto-installed on the initial
commit, so every resolution step warned:

  ✕ unmet peer @sanity/language-filter@"^5.0.13": found 5.0.1
  ✕ unmet peer sanity@^5: found 6.8.0   (language-filter 5.0.1 itself)

Not cosmetic: the plugin statically imports the package at the top of
its `dist/index.js`, so it loads whenever the plugin loads — even though
we never register `languageFilter()` in sanity.config.ts. Its code is
bundled into the built Studio, which means we were shipping a
language-filter built against Sanity 5 into a Sanity 6.8.0 Studio.
5.0.13 declares `sanity: ^5 || ^6.0.0-0` and clears both warnings.

pnpm never re-resolves an auto-installed peer once recorded, so neither
`pnpm update @sanity/language-filter -r` (no direct-dependency handle —
a genuine no-op) nor a `pnpm.overrides` entry dislodges it; a from-
scratch resolve lands on 5.0.13 with or without an override, so no
override is warranted. Regenerating the whole lockfile fixes it too but
drifts dozens of unrelated package versions. Instead the four stale
entries were dropped and re-resolved via `pnpm install --resolution-only`,
keeping the diff to this one package.

On this branch the change also updates the peer-hash suffix recorded for
`@sanity/document-internationalization`, which likewise depends on
`sanity-plugin-internationalized-array`.

`sanity-plugin-netlify@1.4.0` still warns (`sanity: ^3 || ^5`); 1.4.0 is
the latest published version, so that one is upstream's to fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…lay fixes from farbstudio

Port the advanced Mux loop implementation from the farbstudio.de build:
- muxLoopHlsSrc pins a single resolution tier (min=max) from container size
  x capped DPR combined with a network-aware ceiling; fixes the no-op
  min_resolution_tier param to min_resolution; DPR cap 1.25->2.0, max tier
  1440p->2160p.
- useMuxHlsSource: Safari native-HLS fast path (sync video.src, skips hls.js
  import + codec probe) to stay inside the autoplay window.
- useContainerPixelWidth now also reports height for cover-fit tier math.
- MediaVideoLoop: DPR snapshot, useLayoutEffect muted/defaultMuted latch,
  rVFC stable-frame readiness + force-ready net, play() guards against
  poisoning Safari MediaEngagement, stacked-slide restart. English aria
  labels (was German) + starter spacing tokens.
- Studio: muxInput 1440p/plus/mp4_support:none (was bare defaults); add
  mux:migrate-assets one-off script + .env hint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… metadata/lang; drop hardcoded title

Sanity<->frontend disconnects in the root layout:
- Static root metadata hardcoded title { default: 'Site', template: '%s | Site' }
  duplicated/overrode the per-locale title in app/[locale]/layout.tsx. Convert
  root to async generateMetadata and drop the hardcoded title; the locale
  layout owns the title template.
- Favicon: siteSettings.favicon (per-locale doc) existed but no route consumed
  it. Add siteSettingsFaviconQuery + fetchSiteSettingsFavicon (fetched for the
  default locale) and emit icons; static app/favicon.ico stays the fallback.
- <html lang>: was hardcoded to the offline FALLBACK_SITE_LOCALE_CONFIG default
  instead of the live siteLanguageSettings.defaultLanguageId.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirrors the same rule on `main`. `sanity-plugin-netlify@1.4.0` declares
`sanity: ^3 || ^5`, so Sanity 6.8.0 tripped an unmet-peer warning on every
resolution step — the last one left after the @sanity/language-filter refresh.
A public starter that greets every downstream user with a peer warning trains
people to ignore warnings, so the next real one goes unnoticed.

Verified stale metadata rather than a real incompatibility before silencing:

- The plugin imports only `FormField`, `useColorScheme`, `useClient` and
  `definePlugin` from `sanity`; all four are still exported by 6.8.0.
- Upstream PR jclusso/sanity-plugin-netlify#24 reports that `FormField`
  crashes on Sanity >=5.17, where `useDocumentDivergences()` threw without
  `DocumentDivergencesContext` — which a standalone tool never provides. That
  path is dead on 6.8.0: the context now carries a `{enabled: false}` default,
  so `FormNodeDivergenceDetail` returns its children unchanged instead of
  throwing. Sanity fixed the root cause itself.
- Both `web` and `studio` build; typecheck and check:wiring pass.

Scoped to the single `sanity-plugin-netlify>sanity` edge rather than a blanket
rule, so any other peer mismatch still surfaces. The lockfile is byte-identical
— this only changes which warnings pnpm prints, not resolution.

Preferred `peerDependencyRules` over `patchedDependencies`: the range is a
declaration nothing enforces, and a patch would need re-applying on every
plugin bump. Exit condition is upstream widening the range; issues are
disabled on that repo, so a PR is the only route.

Not addressed here, pre-existing and unrelated to Sanity 6: the plugin pins
`@sanity/ui ^2` and `@sanity/icons ^3` as hard dependencies, so its tool UI
renders against older majors than the Studio's `@sanity/ui 3` / `icons 5`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mirrors the same correction on `main`. The note left on
`pnpm.peerDependencyRules` flagged the plugin's `@sanity/ui ^2` /
`@sanity/icons ^3` hard pins as an open risk. Investigated properly, it is a
cost, not a defect, so the note read more alarming than the facts support and
invited a bad "fix".

What the plugin actually does: it wraps its own tool in its own v2
`ThemeProvider theme={studioTheme}` before rendering any v2 primitive, so it
never reads the Studio's v3 theme context — the two majors do not meet. Both
also resolve to the single hoisted styled-components 6.4.4, so there is no
duplicated styling runtime either. What remains is bundle weight: a second
@sanity/ui major ships inside the Studio build.

Records the conclusion plus the trap: forcing the plugin onto @sanity/ui 3 via
an override stakes all 26 of its v2 imports on v3 API parity and buys no
correctness. `studioTheme` still exists in v3, so such an override would look
plausible and fail subtly — worth naming explicitly.

Comment-only; the rule, the resolution and the lockfile are untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Propagation step for 8698e8c on `main`, per the ritual in AGENTS.md
§"Updating conventions on both branches": take the convention files from main
verbatim, then re-check the branch-specific section against this branch.

Re-checked, all three surviving rows hold here: `page` carries the `language`
field, `@sanity/document-internationalization` is in `studio/package.json`, and
the `siteSettings` snippets do filter on `language == $locale` rather than
main's `_id` lookup. No further adjustment needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Port of 97f4fe4 from `main`, which never reached this branch.

`fetchSiteLanguageSettings` chose the drafts perspective purely on the presence
of `SANITY_API_READ_TOKEN`. A production deploy sets that token for Visual
Editing, so every visitor-facing render paid an uncached, non-CDN Sanity round
trip before anything else could paint. Gates on what actually needs drafts
instead — dev, or a real Draft Mode / Presentation request — via a new
`isDraftModeEnabled()` helper that treats `draftMode()` throwing outside a
request scope (`generateStaticParams`, build-time prerender) as "not in draft
mode". Published reads keep going through `unstable_cache`.

`proxyLocaleFetch.ts` and `proxy.ts` applied cleanly. The conflict was in the
doc comment of `fetchSiteLanguageSettings`, where this branch carries an extra
first paragraph noting that `siteLanguageSettings` is the global locale registry
and not itself per-language — a distinction that matters here, where other
settings documents are per-locale. Kept that paragraph, took main's two rewritten
ones. The resulting function body is byte-identical to main's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Port of a5d9827 from `main`, which never reached this branch.

`ModulesRenderer` now marks the first module in the stack as the LCP candidate
and threads a `priority` flag into `ModuleMedia` / `ModuleContentRefs`, so the
first above-the-fold image loads eagerly instead of waiting its turn.

Three parts of main's diff deliberately did not come along:

- The per-module `<div data-sanity={sanityAttr}>` wrapper is main's field-level
  Presentation convention. This branch attaches one `containerSanityAttr` on the
  outer container by design (documented on `ModulesRenderer`), and `sanityAttr`
  does not exist in this scope — porting that hunk would not even compile.
- `ModuleContentRefs` reads `module.heading` as a plain string here, because
  document-level i18n resolves it in GROQ. Main's switch to
  `pickLocalizedString(module.heading, …)` belongs to the field-level model.
  Kept the local read, took only the `priority = false` prop.
- Main's `layout.tsx` hunk is just `display: "block"` → `"swap"` on its Geist
  fonts. Geist predates a5d9827 on main; this branch has no active `next/font`
  at all, only the commented `localFont` scaffold, so there was nothing to flip.

That last one left a trap worth closing: the scaffold recommended `display:
"block"` as its default — precisely what main measured and moved off. A fork of
this branch following the scaffold would rebuild the FOIT hold on first paint.
Updated the scaffold's recommendation to "swap" with the reasoning from a5d9827
and switched its two examples accordingly. Comment-only, no behavior change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Port of 78f69f7 from `main`, which never reached this branch.

Adds the `route-loading` animation (`animations.css`) that holds the locale
Suspense fallback invisible for 300 ms, so prefetched/ISR navigations never
flash the skeleton — the skeleton → content swap was a layout shift on every
transition. Slow loads still get feedback once the delay elapses.

`animations.css` and `globals.css` applied cleanly. The conflict was on the
skeleton's own `className`, and resolving it turned out to be part of the fix
rather than cosmetics: this branch's skeleton used `gap-6 px-6 py-16 sm:px-8`
while its real content container (`work/page.tsx`) already used
`gap-md px-md py-max sm:px-container`. Three of those map to identical values,
but `py-16` is 64px against `py-max`'s 80px — a 16px jump between fallback and
content on every transition into those routes, which is the exact bug class this
commit exists to remove.

Also switched the inner skeleton's `gap-4` to `gap-sm`. That one arrived as merge
context rather than a conflict, and `--space-sm` is `rem(16)` at every
breakpoint, exactly what `gap-4` resolves to — a pure spelling change with no
visual effect, taken so the file is byte-identical to main's and stops
re-conflicting on the next port.

Note for a follow-up, out of scope here: `[locale]/[slug]/page.tsx` on this
branch still uses raw `gap-10 px-6 py-16 sm:px-8`, so that one route keeps a
skeleton/content padding mismatch until it migrates to the spacing tokens.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rojection

Port of 3cf1317 from `main`, which never reached this branch.

Removes four settings queries that nothing consumed — `settingsBundleQuery`,
`siteSettingsQuery`, `siteNavQuery`, `siteCookieBannerQuery` — along with their
re-exports, and stops projecting `modules[]` in `errorSettingsQuery`. No error
page renders modules, and embedding `modulesQuery` there inflated the query from
roughly 2 KB to 79 KB.

Re-verified the four are dead **on this branch** rather than trusting main's
audit: the only references outside their own definition and the barrel were in
READMEs. `siteNavByLocale` stays — `siteNavMenusQuery` still uses it.

The i18n model is where this could not be copied. Main addresses these documents
by `_id` and types their copy as field-level i18n arrays; here they are
per-locale documents. So the surviving projections keep their
`*[_type == "…" && language == $locale][0]` selectors, `errorSettingsQuery` keeps
`"serverErrorBody": serverErrorBody${richTextBody}` instead of main's
`internationalizedRichTextArrayField(…)`, and `ErrorSettingsDocument` keeps its
plain `PortableTextBlock[]` / `string` fields plus `language`. Only `modules`
and the now-unused `ContentModule` import came off the type — the part that is
actually the fix.

Doc comments were reconciled the same way: main's wording, with "document id"
corrected back to "document type (one per language)" where this branch differs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Port of c29df3d from `main`, which never reached this branch.

`richTextMediaQuery` repeated the whole `module.media` / `module.carousel` /
`module.contentRefs` projection set inside the nested `module.text` body, so the
same projections were POSTed twice per query — and `sanityFetch` sends the query
text twice. Embedding them only at the top level cuts this snippet from 31.6 KB
to 17.1 KB (32367 → 17517 characters, measured on this branch with all nested
snippet imports expanded).

Nested `module.text` bodies still resolve blocks + link marks. A media module
embedded *inside* a nested text module now arrives with its raw stored fields
only, without asset/reference expansion, and is not expected to render — the
top-level rich text is the module surface.

Main restructured this into a recursive `buildRichTextMediaQuery(depth, top)`
whose nested bodies project `internationalizedArrayRichTextMedia` as
`{_key, _type, language, value[]}`. That shape belongs to field-level i18n; here
`module.text.body` is a plain array because document-level i18n resolves the
locale in GROQ. So the flat, hand-unrolled two-level form stays — its own comment
records that the flat shape is what keeps Sanity Typegen working on this branch —
and only the duplicated module projections came out.

Worth noting for expectations: main measured ~57 KB saved on this snippet, far
more than the 14.5 KB here. The difference is the i18n model — main's module
projections carry the internationalized-array expansions, which are much larger
than this branch's plain fields.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e tags

Port of f643caa from `main`, which never reached this branch.

`<SanityLive />` was mounted for anyone once `SANITY_API_READ_TOKEN` was set,
opening an SSE connection per tab and refreshing the `sanityFetch` cache through
a server action on every publish event. Needed for Presentation / Draft Mode,
wasted on anonymous visitors. It is now gated on draft mode, with a fallback:
a read token but no `SANITY_REVALIDATE_SECRET` keeps Live mounted for everyone,
so webhook-less setups still propagate published edits.

Published freshness then has to come from `/api/revalidate`, which only works if
the `sanityFetch` cache entries carry our webhook tags — next-sanity stores them
with `revalidate: false` and only its own `sanity:*` sync tags, which nothing but
a mounted Live ever touches. So all ten wrappers now pass `tags`.

Two adaptations this branch needed:

- `SANITY_CACHE_TAGS` is locale-aware here, because per-locale documents are
  distinct documents: `home(locale)`, `pageSlug(slug, locale)`,
  `projectSlug(slug, locale)`. Main's flat `home` / `pageSlug(slug)` do not
  typecheck against it. Every wrapper keeps its `params: { locale }` — the
  conflicts were main dropping `locale` (its documents are singletons), not main
  replacing params with tags. Resolution was additive throughout: keep params,
  add tags.
- `SANITY_CACHE_TAGS.work` did not exist. Added it as `work(locale)`, matching
  `home`.

One step beyond a literal port, and deliberate: `work` and `project` were absent
from the webhook's `ALLOWED_DOCUMENT_TYPES`, so tagging their fetches would have
produced tags nothing ever invalidates — cache entries that look covered and
silently never refresh, which is worse than leaving them untagged. Added both
types to the allow-list with locale-aware tags, mirroring main's coverage in this
branch's tag shape. Cross-checked afterwards that every `SANITY_CACHE_TAGS` entry
is both used and reachable from the route.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow-up to 30320b2, which noted this branch still had route containers on raw
Tailwind values while the loading skeleton had moved to the spacing tokens — a
skeleton/content padding mismatch on every transition into those routes, the
exact bug class that commit set out to remove.

Five containers across four files, mapped per file to whatever `main` already
runs in the same file. Every route container on both branches is now identical,
4× `gap-lg` and 5× `gap-md`, so nothing is left mid-migration and this file set
stops re-conflicting on future ports.

Four of the five class swaps are value-identical at the base breakpoint:
`gap-6`→`gap-md` and `px-6`→`px-md` are both `rem(24)`, `gap-10`→`gap-lg` is
`rem(40)`, and `sm:px-8`→`sm:px-container` is `rem(32)` at `sm`. The one real
change is `py-16`→`py-max`: 64px becomes 80px, which is the point — it is what
the skeleton and the already-migrated routes use, so the fallback and the content
finally agree.

Scope note: the follow-up called out `[locale]/[slug]/page.tsx`, but the same raw
container also sat in `[locale]/page.tsx` (twice), `error.tsx` and
`LocaleNotFoundContent.tsx`. Migrating only the named one would have left three
routes mismatched, so all five moved together.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants