diff --git a/prototypes/docusaurus/sidebars.ts b/prototypes/docusaurus/sidebars.ts index 87be5d7..a240219 100644 --- a/prototypes/docusaurus/sidebars.ts +++ b/prototypes/docusaurus/sidebars.ts @@ -6,6 +6,9 @@ import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; // - deployment/troubleshooting-when-using-webpacker // - misc/asset-pipeline // +// URL-compatibility stubs (redirect to a current, live page): +// - pro/home-pro (→ pro/react-on-rails-pro) +// // Contributing/Resources pages (linked from introduction.md instead of sidebar): // - misc/doctrine // - misc/style @@ -26,6 +29,7 @@ const sidebars: SidebarsConfig = { 'getting-started/quick-start', 'getting-started/create-react-on-rails-app', 'getting-started/tutorial', + 'getting-started/examples-and-references', 'getting-started/installation-into-an-existing-rails-app', 'getting-started/project-structure', 'getting-started/using-react-on-rails', @@ -172,6 +176,7 @@ const sidebars: SidebarsConfig = { type: 'category', label: 'Migration Guides', items: [ + 'migrating/example-migrations', 'migrating/migrating-from-react-rails', 'migrating/migrating-from-vite-rails', 'migrating/migrating-from-webpack-to-rspack', @@ -201,6 +206,7 @@ const sidebars: SidebarsConfig = { link: { type: 'doc', id: 'pro/react-server-components/index' }, items: [ 'pro/react-server-components/purpose-and-benefits', + 'pro/react-server-components/success-stories', 'pro/react-server-components/how-react-server-components-work', 'pro/react-server-components/rendering-flow', 'pro/react-server-components/tutorial', @@ -211,6 +217,7 @@ const sidebars: SidebarsConfig = { 'pro/react-server-components/selective-hydration-in-streamed-components', 'pro/react-server-components/flight-protocol-syntax', 'pro/react-server-components/upgrading-existing-pro-app', + 'pro/react-server-components/rspack-compatibility', 'pro/react-server-components/glossary', { type: 'category', diff --git a/prototypes/docusaurus/src/constants/docsRoutes.ts b/prototypes/docusaurus/src/constants/docsRoutes.ts index 91aa326..94e16f1 100644 --- a/prototypes/docusaurus/src/constants/docsRoutes.ts +++ b/prototypes/docusaurus/src/constants/docsRoutes.ts @@ -1,6 +1,7 @@ export const docsRoutes = { docsGuide: '/docs/', createApp: '/docs/getting-started/create-react-on-rails-app', + examplesAndReferences: '/docs/getting-started/examples-and-references', installExistingApp: '/docs/getting-started/existing-rails-app', ossVsPro: '/docs/getting-started/oss-vs-pro', proOverview: '/docs/pro', diff --git a/prototypes/docusaurus/src/pages/examples.module.css b/prototypes/docusaurus/src/pages/examples.module.css index 2dcc300..18823d2 100644 --- a/prototypes/docusaurus/src/pages/examples.module.css +++ b/prototypes/docusaurus/src/pages/examples.module.css @@ -39,6 +39,11 @@ margin-bottom: 0.85rem; } +.sectionLead { + margin: 0.45rem 0 0; + color: var(--ifm-color-content-secondary); +} + .sectionHeader h2 { margin-bottom: 0; } @@ -46,14 +51,14 @@ .grid { margin-bottom: 1.6rem; display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); gap: 0.9rem; } .decisionGrid { margin-bottom: 3rem; display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: 1rem; } @@ -70,6 +75,30 @@ line-height: 1.12; } +.repoMeta { + margin: 0 0 0.55rem; + font-size: 0.88rem; + color: var(--ifm-color-content-secondary); +} + +.tagRow { + display: flex; + flex-wrap: wrap; + gap: 0.35rem; + margin: 0.85rem 0 0.2rem; +} + +.tag { + display: inline-flex; + align-items: center; + padding: 0.18rem 0.45rem; + border-radius: 999px; + background: var(--site-soft-surface); + border: 1px solid var(--site-border); + font-size: 0.75rem; + font-weight: 700; +} + .cardLink { display: inline-flex; align-items: center; diff --git a/prototypes/docusaurus/src/pages/examples.tsx b/prototypes/docusaurus/src/pages/examples.tsx index f0a3c5f..52cbb43 100644 --- a/prototypes/docusaurus/src/pages/examples.tsx +++ b/prototypes/docusaurus/src/pages/examples.tsx @@ -5,76 +5,158 @@ import Layout from '@theme/Layout'; import {docsRoutes} from '../constants/docsRoutes'; import styles from './examples.module.css'; -const evaluationPaths = [ +const decisionPaths = [ { - eyebrow: 'Evaluator path', - title: 'Compare setup approaches', + eyebrow: 'Starter path', + title: 'Start a new Rails + React app', description: - 'Start with the docs landing page to choose between new app setup, existing app install, migration, or Pro evaluation.', + 'Use the create-app and quick-start docs first, then compare the maintained starter repos for SSR + HMR or React on Rails Pro + RSC.', href: docsRoutes.docsGuide, - cta: 'Open the docs guide', + cta: 'Open starter docs', }, { eyebrow: 'Migration path', title: 'Move from react-rails', description: - 'Follow a migration sequence validated against a real open-source example app instead of reconstructing it from old guides.', + 'Use the migration guide together with the maintained migration reference repos instead of reconstructing the process from older blog posts.', href: docsRoutes.migrateFromReactRails, - cta: 'Use the react-rails guide', + cta: 'Use the migration guide', }, { - eyebrow: 'Upgrade path', - title: 'Move from OSS to Pro', + eyebrow: 'Pro path', + title: 'Evaluate React on Rails Pro + RSC', description: - 'If your current app needs more SSR throughput or RSC support, compare OSS and Pro before adding the Pro package.', + 'Start with the OSS vs Pro guide, then use the public RSC demos to judge where the added complexity pays for itself.', href: docsRoutes.ossVsPro, cta: 'Compare OSS and Pro', }, ]; -const exampleApps = [ +const catalogSections = [ { - title: 'react_on_rails_demo_ssr_hmr', + eyebrow: 'Starters', + title: 'Current starting points', description: - 'Canonical demo app showing React on Rails setup with SSR and hot reloading workflows.', - href: 'https://github.com/shakacode/react_on_rails_demo_ssr_hmr', + 'These are the best public repos to start from when you want a maintained reference instead of a historical artifact.', + items: [ + { + title: 'SSR + HMR tutorial demo', + repo: 'react-on-rails-demo-ssr-hmr', + description: + 'Maintained Rails + React + SSR + HMR tutorial repo. This is the reference behind the tutorial and Webpack customization guidance.', + href: 'https://github.com/shakacode/react-on-rails-demo-ssr-hmr', + tags: ['OSS', 'SSR', 'HMR'], + }, + { + title: 'React on Rails Pro + RSC starter', + repo: 'react-on-rails-rsc-demo', + description: + 'Minimal public sample for React Server Components with React on Rails Pro. Use this when you want the smallest current RSC starting point.', + href: 'https://github.com/shakacode/react-on-rails-rsc-demo', + tags: ['Pro', 'RSC', 'Starter'], + }, + ], }, { - title: 'react-rails-example-app', + eyebrow: 'Migrations', + title: 'Adoption and migration references', description: - 'Legacy react-rails app used to validate the migration guide and current Rails-version constraints.', - href: 'https://github.com/shakacode/react-rails-example-app', + 'Use these when your question is not “how do I start?” but “how do I move an existing app?”', + items: [ + { + title: 'react-rails migration example', + repo: 'react-on-rails-example-migration', + description: + 'Focused migration reference showing the shape of moving from react-rails into React on Rails.', + href: 'https://github.com/shakacode/react-on-rails-example-migration', + tags: ['OSS', 'Migration'], + }, + { + title: 'Open Flights migration example', + repo: 'react-on-rails-example-open-flights', + description: + 'Larger migration reference that shows React on Rails replacing react-rails in a more realistic app.', + href: 'https://github.com/shakacode/react-on-rails-example-open-flights', + tags: ['OSS', 'Migration', 'App'], + }, + ], }, { - title: 'vite_ruby/examples/rails', + eyebrow: 'React on Rails Pro', + title: 'RSC and performance demos', description: - 'Official Vite Rails sample app used to document migration preflight and dependency lockfile issues.', - href: 'https://github.com/ElMassimo/vite_ruby/tree/main/examples/rails', + 'These public demos use React on Rails Pro and React Server Components. Reach for them when the conversation is about measured user-visible wins.', + items: [ + { + title: 'Hacker News RSC demo', + repo: 'react-on-rails-demo-hacker-news-rsc', + description: + 'Compact public demo of React on Rails Pro + React Server Components on a familiar read-heavy UI.', + href: 'https://github.com/shakacode/react-on-rails-demo-hacker-news-rsc', + tags: ['Pro', 'RSC', 'Demo'], + }, + { + title: 'Marketplace RSC performance demo', + repo: 'react-on-rails-demo-marketplace-rsc', + description: + 'Public performance-oriented RSC demo showing the shape of the user-visible improvement on a marketplace-style surface.', + href: 'https://github.com/shakacode/react-on-rails-demo-marketplace-rsc', + tags: ['Pro', 'RSC', 'Performance'], + }, + { + title: 'Gumroad-style comparison demo', + repo: 'react-on-rails-demo-gumroad-rsc', + description: + 'Benchmark-oriented comparison between an Inertia-style surface and a React on Rails Pro + RSC surface on the same product domain. ShakaCode-built demo, not an official Gumroad integration.', + href: 'https://github.com/shakacode/react-on-rails-demo-gumroad-rsc', + tags: ['Pro', 'RSC', 'Benchmark'], + }, + ], + }, + { + eyebrow: 'Legacy', + title: 'Historical full-app reference', + description: + 'This repo is still useful when you want to see an older production-style app, but it is no longer the recommended starting point for new work.', + items: [ + { + title: 'react-webpack-rails-tutorial', + repo: 'react-webpack-rails-tutorial', + description: + 'Older full-app reference with a live demo at reactrails.com. Keep this for historical context rather than as the primary starter.', + href: 'https://github.com/shakacode/react-webpack-rails-tutorial', + tags: ['Legacy', 'Full App'], + }, + ], }, ]; export default function ExamplesPage(): ReactNode { return ( - +
-

Examples and migration references

-

Use concrete repos and concrete guides when deciding whether React on Rails fits.

+

Examples, demos, and migration references

+

Use the maintained public repos when you evaluate React on Rails.

- These links are meant for evaluation, migration, and validation work. They are not a - parallel docs track. + This catalog exists to make adoption easier: choose the path that matches your app, + use the current example repos, and ignore historical artifacts unless you are doing + archaeology.

-

Start with a decision path

-

Choose the guide that matches your migration or evaluation goal.

+

Start with the right path

+

Choose the guide that matches your evaluation or migration goal.

- {evaluationPaths.map((path) => ( + {decisionPaths.map((path) => (

{path.eyebrow}

{path.title}

@@ -87,21 +169,47 @@ export default function ExamplesPage(): ReactNode {
+ {catalogSections.map((section) => ( +
+
+

{section.eyebrow}

+

{section.title}

+

{section.description}

+
+
+ {section.items.map((item) => ( +
+

{item.title}

+

{item.repo}

+

{item.description}

+
+ {item.tags.map((tag) => ( + + {tag} + + ))} +
+ + Open repository + +
+ ))} +
+
+ ))} +
-

Reference repos

-

Open-source apps that map to the docs.

-
-
- {exampleApps.map((app) => ( -
-

{app.title}

-

{app.description}

- - Open repository - -
- ))} +

Source of truth

+

Use the docs for taxonomy and this page for curation.

+

+ The canonical docs page for repo taxonomy lives in{' '} + + Examples and migration references + + . This page is the marketing-forward catalog of the public repos we want people to + find first. +

diff --git a/scripts/docs-layout.mjs b/scripts/docs-layout.mjs index ec88c11..a0f729d 100644 --- a/scripts/docs-layout.mjs +++ b/scripts/docs-layout.mjs @@ -6,6 +6,7 @@ export const docsSubsetEntries = [ {kind: "oss", relativePath: "introduction.md"}, {kind: "oss", relativePath: "getting-started/quick-start.md"}, {kind: "oss", relativePath: "getting-started/tutorial.md"}, + {kind: "oss", relativePath: "getting-started/examples-and-references.md"}, {kind: "oss", relativePath: "getting-started/installation-into-an-existing-rails-app.md"}, {kind: "oss", relativePath: "core-concepts/how-react-on-rails-works.md"}, {kind: "oss", relativePath: "core-concepts/react-server-rendering.md"}, diff --git a/scripts/docs-layout.test.mjs b/scripts/docs-layout.test.mjs index 368e15f..ee67698 100644 --- a/scripts/docs-layout.test.mjs +++ b/scripts/docs-layout.test.mjs @@ -45,9 +45,13 @@ test("subsetPathsForLayout maps OSS docs differently by layout", () => { const consolidatedPaths = subsetPathsForLayout("consolidated"); assert.ok(splitPaths.includes("oss/introduction.md")); + assert.ok(splitPaths.includes("oss/getting-started/examples-and-references.md")); assert.ok(!splitPaths.includes("introduction.md")); + assert.ok(!splitPaths.includes("getting-started/examples-and-references.md")); assert.ok(consolidatedPaths.includes("introduction.md")); + assert.ok(consolidatedPaths.includes("getting-started/examples-and-references.md")); assert.ok(!consolidatedPaths.includes("oss/introduction.md")); + assert.ok(!consolidatedPaths.includes("oss/getting-started/examples-and-references.md")); assert.ok(splitPaths.includes("pro/react-on-rails-pro.md")); assert.ok(consolidatedPaths.includes("pro/react-on-rails-pro.md")); }); diff --git a/scripts/prepare-docs.mjs b/scripts/prepare-docs.mjs index 2e5bd8e..b24e5fb 100644 --- a/scripts/prepare-docs.mjs +++ b/scripts/prepare-docs.mjs @@ -687,10 +687,83 @@ ${legacyItems.join("\n")} },`; } +function subsetSidebarsContent() { + return `import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; + +const sidebars: SidebarsConfig = { + docsSidebar: [ + 'introduction', + { + type: 'category', + label: 'Getting Started', + link: {type: 'generated-index', title: 'Getting Started'}, + items: [ + 'getting-started/quick-start', + 'getting-started/tutorial', + 'getting-started/examples-and-references', + 'getting-started/installation-into-an-existing-rails-app', + ], + }, + { + type: 'category', + label: 'Core Concepts', + link: {type: 'generated-index', title: 'Core Concepts'}, + items: [ + 'core-concepts/how-react-on-rails-works', + 'core-concepts/react-server-rendering', + ], + }, + { + type: 'category', + label: 'Building Features', + link: {type: 'generated-index', title: 'Building Features'}, + items: ['building-features/react-and-redux'], + }, + { + type: 'category', + label: 'Deployment', + link: {type: 'generated-index', title: 'Deployment'}, + items: ['deployment/README'], + }, + { + type: 'category', + label: 'API Reference', + link: {type: 'generated-index', title: 'API Reference'}, + items: ['api-reference/view-helpers-api'], + }, + { + type: 'category', + label: 'Upgrading', + link: {type: 'generated-index', title: 'Upgrading'}, + items: ['upgrading/upgrading-react-on-rails'], + }, + { + type: 'category', + label: 'React on Rails Pro', + link: {type: 'generated-index', title: 'React on Rails Pro'}, + items: [ + 'pro/react-on-rails-pro', + 'pro/home-pro', + 'pro/react-server-components/tutorial', + ], + }, + ], +}; + +export default sidebars; +`; +} + async function prepareSidebars(siteRoot, hasArchive) { const upstreamSidebars = path.join(workspaceRoot, "content", "upstream", "sidebars.ts"); const targetSidebars = path.join(siteRoot, "sidebars.ts"); + if (useSubset) { + await fs.writeFile(targetSidebars, subsetSidebarsContent(), "utf8"); + console.log("Generated subset sidebars.ts"); + return; + } + if (await exists(upstreamSidebars)) { let content = await fs.readFile(upstreamSidebars, "utf8");