docs/plans/2026-05-23-shadcn-docs-restart-comparison.md
Compare latest local upstream shadcn docs in ../ui/apps/v4 with Plate's current docs app in apps/www, then identify every meaningful Plate-specific change before restarting Plate docs from upstream.
The question is not "how do we merge this today." The question is: when Plate restarts from latest shadcn docs, what is worth deliberately reapplying, what should be thrown away, and what should be adopted from upstream without debate?
Restart from ../ui/apps/v4. Do not try to patch the current apps/www app forward. The two apps no longer differ by theme and copy. They have different route maps, search models, registry pipelines, and product surface.
Upstream should win for:
Plate should reapply only the parts that are real Plate product leverage:
content/**.apps/www remains the integration harness.Throw the Plate theme/customizer work. Brutal take: it is old fork residue with high surface area and low leverage. Upstream's current theme/style system is stronger, fresher, and tied to the actual shadcn v4 product.
This artifact was first written before the Plate docs source cutover landed. The current checkout is already past that first step:
../ui/apps/v4; ../shadcn/apps/v4 is not present in this workspace.apps/www now has source.config.ts, src/lib/source.ts, createMDX in next.config.ts, build:source, postinstall: fumadocs-mdx, and docs routes that read source.getPage(...).doc.data.body, doc.data.getText("raw"), and the registry component/example fallback.languages: ["en", "cn"].apps/www scripts and dependencies.content/docs/**, with content/docs/meta.json as the committed Fumadocs page-tree metadata root.docsConfig directly.The current middle state is narrower than the original restart problem, but still not the final restart:
docsConfig and its sync generator are gone; committed content/docs/meta.json is the navigation metadata source.So the next useful restart work is not "remove Contentlayer." That is done. The next useful work is to replace the remaining navigation/search/registry/app-shell authorities with the upstream Fumadocs and shadcn v4 model while deliberately reapplying Plate product surfaces.
| Area | Upstream ../ui/apps/v4 | Plate apps/www | Take |
|---|---|---|---|
| Main app files | 206 under app | 51 under src/app | Route tree diverged hard. |
| Content files | 227 under content/docs, including meta.json | Plate docs now live under content/docs/**, including CN files and meta.json | Content root is aligned; exact document set is Plate-owned. |
| Registry files | 1127 under registry | 381 under src/registry | Different registry ownership and generated output model. |
| Components | 71 under components | 104 under src/components | Plate added docs/API/editor/product components. |
| Scripts | 6 under scripts | 7 under apps/www/scripts | Plate replaced upstream registry/docs build pieces. |
| Shared app paths | 5 exact relative matches | 36 Plate-only app files | This is a rewrite candidate, not a merge candidate. |
| Shared content paths | 0 exact relative matches | 251 Plate-only content files | Content has to be migrated, not merged. |
| Tests | 6 upstream app tests | 70+ Plate app/registry/package integration tests | Plate tests are a separate asset. |
Files:
../ui/apps/v4/package.json../ui/apps/v4/next.config.mjs../ui/apps/v4/source.config.ts../ui/apps/v4/lib/source.ts../ui/apps/v4/mdx-components.tsxUpstream uses fumadocs-mdx, fumadocs-ui, fumadocs-core, [email protected], [email protected], React 19.2.3, @base-ui/react, radix-ui, icon packs, and a shadcn v4 registry build.
Important scripts:
postinstall: fumadocs-mdxdev: pnpm icons:dev & next dev --turbopack --port 4000build: pnpm registry:build && next buildregistry:build: pnpm --filter=shadcn build && bun run ./scripts/build-registry.mtsFumadocs source is first-class:
source.config.ts calls defineDocs({ dir: "content/docs" }).lib/source.ts loads @/.source through fumadocs-core/source.next.config.mjs wraps config with createMDX({}).Files:
apps/www/package.jsonapps/www/next.config.tsapps/www/source.config.tsapps/www/src/lib/source.tsapps/www/src/components/mdx-components.tsxapps/www/scripts/build-registry.mtsapps/www/scripts/build-docs-registry.mtsapps/www/scripts/check-docs-source-parity.mtsPlate now uses [email protected], [email protected], createMDX, defineDocs({ dir: "../../content/docs" }), and [email protected]. It still uses many @platejs/* workspace deps, editor runtime deps, AI/upload/docx/yjs/dnd deps, and package integration tests.
Important scripts:
prebuild: pnpm build:sourcebuild: pnpm build:registry && next build with the prebuild lifecycle running pnpm build:sourcebuild:source: fumadocs-mdxdev: pnpm build:source && next devtypecheck: pnpm build:source && tsx --tsconfig ./scripts/tsconfig.scripts.json scripts/check-docs-source-parity.mts && tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.package-integration.jsonbuild:registry: tsx --tsconfig ./scripts/tsconfig.scripts.json scripts/build-registry.mtsDecision: the Fumadocs source-engine adoption is already done in this checkout. Keep Plate's API MDX vocabulary and registry docs publishing as content/features, then finish the restart by replacing the remaining old nav/search/registry/app-shell pieces.
Primary files:
../ui/apps/v4/app/(app)/(root)/page.tsx../ui/apps/v4/app/(app)/docs/[[...slug]]/page.tsx../ui/apps/v4/app/(app)/docs/layout.tsx../ui/apps/v4/app/(app)/blocks/[...categories]/page.tsx../ui/apps/v4/app/(app)/charts/[type]/page.tsx../ui/apps/v4/app/(app)/colors/page.tsx../ui/apps/v4/app/(app)/create/page.tsx../ui/apps/v4/app/(app)/llm/[[...slug]]/route.ts../ui/apps/v4/app/(create)/init/route.ts../ui/apps/v4/app/(create)/init/md/route.ts../ui/apps/v4/app/(create)/init/v0/route.ts../ui/apps/v4/app/(view)/view/[style]/[name]/page.tsx../ui/apps/v4/app/api/search/route.tsUpstream docs app is also a shadcn product app:
Primary files:
apps/www/src/app/(app)/page.tsxapps/www/src/app/(app)/docs/[[...slug]]/page.tsxapps/www/src/app/(app)/docs/[[...slug]]/doc-content.tsxapps/www/src/app/(app)/docs/layout.tsxapps/www/src/app/(app)/docs/api/page.tsxapps/www/src/app/(app)/docs/components/page.tsxapps/www/src/app/(app)/docs/examples/page.tsxapps/www/src/app/(app)/docs/plugins/page.tsxapps/www/src/app/(app)/docs/examples/slate-to-html/page.tsxapps/www/src/app/(app)/editors/page.tsxapps/www/src/app/(blocks)/blocks/[name]/page.tsxapps/www/src/app/(blocks)/blocks/playground/page.tsxapps/www/src/app/api/registry-source/[name]/route.tsapps/www/src/app/cn/docs/[[...slug]]/page.tsxapps/www/src/app/dev/**Plate docs app is a Plate product/docs/registry app:
Decision: use upstream route shape as the base, then reintroduce Plate routes deliberately. Do not copy Plate's route tree wholesale.
Files:
../ui/apps/v4/source.config.ts../ui/apps/v4/lib/source.ts../ui/apps/v4/content/docs/**../ui/apps/v4/content/docs/**/meta.jsonUpstream docs are Fumadocs-native:
source.generateParams().source.getPage(params.slug).source.pageTree.page.data.getText("raw").doc.body as the compiled MDX component.meta.json drives navigation structure.Files:
content/**/*.mdxapps/www/source.config.tsapps/www/src/lib/source.tsapps/www/src/config/docs.tsapps/www/src/config/docs-api.tsapps/www/src/config/docs-examples.tsapps/www/src/config/docs-plugins.tsapps/www/src/config/registry-to-nav.tsPlate docs are Fumadocs MDX plus hand-authored nav config:
content/**, not app-local content/docs/**.(group) directory names are stripped from slugs.*.cn.mdx translated docs live beside English docs.docsConfig.sidebarNav is the real nav source.source.config.ts extends Fumadocs frontmatter for component, docs, featured, links, published, and toc.apps/www/src/lib/source.ts exposes Fumadocs i18n with English and Chinese languages.Decision: the source engine has migrated, but the content layout has not restarted from upstream. The target should still be content/docs/** or an equally explicit Fumadocs layout with committed meta.json navigation, not root content plus permanent TS nav authority.
Keep from Plate:
docs, links, toc, and API-related frontmatter concepts if still used.Throw from Plate:
docsConfig nav as the only page-tree source.Files:
../ui/apps/v4/mdx-components.tsx../ui/apps/v4/components/component-preview.tsx../ui/apps/v4/components/component-source.tsx../ui/apps/v4/components/components-list.tsx../ui/apps/v4/components/code-tabs.tsx../ui/apps/v4/components/code-block-command.tsxUpstream MDX components are mostly shadcn docs primitives:
Callout.CodeTabs.ComponentPreview.ComponentSource.ComponentsListWrapper.DirectoryList.Kbd.Files:
apps/www/src/components/mdx-components.tsxapps/www/src/components/api-list.tsxapps/www/src/components/package-info.tsxapps/www/src/components/component-installation.tsxapps/www/src/components/component-preview.tsxapps/www/src/components/component-preview-pro.tsxapps/www/src/components/component-source.tsxapps/www/src/components/framework-docs.tsxapps/www/src/components/release-index.tsxapps/www/src/registry/blocks/fumadocs/fumadocs-mdx-components.tsxapps/www/src/registry/blocks/fumadocs/mdx-plate-components.tsxPlate MDX adds a real API documentation language:
APIAPIAttributesAPIItemAPIListAPIListAPIAPIMethodsAPIOptionsAPIParametersAPIPropsAPIReturnsAPIStateAPISubListAPISubListItemAPITransformsKeyTableKeyTableItemPackageInfoComponentInstallationComponentPreviewProReleaseIndexUsage evidence:
content/api/** heavily uses APIItem, APIOptions, APIParameters, APIReturns, APISubListItem, and PackageInfo.apps/www/src/registry/blocks/fumadocs/fumadocs-mdx-components.tsx already looks like a bridge for rendering Plate API docs in Fumadocs.Decision: keep Plate API MDX vocabulary. Rebuild it as a Fumadocs-compatible MDX component layer, starting from apps/www/src/registry/blocks/fumadocs/*, not from the old Contentlayer runtime wrapper.
Throw:
useMDXComponent from next-contentlayer2/hooks.Keep:
PackageInfo if bundle/source/npm metadata still matters.ComponentInstallation if component docs remain generated from registry metadata.ComponentPreviewPro only if Plate Plus examples remain linked from docs.Files:
../ui/apps/v4/app/(app)/docs/[[...slug]]/page.tsx../ui/apps/v4/app/(app)/docs/layout.tsx../ui/apps/v4/components/docs-sidebar.tsx../ui/apps/v4/components/docs-toc.tsx../ui/apps/v4/components/docs-copy-page.tsx../ui/apps/v4/components/docs-base-switcher.tsx../ui/apps/v4/components/open-in-v0-cta.tsxUpstream page behavior:
dynamic = "force-static", dynamicParams = false, revalidate = false.title and description.findNeighbour(source.pageTree, page.url).DocsCopyPage.DocsBaseSwitcher for base/radix component docs.source.pageTree.Files:
apps/www/src/app/(app)/docs/[[...slug]]/page.tsxapps/www/src/app/(app)/docs/[[...slug]]/doc-content.tsxapps/www/src/app/(app)/docs/layout.tsxapps/www/src/components/docs-nav.tsxapps/www/src/components/docs-toc.tsxapps/www/src/components/llm-copy-button.tsxapps/www/src/components/view-options.tsxapps/www/src/components/open-in-plus.tsxPlate page behavior:
dynamic = 'force-static'.source.getPage(params.slug, "en")./docs/components/[name] and /docs/examples/[name].source.getPages("en") and registry items.ComponentInstallation for component docs.ComponentPreview for example docs.LLMCopyButton, ViewOptions, OpenInPlus, related docs badges, previous/next buttons, and custom TOC.Decision: keep the registry-derived docs behavior. The first Fumadocs route cutover is already in place, but doc-content.tsx, related docs, pager/nav metadata, and LLM UI still need to be judged against upstream's Fumadocs page model instead of carried forward by inertia.
Keep:
file.meta.docs..md route model leaves a real gap.OpenInPlus if Plate Plus is still part of docs conversion.Throw or rewrite:
DocsNav accordion/filter as the primary nav. Use upstream DocsSidebar/Fumadocs page tree first.DocsNav.docsMap fallback as a substitute for source metadata.Files:
../ui/apps/v4/scripts/build-registry.mts../ui/apps/v4/registry/bases/base/registry.ts../ui/apps/v4/registry/bases/radix/registry.ts../ui/apps/v4/registry/new-york-v4/**../ui/apps/v4/registry/styles/style-*.css../ui/apps/v4/public/r/**../ui/apps/v4/registry/config.test.tsUpstream v4 registry pipeline:
registry/bases/base and registry/bases/radix.registry/styles/style-*.css.public/r.shadcn/schema.shadcn/utils transforms.This is the contract Plate should follow at the installer boundary.
Files:
apps/www/src/registry/registry.tsapps/www/src/registry/registry-ui.tsapps/www/src/registry/registry-components.tsapps/www/src/registry/registry-examples.tsapps/www/src/registry/registry-blocks.tsapps/www/src/registry/registry-hooks.tsapps/www/src/registry/registry-lib.tsapps/www/src/registry/registry-kits.tsapps/www/src/registry/registry-pro.tsapps/www/scripts/build-registry.mtsapps/www/scripts/build-docs-registry.mtsapps/www/src/lib/rehype-utils.tsapps/www/src/lib/registry-cache.tsapps/www/public/r/**apps/www/public/rd/**Plate registry pipeline:
plate registry with homepage https://platejs.org.@ registry dependencies to /r or /rd URLs.src/__registry__/index.tsx with React.lazy component previews.public/r/registry.json or public/rd/registry.json.shadcn build against generated registry JSON.registry-docs.json from root content/**.fumadocs registry item containing mdx-components.tsx, mdx-plate-components.tsx, and docs dependencies.Decision: keep Plate registry content and delivery, but modernize it around upstream shadcn v4 schema/resolver/base behavior. Do not preserve old shadcn 2.6.3 assumptions.
Keep:
apps/www/src/registry/**.build-docs-registry.mts.fumadocs registry item idea.registry-shadcn.json lookup only if Plate registry still references upstream @shadcn/*.Rewrite:
build-registry.mts around upstream shadcn v4 conventions.Throw:
Files:
../ui/apps/v4/components/block-viewer.tsx../ui/apps/v4/components/component-preview.tsx../ui/apps/v4/components/component-source.tsx../ui/apps/v4/app/(view)/view/[style]/[name]/page.tsxUpstream BlockViewer:
/view/[style]/[name]./r/styles/new-york-v4/....item.files.Files:
apps/www/src/components/block-viewer.tsxapps/www/src/components/component-preview.tsxapps/www/src/components/component-installation.tsxapps/www/src/components/component-source.tsxapps/www/src/app/api/registry-source/[name]/route.tsapps/www/src/app/(blocks)/blocks/[name]/page.tsxPlate BlockViewer:
/blocks/[name] or item.meta.src instead of upstream /view./api/registry-source/[name] when switching to code view.item.meta.isPro.npx shadcn@latest add ${siteConfig.registryUrl}${item.name}.Decision: start from upstream preview/view architecture, then reapply Plate registry install behavior and Plate editor demo rendering. The Plate preview code has product value, but upstream's current view/style architecture is cleaner.
Keep:
Adopt:
/view concept if style previews matter.Throw:
/api/registry/[name] lazy code route. If lazy source loading stays, keep it under an internal docs-code route such as /api/registry-source/[name].block-viewer.tsx.Files:
../ui/apps/v4/app/api/search/route.ts../ui/apps/v4/components/command-menu.tsx../ui/apps/v4/lib/page-tree.ts../ui/apps/v4/lib/source.tsUpstream search:
createFromSource(source) from fumadocs-core/search/server.useDocsSearch({ type: "fetch" }).Files:
apps/www/src/components/command-menu.tsxapps/www/src/config/docs.tsapps/www/src/components/docs-nav.tsxPlate search:
cmdk over docsConfig.mainNav and docsConfig.sidebarNav.Decision: use upstream Fumadocs search. Plate's current command menu is a hack and should not survive as-is.
Keep:
Throw:
Files:
../ui/apps/v4/app/globals.css../ui/apps/v4/app/legacy-themes.css../ui/apps/v4/components/active-theme.tsx../ui/apps/v4/components/theme-customizer.tsx../ui/apps/v4/lib/themes.ts../ui/apps/v4/registry/styles/style-*.css../ui/apps/v4/registry/themes.tsUpstream has a current shadcn v4 theme/style system:
shadcn/tailwind.css.style-vega, style-nova, style-lyra, style-maia, style-mira, style-luma, style-sera.ActiveThemeProvider to apply theme-${activeTheme} and theme-scaled.Files:
apps/www/src/app/globals.cssapps/www/src/app/themes.cssapps/www/src/lib/themes.tsapps/www/src/components/theme-customizer.tsxapps/www/src/components/customizer-drawer.tsxapps/www/src/components/themes-button.tsxapps/www/src/components/themes-selector.tsxapps/www/src/components/themes-styles.tsxapps/www/src/hooks/use-themes-config.tsPlate custom themes include named palettes like Ayu, Catppuccin, Dune, Everforest, GitHub, Horizon, Linear, One Dark Pro, plus many custom CSS theme/radius/font variants.
Plate CSS has explicit cleanup comments:
Custom scrollbar styling (remove after sync).Custom prose styling (remove after sync).MDX (remove after sync).Decision: throw Plate themes/customizer. Keep only Plate brand tokens that are actually used outside theme browsing.
Throw:
apps/www/src/lib/themes.ts.apps/www/src/app/themes.css.customizer-drawer.tsx.Adopt:
ActiveThemeProvider.Files:
../ui/apps/v4/app/layout.tsx../ui/apps/v4/components/theme-provider.tsx../ui/apps/v4/components/active-theme.tsxUpstream providers:
NuqsAdapter.LayoutProvider.ActiveThemeProvider.ThemeProvider.Toaster.Analytics.TailwindIndicator.d.Files:
apps/www/src/app/layout.tsxapps/www/src/components/context/providers.tsxapps/www/src/components/context/theme-provider.tsxPlate providers:
HTML5Backend.Agentation in dev.Toaster.TailwindIndicator.Decision: start from upstream providers, then add Plate runtime providers only where current features require them.
Keep:
DndProvider if editor demos are still rendered in the docs app.Agentation only if this repo still wants local visual feedback in dev.Adopt:
ActiveThemeProvider.Known trap:
docs/solutions/developer-experience/2026-03-28-next-prerendered-client-editors-need-dnd-hooks-to-noop-on-the-server.md says app-level DnD providers are not enough. Browser-only DnD hooks must no-op during prerender. Do not "fix" docs restart DnD crashes by slapping ssr: false everywhere.File: ../ui/apps/v4/next.config.mjs
Upstream config:
createMDX({}) wrapper.typescript.ignoreBuildErrors = true../registry/**/* and ./styles/**/*./docs/:path*.md to /llm/:path*./init.md to /init/md.File: apps/www/next.config.ts
Plate config:
externalDir only in dev.reactCompiler: !isDev.staticPageGenerationTimeout: 1200.transpilePackages: ['ts-morph']./r/:path and /rd/:path to JSON.?locale=cn URLs to /cn.Decision: merge the configs by intent, not by text.
Keep:
/r and /rd JSON redirects if public registry URLs still rely on them.Adopt:
createMDX./docs/*.md LLM rewrite.Throw:
apps/www/next.config.ts.Known trap:
docs/solutions/developer-experience/2026-03-12-typescript-workspace-subpath-aliases-in-apps-www.md explains why workspace source aliases matter. Do not simplify them into broad wildcard aliases and call it done. That caused mixed source/dist TypeScript nonsense.Files:
apps/www/tsconfig.jsonapps/www/tsconfig.package-integration.json../ui/apps/v4/tsconfig.jsonapps/www/src/__tests__/package-integration/**apps/www/src/registry/**/*.spec.ts*../ui/apps/v4/app/(create)/**.test.ts../ui/apps/v4/registry/config.test.tsUpstream TS config is simple and app-local:
@/* maps to app root.next.config.mjs.react types path.Plate TS config is a docs app plus package harness:
@/* maps to ./src/*.@platejs/*/react and package root imports.@platejs/* and @udecode/* source aliases.registry maps to ./public/r/registry.json.registry-shadcn maps to ./registry-shadcn.json.tsconfig.package-integration.json checks package integration tests against built package contracts.Decision: keep Plate split typecheck. It exists because the docs app doubles as package integration proof.
Keep:
tsconfig.package-integration.json.Adopt:
Throw:
Files:
content/**/*.cn.mdxapps/www/src/app/cn/**apps/www/src/hooks/useLocale.tsapps/www/src/lib/withLocale.tsapps/www/src/components/languages-dropdown-menu.tsxapps/www/src/components/docs-nav.tsxPlate has 124 CN MDX files and a duplicate /cn route tree. Upstream has no i18n in this app.
Decision: keep CN. Port it using Fumadocs i18n patterns. Do not preserve the current duplicate route logic unless forced.
Keep:
Rewrite:
/cn/docs/[[...slug]] duplicated page logic.hrefWithLocale and manual route-prefix behavior around the new Fumadocs source tree.Throw:
/cn route plumbing once Fumadocs i18n covers the same behavior.Files:
../ui/apps/v4/app/(app)/(root)/page.tsx../ui/apps/v4/components/site-header.tsx../ui/apps/v4/lib/config.ts../ui/apps/v4/components/main-nav.tsx../ui/apps/v4/components/mobile-nav.tsxUpstream header/nav:
source.pageTree.GitHubLink, SiteConfig, ModeSwitcher, create/v0 controls, New button.Files:
apps/www/src/app/(app)/page.tsxapps/www/src/components/site-header.tsxapps/www/src/config/site.tsapps/www/src/components/logo.tsxapps/www/src/components/main-nav.tsxapps/www/src/components/mobile-nav.tsxapps/www/src/components/mcp-dialog.tsxapps/www/src/components/languages-dropdown-menu.tsxPlate header/nav:
Decision: keep Plate branding and product links, but use upstream Fumadocs-aware nav infrastructure where possible.
Keep:
Throw:
Upstream files:
../ui/apps/v4/app/(app)/llm/[[...slug]]/route.ts../ui/apps/v4/components/docs-copy-page.tsx../ui/apps/v4/lib/llm.tsPlate files:
apps/www/src/components/llm-copy-button.tsxapps/www/src/components/view-options.tsxapps/www/src/lib/llm-context.tsUpstream serves .md routes through Fumadocs and page.data.getText("raw"). Plate exposes copy/view actions on docs pages, but the restart should not preserve that duplicate UI by default.
Decision: adopt upstream .md route and copy-page model. Reapply Plate-specific LLM context only if the upstream route cannot cover a real Plate agent/docs workflow.
Keep:
Adopt:
/docs/:path*.md rewrite.Plate files:
apps/www/public/r/**apps/www/public/rd/**apps/www/registry-shadcn.jsonapps/www/src/__registry__/index.tsxUpstream files:
../ui/apps/v4/public/r/**../ui/apps/v4/registry/__index__.tsx../ui/apps/v4/registry/bases/__index__.tsx../ui/apps/v4/examples/__index__.tsxDecision: generated artifacts should come from the new source pipeline. Do not hand-edit them. For the restart, preserve source and scripts, not old generated output.
Keep source:
apps/www/src/registry/**.apps/www/scripts/build-registry.mts only as input to rewrite.apps/www/scripts/build-docs-registry.mts only as input to rewrite.Regenerate:
public/r/**.public/rd/**.src/__registry__/index.tsx.Read these before phase two implementation:
docs/solutions/developer-experience/2026-03-12-typescript-workspace-subpath-aliases-in-apps-www.md
docs/solutions/developer-experience/2026-04-06-next-turbopack-needs-client-boundaries-at-react-package-entrypoints.md
docs/solutions/developer-experience/2026-04-06-registry-helper-refactors-must-update-template-registry-dependencies.md
apps/www/src.docs/solutions/developer-experience/2026-04-27-mdx-generated-markers-must-use-jsx-comments.md
docs/solutions/developer-experience/2026-03-28-next-prerendered-client-editors-need-dnd-hooks-to-noop-on-the-server.md
| Item | Files | Verdict | Phase Two Action |
|---|---|---|---|
| Fumadocs engine | ../ui/apps/v4/source.config.ts, ../ui/apps/v4/lib/source.ts | Adopted | Already wired in apps/www/source.config.ts and apps/www/src/lib/source.ts; preserve it. |
| Contentlayer engine | former apps/www/contentlayer.config.js, next-contentlayer2 usage | Thrown | Already removed; do not recreate compatibility layers around it. |
| Plate docs content | content/docs/** | Keep | Moved under the upstream-style Fumadocs source root. |
| Fumadocs meta | ../ui/apps/v4/content/docs/**/meta.json | Adopted | content/docs/meta.json is committed and owns the Plate page tree plus _plate overlays. |
| Manual docs nav | former apps/www/src/config/docs*.ts | Thrown | Deleted after metadata covered pages, labels, CN titles, registry/app-only links, sections, and category groups. |
| Plate API MDX components | apps/www/src/components/api-list.tsx, apps/www/src/registry/blocks/fumadocs/* | Keep | Port into Fumadocs MDX layer. |
| Plate MDX Contentlayer wrapper | apps/www/src/components/mdx-components.tsx | Rewritten partly | useMDXComponent is gone; keep auditing component boundaries against Fumadocs/server rendering. |
| Registry-derived docs pages | apps/www/src/app/(app)/docs/[[...slug]]/page.tsx | Kept partly | Fumadocs fallback is wired; next pass should simplify metadata fallbacks and align with upstream static highlighted-source flow. |
Plate DocContent UX | apps/www/src/app/(app)/docs/[[...slug]]/doc-content.tsx | Keep selectively | Port related docs, Plus CTA, and any retained copy UX onto upstream page/tree assumptions. |
Plate DocsNav | apps/www/src/components/docs-nav.tsx | Keep UX, rewrite code | Keep accordion/grouped sidebar behavior for Plate's large docs tree, but rebuild it on Fumadocs page data and upstream sidebar primitives. |
| Plate command menu | apps/www/src/components/command-menu.tsx | Throw/rewrite | Replace with upstream Fumadocs search plus Plate groups. |
| Invisible command suffix hack | apps/www/src/components/command-menu.tsx | Throw | Do not port. |
| Upstream search route | ../ui/apps/v4/app/api/search/route.ts | Adopt | Use Fumadocs search API. |
| Plate registry content | apps/www/src/registry/** | Keep | Upgrade to shadcn v4 contract. |
| Plate registry build | apps/www/scripts/build-registry.mts | Rewrite | Keep Plate content rules, adopt upstream v4 registry model. |
| Plate docs registry build | apps/www/scripts/build-docs-registry.mts | Keep concept | Generate Fumadocs-ready docs registry. |
| Upstream registry v4 pipeline | ../ui/apps/v4/scripts/build-registry.mts | Adopt patterns | Use schema/resolver/base/style behavior as source of truth. |
| Lazy registry source route | apps/www/src/app/api/registry-source/[name]/route.ts | Keep internal | Keep only for code-view bandwidth. Do not treat it as a public registry API. |
| Plate component install UI | apps/www/src/components/component-installation.tsx | Keep | Reapply for Plate registry items. |
| Plate previews | apps/www/src/components/component-preview.tsx, block-viewer.tsx | Keep selectively | Combine with upstream /view model. |
Upstream /view route | ../ui/apps/v4/app/(view)/view/[style]/[name]/page.tsx | Adopt if style previews stay | Prefer over Plate-only block preview route. |
| Plate editor demos | apps/www/src/registry/examples/**, apps/www/src/app/(app)/editors/** | Keep | These are Plate docs product surface. |
| Plate theme library | apps/www/src/lib/themes.ts, apps/www/src/app/themes.css | Throw | Use upstream shadcn theme/style system. |
| Plate customizer drawer | apps/www/src/components/customizer-drawer.tsx, theme selectors | Throw | Dead weight for restart. |
| Upstream create/customizer | ../ui/apps/v4/app/(app)/create/** | Adopt if wanted | Use for preset/style generation, not Plate old theme UI. |
| Plate providers | apps/www/src/components/context/providers.tsx | Keep selectively | Add DnD/Jotai only for retained editor surfaces. |
| Upstream providers | ../ui/apps/v4/app/layout.tsx, components/theme-provider.tsx, active-theme.tsx | Adopt | Use as base shell. |
| Workspace aliases | apps/www/next.config.ts, apps/www/tsconfig.json | Keep | Required for local package dev/typecheck sanity. |
| Split typecheck | apps/www/tsconfig.package-integration.json | Keep | Required if app remains package harness. |
| CN docs | content/**/*.cn.mdx, src/app/cn/** | Keep | Keep Chinese docs; rewrite routing with Fumadocs/i18n instead of duplicating the old route logic. |
| MCP dialog | apps/www/src/components/mcp-dialog.tsx | Keep | Keep MCP install/docs/header flow. |
| Plate Plus links | OpenInPlus, ComponentPreviewPro, registry-pro.ts | Keep | Keep public Plus/Pro docs hooks. |
| Dev routes | apps/www/src/app/dev/** | Throw from public docs base | Move to internal/debug app if still useful. |
| Package integration tests | apps/www/src/__tests__/package-integration/** | Keep | Do not lose behavioral coverage during app restart. |
This is the recommended default for confirmation. "Discard upstream" means do not carry that shadcn product feature into Plate's public docs app, even if the implementation is good upstream code.
| Area | Keep From Upstream Shadcn | Discard From Upstream Shadcn | Keep From Custom Plate | Discard From Custom Plate | Suggested Default |
|---|---|---|---|---|---|
| Base app foundation | apps/v4 app-router structure, Fumadocs-first docs shell, modern shadcn v4 app patterns | Upstream brand/product copy | Plate brand, siteConfig, Plate nav labels | Current app shell if it fights Fumadocs | Start from upstream, rebrand to Plate |
| Docs engine | fumadocs-mdx, fumadocs-ui, source.config.ts, lib/source.ts, createMDX Next wrapper | None | Plate docs content and custom MDX vocabulary | Contentlayer runtime and next-contentlayer2 | Engine is adopted; keep it hard-cut from Contentlayer |
| Content source | Fumadocs content/docs/** layout and meta.json navigation model | Upstream shadcn docs content as public Plate docs | Root content/** Plate docs, API docs, examples, guides, plugins, install docs | Content path grouping only if it blocks Fumadocs | Add explicit Fumadocs metadata; move content only if root layout blocks page-tree authority |
| Public docs navigation | Fumadocs page tree, upstream DocsSidebar primitives, mobile nav model | Upstream nav items for Components, Blocks, Charts, Directory, Create unless Plate wants those pages | Plate nav categories: Docs, Editors, API, Plugins, Examples, Installation | Manual nav as runtime authority | Use Fumadocs tree, generate/port Plate nav structure |
| Sidebar accordion/filter | Upstream shadcn sidebar primitives and Fumadocs page-tree data | Upstream always-expanded flat docs sidebar as the final Plate UX | Plate accordion sections, active-section compression, filter input, labels, CN labels | Current DocsNav implementation: manual docsConfig authority, timeout scroll, direct DOM query, route-prefix hacks | Keep the Plate accordion UX, rewrite it cleanly |
| Search | Fumadocs app/api/search/route.ts, useDocsSearch, upstream command-menu architecture | Upstream color/block/create/v0 search groups | Plate API, plugins, examples, editors, MCP groups | Invisible Unicode suffix hack and client-only nav search | Adopt upstream search, inject Plate groups |
| Docs page rendering | Static Fumadocs page loading, TOC, neighbours, upstream copy-page pattern | OpenInV0Cta | Plate DocContent ideas: related docs and Plus CTA | Metadata fallbacks that duplicate Fumadocs, Plate extra LLM copy/view UI | Continue rewriting Plate UX around Fumadocs page data |
| API MDX docs | Fumadocs MDX compile/runtime path | None | API*, APISubList*, KeyTable, PackageInfo, current API docs content | Old useMDXComponent wrapper | Keep strongly |
| Fumadocs API bridge | Upstream default MDX components and Fumadocs UI primitives | None | src/registry/blocks/fumadocs/fumadocs-mdx-components.tsx, mdx-plate-components.tsx | Placeholder behavior that hides needed docs UI | Use this as the port starting point |
| Component docs generated from registry | Upstream component-source/preview patterns | Upstream shadcn component docs content | Plate ComponentInstallation, registry-derived /docs/components/[name] | Contentlayer fallback shape | Keep concept, rewrite implementation |
| Example docs generated from registry | Upstream preview/source UI patterns | Generic shadcn example docs content | Plate registry examples and /docs/examples/[name] pages | Old duplicate preview paths if replaced by upstream /view | Keep |
| Registry contract | shadcn v4 schema, namespace behavior, resolver behavior, local-file install semantics | Upstream registry content that is unrelated to Plate | Plate registry item content under src/registry/**, @plate namespace | Plate-only schema ideas or installer workarounds | Upstream contract, Plate content |
| Registry build | Upstream v4 build design, style/base transforms, schema validation, generated output discipline | Upstream styles/components that Plate does not ship | Plate docs-registry generation and local public/r/public/rd delivery needs | Old shadcn 2.6.3 assumptions | Rewrite Plate build from upstream v4 patterns |
| Generated registry output | Upstream rule: generated output comes from source pipeline | Hand-copied upstream public output | Plate public/r, public/rd, src/__registry__/index.tsx as regenerated artifacts | Manual edits to generated output | Regenerate only |
| Template/local install sync | Upstream local-file install semantics | Any upstream template workflow not used by Plate | Plate template sync tooling and @plate install entrypoint | Generated-template hand edits | Keep Plate sync, align with upstream installer |
| Source code preview | Upstream highlighted code/file tree design | v0-specific copy/open actions | Plate dependency-aware manual install and registry URL copy command | Public-shaped lazy registry API | Keep lazy source loading for bandwidth, drop v0 |
| Lazy registry source route | None unless needed | None | /api/registry-source/[name] for code-view payloads | /api/registry/[name] as a public-looking registry API | Keep internal docs source endpoint only |
| Blocks route | Upstream /view/[style]/[name] renderer pattern | Upstream block gallery categories as public Plate pages | Plate editor block demo routes | Plate duplicate route shape if upstream /view can cover it | Keep renderer, not gallery |
| Charts pages | Maybe chart component implementation if registry needs it | /charts/** public product pages | None obvious | None | Discard from Plate public docs |
| Colors pages | Maybe color utilities/tokens if style system needs them | /colors public product page | None obvious | Plate old color/theme pages | Discard page |
| Create/customizer app | Maybe low-level preset/style code if registry build needs it | /create public page, create app UX, project form, share/history/random UI | None from Plate old customizer | Plate theme/customizer drawer | Discard for now |
| v0 | None | OpenInV0Cta, V0Button, app/(create)/init/v0, v0 search/copy/project hooks | None | Plate commented v0 remnants | Discard all v0 |
| Init route | Upstream /init and /init.md pattern for shadcn-compatible bootstrap | v0 init route | Plate registry install URLs and @plate bootstrap needs | Any custom installer semantics beyond shadcn-compatible registry bootstrap | Keep non-v0 Plate init/bootstrap if it directly serves @plate; no create/v0 side quest |
| Directory/registry docs | Upstream registry contract docs as implementation reference | Public shadcn directory pages | Plate installation/local-docs/MCP docs | Old docs that explain obsolete Plate registry behavior | Rewrite as Plate registry docs |
| Theme system | Upstream shadcn v4 CSS tokens, style CSS, ActiveThemeProvider | Upstream public theme/create UI if not needed | Minimal Plate brand tokens | themes.css, src/lib/themes.ts, custom theme selector/drawer | Keep upstream system, discard Plate themes |
| CSS/prose/code styles | Upstream current globals and code styling | Any shadcn brand-only styles | Plate-specific prose/code tweaks only if API docs require them | CSS blocks marked "remove after sync" | Start upstream, reapply minimal Plate fixes |
| Header | Upstream Fumadocs-aware header structure, mobile nav behavior | Create/New/v0 controls, shadcn nav labels | Plate logo, GitHub, Discord, Docs, Editors, language switcher, MCP entry | Old header comments, customizer buttons, v0/create buttons | Keep Plate brand on upstream structure |
| Homepage | Upstream app structure patterns if useful | Upstream shadcn marketing content | Plate homepage direction: centered product/editor positioning | Theme customizer, theme gallery, random Potion/pro iframe clutter | Keep a Plate home page, centered and no themes |
| Public assets and manifest | Upstream asset layout if useful | shadcn favicons/brand images | Plate favicon, manifest, _og.png, Plate metadata assets | Stale generated registry screenshots/assets only if regenerated | Keep Plate assets, regenerate generated assets |
| Redirects and rewrites | Upstream .md LLM rewrite, non-v0 init rewrite if kept | shadcn legacy redirects unrelated to Plate, v0 rewrites | Plate /r and /rd JSON redirects, old ?locale=cn redirects | Redirects for discarded theme/create/v0 pages | Keep Plate registry/CN redirects and upstream LLM rewrite |
| Providers | Upstream theme provider, tooltip providers, toaster, layout providers | v0/create-only providers | Plate DndProvider, Jotai only where retained components need them, Agentation dev only if wanted | Providers required only by discarded theme/customizer code | Start upstream, add minimal Plate providers |
| DnD/editor runtime | None directly | None | DnD provider and package-level prerender no-op expectations for editor demos | Route-level SSR hacks as default fix | Keep if editor demos stay |
| Package workspace aliases | None from upstream simple app | Upstream simple-only tsconfig as complete answer | Plate next.config.ts source aliases, exact tsconfig paths, split integration typecheck | Contentlayer aliases after removal | Keep Plate alias/typecheck model |
| Package integration tests | None comparable upstream | None | apps/www/src/__tests__/package-integration/**, registry specs | Tests only tied to discarded Contentlayer UI | Keep |
| Upstream create/init tests | Tests for kept non-v0 init behavior | v0 tests | Add Plate registry/install tests around kept behavior | None | Keep only matching retained routes |
| CN docs | None | None | Existing *.cn.mdx, language dropdown, locale labels | Duplicate /cn route implementation if Fumadocs i18n replaces it | Keep CN |
| Plate Plus / Pro | None | None | ComponentPreviewPro, OpenInPlus, registry-pro.ts, public Plus links | Pro iframe/homepage clutter if not strategic | Keep Plus/Pro hooks |
| MCP docs/dialog | Upstream MCP docs can inform structure | Upstream shadcn-specific MCP copy | Plate mcp-dialog, installation MCP docs, header entry | None unless duplicated by better docs UI | Keep MCP |
| LLM docs | Upstream /docs/*.md rewrite, LLM route, and shadcn copy-page UI | None | Plate-specific context only if upstream route cannot cover it | Plate LLMCopyButton, ViewOptions, duplicate LLM UI | Use shadcn LLM/copy model |
| Analytics | None beyond basic app analytics shape | v0/create/per-click event tracking | Plate GA | Per-click event tracking and analytics around discarded surfaces | Keep GA only |
| OG/RSS | Upstream OG/RSS structure | shadcn-specific content | Plate OG branding and metadata | Stale duplicate font assets if not needed | Keep structure, rebrand |
| Dev/debug routes | None | None | Move useful debug tools elsewhere if still needed | apps/www/src/app/dev/** in public docs app | Discard from restart |
| Slate-to-HTML special page | None | None | docs/examples/slate-to-html, blocks/slate-to-html, Tailwind trace include | Generic preview path for this page, because RSC cannot be previewed normally | Keep special route/page |
| Release docs | Fumadocs content patterns | shadcn changelog content | Plate content/releases/index.mdx, ReleaseIndex if release docs stay | Contentlayer-only release generation assumptions | Keep content, port renderer |
| Dependencies | Current upstream Fumadocs/shadcn v4 deps | v0-only deps if any | Plate editor/runtime deps required by retained demos | contentlayer2, next-contentlayer2, old theme-only deps | Keep upgrading and pruning |
| Verification model | Upstream app tests for retained upstream routes | Tests for discarded routes | Plate package integration and registry validation | Browser checks for discarded theme/create/v0 paths | Verify retained surfaces only |
docsConfig and current content grouping, then move sidebar/pager toward source.pageTree.../ui/apps/v4, bringing over Plate siteConfig, logo, product nav labels, and minimal providers.content/** remains acceptable. Move Plate content into content/docs/** only if that is needed for clean Fumadocs metadata and page-tree authority.apps/www/src/registry/blocks/fumadocs/* as the starting point.@plate init/bootstrap if useful.ComponentPreviewPro, OpenInPlus, and registry-pro.ts..md route and copy-page model; discard Plate's extra LLMCopyButton / ViewOptions unless a later gap appears.@plate registry install; skip create/v0/product-generator behavior.@plate bootstrap only if directly useful./api/registry/[name]: throw as a public-shaped route. Keep /api/registry-source/[name] for lazy code-view bandwidth if large registry payloads require it.docsConfig files: use as migration data, not the new architecture.Completed evidence pass:
docs/solutions traps relevant to apps/www.2026-05-24 refresh evidence:
../ui/apps/v4 exists and ../shadcn/apps/v4 does not in this workspace.meta.json files, and 381 registry source files.apps/www/package.json uses build:source, postinstall: fumadocs-mdx, and typecheck runs scripts/check-docs-source-parity.mts.apps/www/source.config.ts, apps/www/src/lib/source.ts, and apps/www/next.config.ts are the active Fumadocs source path.apps/www/src/app/(app)/docs/[[...slug]]/page.tsx uses source.getPage, source.getPages, doc.data.body, and doc.data.getText("raw").docs-nav, pager, site-header, and command-menu still import docsConfig.No runtime verification was needed because this refresh only updated the research artifact. No source app behavior was changed.