Skip to content

Commit b3dbc6d

Browse files
[docs] v5 changes docs: what's new, world upgrade guide, migration skills (#3100)
1 parent d012bf0 commit b3dbc6d

62 files changed

Lines changed: 1216 additions & 142 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ Linting, formatting, and typechecking (`pnpm lint`, `pnpm format`, `pnpm typeche
333333
When a PR adds or updates docs pages (anything under `docs/content/`), add a "Docs Preview" section to the PR description with direct links to each changed page on the `workflow-docs` preview deployment:
334334

335335
- Get the preview base URL from the `vercel[bot]` comment on the PR — use the Preview link from the `workflow-docs` project row (e.g. `https://workflow-docs-git-<branch-slug>.vercel.sh`). Don't construct the URL by hand; Vercel's branch-slug normalization is not a simple substitution.
336-
- Map content paths to routes: `docs/content/docs/v4/<path>.mdx` is served at `/docs/<path>` (v4 is the default/latest version) and `docs/content/docs/v5/<path>.mdx` at `/v5/docs/<path>`.
336+
- Map content paths to routes: `docs/content/docs/v5/<path>.mdx` is served at `/docs/<path>` (v5 is the default/latest version) and `docs/content/docs/v4/<path>.mdx` at `/v4/docs/<path>` (v4 is the maintenance version).
337337
- When a change is scoped to a specific section of a page, link to its heading anchor (e.g. `/docs/foundations/hooks#checking-for-token-conflicts`) and verify the anchor matches a real heading in the MDX.
338338
- A simple table with one row per page (and one column per docs version, when both v4 and v5 were updated) works well.
339339
- The preview deployment sits behind deployment protection, so the links require Vercel team access — that's expected; include them anyway for reviewers.

docs/app/[lang]/docs/layout.tsx renamed to docs/app/[lang]/docs/[[...slug]]/layout.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ import { DocsLayout } from '@/components/geistdocs/docs-layout';
22
import { getDocsTreeForVersion } from '@/lib/geistdocs/version-source';
33
import { LATEST_VERSION } from '@/lib/geistdocs/versions';
44

5-
const Layout = async ({ children, params }: LayoutProps<'/[lang]/docs'>) => {
6-
const { lang } = await params;
5+
// This layout lives inside `[[...slug]]` rather than next to it so that
6+
// `params.slug` is available: the sidebar needs the active page to decide
7+
// whether to drill into a section. See `DocsLayout`.
8+
const Layout = async ({
9+
children,
10+
params,
11+
}: LayoutProps<'/[lang]/docs/[[...slug]]'>) => {
12+
const { lang, slug } = await params;
713

814
return (
915
<div className="bg-background-200">
1016
<DocsLayout
17+
activeSlug={slug}
1118
currentVersion={LATEST_VERSION.id}
1219
lang={lang}
1320
tree={getDocsTreeForVersion(lang, LATEST_VERSION)}

docs/app/[lang]/v5/docs/layout.tsx renamed to docs/app/[lang]/v5/docs/[[...slug]]/layout.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ import { PreReleaseBanner } from '@/components/geistdocs/pre-release-banner';
33
import { getDocsTreeForVersion } from '@/lib/geistdocs/version-source';
44
import { PRE_RELEASE_VERSION } from '@/lib/geistdocs/versions';
55

6-
const Layout = async ({ children, params }: LayoutProps<'/[lang]/v5/docs'>) => {
7-
const { lang } = await params;
6+
// This layout lives inside `[[...slug]]` rather than next to it so that
7+
// `params.slug` is available: the sidebar needs the active page to decide
8+
// whether to drill into a section. See `DocsLayout`.
9+
const Layout = async ({
10+
children,
11+
params,
12+
}: LayoutProps<'/[lang]/v5/docs/[[...slug]]'>) => {
13+
const { lang, slug } = await params;
814
return (
915
<div className="bg-background-200">
1016
<PreReleaseBanner pathname={`/${lang}/v5/docs`} />
1117
<DocsLayout
18+
activeSlug={slug}
1219
currentVersion={PRE_RELEASE_VERSION.id}
1320
lang={lang}
1421
tree={getDocsTreeForVersion(lang, PRE_RELEASE_VERSION)}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { Metadata } from 'next';
22
import {
3-
BuildingAWorldPage,
4-
generateBuildingAWorldMetadata,
5-
} from '@/components/worlds/building-a-world-page';
3+
generateWorldsGuideMetadata,
4+
WorldsGuidePage,
5+
} from '@/components/worlds/worlds-guide-page';
66

77
export function generateMetadata(): Promise<Metadata> {
8-
return generateBuildingAWorldMetadata('v5');
8+
return generateWorldsGuideMetadata('building-a-world', 'v5');
99
}
1010

1111
export default function Page() {
12-
return <BuildingAWorldPage version="v5" />;
12+
return <WorldsGuidePage slug="building-a-world" version="v5" />;
1313
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { Metadata } from 'next';
2+
import {
3+
generateWorldsGuideMetadata,
4+
WorldsGuidePage,
5+
} from '@/components/worlds/worlds-guide-page';
6+
7+
export function generateMetadata(): Promise<Metadata> {
8+
return generateWorldsGuideMetadata('upgrading-to-v5', 'v5');
9+
}
10+
11+
export default function Page() {
12+
return <WorldsGuidePage slug="upgrading-to-v5" version="v5" />;
13+
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { Metadata } from 'next';
22
import {
3-
BuildingAWorldPage,
4-
generateBuildingAWorldMetadata,
5-
} from '@/components/worlds/building-a-world-page';
3+
generateWorldsGuideMetadata,
4+
WorldsGuidePage,
5+
} from '@/components/worlds/worlds-guide-page';
66

77
export function generateMetadata(): Promise<Metadata> {
8-
return generateBuildingAWorldMetadata('v4');
8+
return generateWorldsGuideMetadata('building-a-world', 'v4');
99
}
1010

1111
export default function Page() {
12-
return <BuildingAWorldPage version="v4" />;
12+
return <WorldsGuidePage slug="building-a-world" version="v4" />;
1313
}

‎docs/components/geistdocs/docs-layout.tsx‎

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,57 @@ const withFallbackFolderIndex = (nodes: DocsTreeNode[]): DocsTreeNode[] =>
8888
};
8989
});
9090

91+
// `/docs` permanently redirects here, so this is the page every bare link to
92+
// the documentation lands on.
93+
const DOCS_HOME_SECTION = 'getting-started';
94+
95+
/**
96+
* geistdocs' sidebar has two panes: the top-level menu, and a section pane it
97+
* drills into for the first root folder containing the active page. On the docs
98+
* home that drill-in is unhelpful — arriving from a `/docs` link would replace
99+
* the top-level menu with the framework list, hiding the rest of the docs.
100+
*
101+
* `findActiveRootSection` only matches folders that have children, so emptying
102+
* the section's children on its own landing page keeps the root menu visible
103+
* with the row highlighted as the current page. Nothing is lost: the page body
104+
* is a card grid of exactly those children, and every other page in the section
105+
* still drills in normally.
106+
*/
107+
const collapseDocsHomeSection = (
108+
tree: DocsTree,
109+
activeSlug?: string[]
110+
): DocsTree => {
111+
if (activeSlug?.join('/') !== DOCS_HOME_SECTION) {
112+
return tree;
113+
}
114+
115+
return {
116+
...tree,
117+
children: tree.children.map((node) =>
118+
node.type === 'folder' &&
119+
node.index?.url.endsWith(`/docs/${DOCS_HOME_SECTION}`)
120+
? { ...node, children: [] }
121+
: node
122+
),
123+
};
124+
};
125+
91126
const addSidebarBadgesToTree = (tree: DocsTree): DocsTree => ({
92127
...tree,
93128
children: addSidebarBadges(withFallbackFolderIndex(tree.children)),
94129
});
95130

96131
interface DocsLayoutProps {
132+
/** Slug of the active page, used to tune sidebar drill-in behavior. */
133+
activeSlug?: string[];
97134
children: ReactNode;
98135
currentVersion?: string;
99136
lang: string;
100137
tree: ComponentProps<typeof PackageDocsLayout>['tree'];
101138
}
102139

103140
export const DocsLayout = ({
141+
activeSlug,
104142
tree,
105143
currentVersion = config.versions?.current,
106144
lang,
@@ -123,7 +161,7 @@ export const DocsLayout = ({
123161
/>
124162
) : null
125163
}
126-
tree={addSidebarBadgesToTree(tree)}
164+
tree={collapseDocsHomeSection(addSidebarBadgesToTree(tree), activeSlug)}
127165
>
128166
{children}
129167
</PackageDocsLayout>

docs/components/worlds/building-a-world-page.tsx renamed to docs/components/worlds/worlds-guide-page.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import type { DocsVersionId } from '@/lib/geistdocs/versions';
1010
import { WorldDetailToc } from './WorldDetailToc';
1111
import { WorldVersionSelect } from './WorldVersionSelect';
1212

13-
const PAGE_SLUGS = ['building-a-world'];
14-
1513
const VERSION_SOURCES = {
1614
v4: worldsSource,
1715
v5: v5WorldsSource,
@@ -22,13 +20,19 @@ const VERSION_PREFIXES = {
2220
v5: '/v5',
2321
} as const;
2422

25-
export async function generateBuildingAWorldMetadata(
23+
/**
24+
* Standalone guide pages in the worlds tree — the ones that are not a world
25+
* detail page. They render outside the docs sidebar, so each is a bespoke
26+
* route passing its own slug.
27+
*/
28+
export async function generateWorldsGuideMetadata(
29+
slug: string,
2630
version: DocsVersionId
2731
): Promise<Metadata> {
28-
const page = VERSION_SOURCES[version].getPage(PAGE_SLUGS);
32+
const page = VERSION_SOURCES[version].getPage([slug]);
2933

3034
if (!page) {
31-
return { title: 'Building a World | Workflow SDK' };
35+
return { title: 'Worlds | Workflow SDK' };
3236
}
3337

3438
const versionPrefix = VERSION_PREFIXES[version];
@@ -41,9 +45,9 @@ export async function generateBuildingAWorldMetadata(
4145
images: ['/og/worlds'],
4246
},
4347
alternates: {
44-
canonical: '/worlds/building-a-world',
48+
canonical: `/worlds/${slug}`,
4549
types: {
46-
'text/markdown': `${versionPrefix}/worlds/building-a-world.md`,
50+
'text/markdown': `${versionPrefix}/worlds/${slug}.md`,
4751
},
4852
},
4953
...(isPreRelease
@@ -57,14 +61,16 @@ export async function generateBuildingAWorldMetadata(
5761
};
5862
}
5963

60-
export async function BuildingAWorldPage({
64+
export async function WorldsGuidePage({
65+
slug,
6166
version,
6267
}: {
68+
slug: string;
6369
version: DocsVersionId;
6470
}) {
6571
const source = VERSION_SOURCES[version];
6672
const versionPrefix = VERSION_PREFIXES[version];
67-
const page = source.getPage(PAGE_SLUGS);
73+
const page = source.getPage([slug]);
6874

6975
if (!page) {
7076
notFound();

‎docs/content/docs/v4/deploying.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ vercel deploy
5555
</Callout>
5656

5757
<Callout type="info">
58-
Starting with `workflow` version 5.0.0-beta.33, the Vercel World supports
58+
Starting with `workflow` version 5.0.0, the Vercel World supports
5959
**multi-region**: runs are pinned to the region that creates them, keeping
6060
workflow data, queuing, and streaming close to your users. See
6161
[Multi-region](/v5/worlds/vercel#multi-region).

0 commit comments

Comments
 (0)