@voltro/cli 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +229 -0
- package/THIRD-PARTY-NOTICES.md +8311 -3318
- package/dist/{apiBuild-CSFI8QGq.js → apiBuild-CaPfoWku.js} +11 -5
- package/dist/apiBuild-DHtLXYx9.js +2 -0
- package/dist/bin.js +1 -1
- package/dist/build-D-OnvNMf.js +843 -0
- package/dist/{checkCommand-COmqc2cB.js → checkCommand-C5elt0tW.js} +6 -6
- package/dist/{checkCommand-2SbqzukH.js → checkCommand-D2ZduVlh.js} +1 -1
- package/dist/codegen-BWpt3VgF.js +2 -0
- package/dist/{codegen-VF479Cnb.js → codegen-FEk8AZHb.js} +2 -2
- package/dist/{codegenCommand-DCdG2JN-.js → codegenCommand-BOiWQ5hz.js} +4 -4
- package/dist/{codemodRunner-r7J9lIa7.js → codemodRunner-BjtB2lq6.js} +109 -11
- package/dist/{commands-Cc_nV8WI.js → commands-DyxAmhP0.js} +30 -30
- package/dist/{dashboardCommand-C-gKvwqh.js → dashboardCommand-BdKTyT13.js} +5 -5
- package/dist/{dataCommand-BgpBHnlB.js → dataCommand-Bab9X7s8.js} +2 -2
- package/dist/{dbCommand-sHedr-NJ.js → dbCommand-06O2finM.js} +277 -236
- package/dist/dbCommand-B1EXBC6f.js +2 -0
- package/dist/{dev-CRHoCEiy.js → dev-C6LGF4iY.js} +3006 -2426
- package/dist/{dev--A3nsxA3.js → dev-GjJWAYo2.js} +1 -1
- package/dist/doctorCommand-B0hX0tdz.js +2 -0
- package/dist/{doctorCommand-DtfJ3FA6.js → doctorCommand-etMkflRc.js} +101 -69
- package/dist/{dormancyCommand-Drn7o0No.js → dormancyCommand-UwZ1AZzB.js} +1 -1
- package/dist/{embeddingsCommand-Z-jO1fWN.js → embeddingsCommand-C70zWHwo.js} +1 -1
- package/dist/{envCommand-D4gCrrTZ.js → envCommand-dSyKvRkM.js} +18 -18
- package/dist/{evolveCommand-CMROeKeA.js → evolveCommand-CG0_ebO5.js} +2 -2
- package/dist/fileConventions-DASGEmj-.js +35 -0
- package/dist/{fileTaxonomy-DvDUV9wq.js → fileTaxonomy-B7uxipWS.js} +55 -55
- package/dist/fontPipeline-LxIHa1vo.js +2 -0
- package/dist/fontPipeline-Tsh8kZfA.js +152 -0
- package/dist/frameworkTableAssembly-C_7Z-rMs.js +2 -0
- package/dist/{frameworkTableAssembly-w-XnLa3q.js → frameworkTableAssembly-DKx3ba3S.js} +5 -5
- package/dist/imagePipeline-B_GVJgm6.js +2 -0
- package/dist/imagePipeline-CBZmjT4i.js +127 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-DXM868o_.js → infoCommand-_53iOc_j.js} +1 -1
- package/dist/{inspect-CtL_xTbu.js → inspect-Bd8-9wsi.js} +1 -1
- package/dist/inspect-CuoDInfZ.js +2 -0
- package/dist/{inspectGateHint-BjnFubmH.js → inspectGateHint-4LxkNtrz.js} +1 -1
- package/dist/manifestBuild-C4-J1-m_.js +2 -0
- package/dist/{manifestBuild-CuU1VrSm.js → manifestBuild-Cqgsx2bM.js} +1 -1
- package/dist/{metaCommands-C6RFmF1r.js → metaCommands-Cn2oboG4.js} +8 -2
- package/dist/{migrate-D0F-eTlK.js → migrate-Cko9rswM.js} +2 -2
- package/dist/{pageConvention-CzUiSbtU.js → pageConvention-C938S8oC.js} +1 -1
- package/dist/{privacyCommand-DGdopOI6.js → privacyCommand-DWTQMC6R.js} +2 -2
- package/dist/{probeCommand-C9gazU0H.js → probeCommand-DkGGLknv.js} +83 -24
- package/dist/{renderModeScan-CcH2X1_D.js → renderModeScan-CUbOeOAg.js} +3 -1
- package/dist/{renderProfile-Ck32Fzxr.js → renderProfile-CskIgAfn.js} +2 -2
- package/dist/{runtimeTrace-BPQyCmC5.js → runtimeTrace-c0APJz7E.js} +1 -1
- package/dist/{sdkgen-Se88ifTd.js → sdkgen-BiQCgIEr.js} +1 -1
- package/dist/{serveCommand-DkP3OT0W.js → serveCommand-CueKQgzl.js} +869 -805
- package/dist/serveCommand-DsnrVN3U.js +2 -0
- package/dist/serveEntry.js +1 -1
- package/dist/start-BJzZLbt8.js +3 -0
- package/dist/start-ekPan8BT.js +1510 -0
- package/dist/startEntry.js +1 -1
- package/dist/{staticCommand-BwNEDlSU.js → staticCommand-xlSL-IWk.js} +1 -1
- package/dist/{test-f3amja6a.js → test-BWPQcRoB.js} +1 -1
- package/dist/updateCommand-Bqql_rsQ.js +2 -0
- package/dist/{updateCommand-BMk2e4ky.js → updateCommand-C_8I8Rzo.js} +139 -115
- package/dist/webDev-C7jWJ5dX.js +2 -0
- package/dist/{webDev-BgWL9gKV.js → webDev-oczpugbx.js} +1455 -922
- package/dist/{webhooksCommand-CoIO3jbj.js → webhooksCommand-4SVPDjKg.js} +1 -1
- package/package.json +60 -19
- package/templates/AGENTS.md +5 -3
- package/templates/agent-docs/_index.md +5 -3
- package/templates/agent-docs/_manifest.json +20 -4
- package/templates/agent-docs/ai.md +2 -2
- package/templates/agent-docs/authentication.md +1 -1
- package/templates/agent-docs/cli.md +2 -2
- package/templates/agent-docs/configuration.md +17 -0
- package/templates/agent-docs/data.md +470 -26
- package/templates/agent-docs/database/advancedqueries.md +7 -7
- package/templates/agent-docs/database/columntypes.md +2 -2
- package/templates/agent-docs/database/querying.md +1 -1
- package/templates/agent-docs/database/schema.md +1 -1
- package/templates/agent-docs/database/seedsdialects.md +1 -1
- package/templates/agent-docs/database/transactions.md +3 -3
- package/templates/agent-docs/deployment.md +8 -0
- package/templates/agent-docs/internationalization.md +2 -2
- package/templates/agent-docs/introduction.md +7 -1
- package/templates/agent-docs/local-first-mobile.md +102 -4
- package/templates/agent-docs/observability.md +2 -0
- package/templates/agent-docs/plugins/auth.md +1 -1
- package/templates/agent-docs/plugins/comments.md +142 -0
- package/templates/agent-docs/plugins/notifications.md +47 -4
- package/templates/agent-docs/plugins/presence.md +16 -3
- package/templates/agent-docs/plugins/prometheus.md +1 -1
- package/templates/agent-docs/plugins/queue.md +129 -0
- package/templates/agent-docs/plugins.md +11 -7
- package/templates/agent-docs/reference.md +16 -4
- package/templates/agent-docs/routing.md +527 -3
- package/templates/agent-docs/schema-driven-ui.md +214 -3
- package/templates/agent-docs/security.md +3 -3
- package/templates/agent-docs/whats-new.md +160 -66
- package/templates/apps/api-ai/package.json +6 -6
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +9 -9
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-row-history/package.json +8 -8
- package/templates/apps/api-saas/package.json +10 -10
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/app.config.ts +26 -2
- package/templates/apps/changelog/content/releases/{0.1.0.mdx → v0-1-0.mdx} +0 -1
- package/templates/apps/changelog/content/releases/{0.2.0.mdx → v0-2-0.mdx} +0 -1
- package/templates/apps/changelog/package.json +8 -8
- package/templates/apps/changelog/src/collections/releases.collection.ts +48 -0
- package/templates/apps/changelog/src/globals.d.ts +1 -1
- package/templates/apps/changelog/src/locales/de.ts +1 -1
- package/templates/apps/changelog/src/locales/en.ts +1 -1
- package/templates/apps/changelog/src/pages/[locale]/[slug]/page.tsx +7 -4
- package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +13 -41
- package/templates/apps/changelog/src/pages/[slug]/page.test.tsx +26 -51
- package/templates/apps/changelog/src/pages/[slug]/page.tsx +21 -19
- package/templates/apps/changelog/src/pages/page.test.tsx +14 -37
- package/templates/apps/changelog/src/pages/page.tsx +18 -12
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +9 -9
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +10 -10
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/content/docs/de/guides/first-page.md +4 -0
- package/templates/apps/frontend-docs/content/docs/de/intro/getting-started.md +4 -0
- package/templates/apps/frontend-docs/content/docs/en/guides/first-page.md +4 -0
- package/templates/apps/frontend-docs/content/docs/en/intro/getting-started.md +4 -0
- package/templates/apps/frontend-docs/package.json +8 -6
- package/templates/apps/frontend-docs/src/collections/docs.collection.ts +21 -0
- package/templates/apps/frontend-docs/src/locales/de.ts +0 -5
- package/templates/apps/frontend-docs/src/locales/en.ts +0 -5
- package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug]/page.tsx +17 -9
- package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +10 -5
- package/templates/apps/frontend-docs/src/pages/[locale]/page.tsx +8 -0
- package/templates/apps/frontend-docs/src/pages/docs/[...slug]/page.test.tsx +53 -15
- package/templates/apps/frontend-docs/src/pages/docs/[...slug]/page.tsx +27 -33
- package/templates/apps/frontend-docs/src/pages/page.test.tsx +17 -3
- package/templates/apps/frontend-docs/src/pages/page.tsx +16 -12
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +6 -6
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/content/posts/cms-to-ssg.md +12 -0
- package/templates/apps/frontend-static-blog/content/posts/hello-static.md +12 -0
- package/templates/apps/frontend-static-blog/content/posts/islands-not-hydration.md +14 -0
- package/templates/apps/frontend-static-blog/package.json +8 -6
- package/templates/apps/frontend-static-blog/src/collections/posts.collection.ts +27 -0
- package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug]/page.tsx +7 -4
- package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +7 -1
- package/templates/apps/frontend-static-blog/src/pages/blog/[slug]/page.test.tsx +19 -9
- package/templates/apps/frontend-static-blog/src/pages/blog/[slug]/page.tsx +19 -21
- package/templates/apps/frontend-static-blog/src/pages/page.test.tsx +18 -5
- package/templates/apps/frontend-static-blog/src/pages/page.tsx +21 -14
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/apiBuild-BYBpL7Pz.js +0 -2
- package/dist/build-CPgcMQug.js +0 -793
- package/dist/codegen-CctkDO-1.js +0 -2
- package/dist/dbCommand-DNb6yeOG.js +0 -2
- package/dist/doctorCommand-CqoWA2p5.js +0 -2
- package/dist/fileConventions-DOqD3lPS.js +0 -34
- package/dist/frameworkTableAssembly-C6ETawPR.js +0 -2
- package/dist/inspect-CuGDYES0.js +0 -2
- package/dist/manifestBuild-CPjhvM62.js +0 -2
- package/dist/serveCommand-DLc-BznW.js +0 -2
- package/dist/start-DfL3fOiN.js +0 -3
- package/dist/start-jw89Xbqy.js +0 -1339
- package/dist/updateCommand-5gFVfK5q.js +0 -2
- package/dist/webDev-CZbTsDcH.js +0 -2
- package/templates/apps/changelog/scripts/generate-rss.mjs +0 -38
- package/templates/apps/changelog/src/lib/releases.ts +0 -21
- package/templates/apps/frontend-static-blog/src/content/posts.ts +0 -64
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
// locale) and mirrored at `/de` by src/pages/[locale]/index.tsx. Pure static
|
|
3
3
|
// render with no client JS (`interactive: 'none'`).
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
5
|
+
// The list comes from the `releases` CONTENT COLLECTION: the loader runs at
|
|
6
|
+
// build time, decodes each entry's frontmatter against the schema, and
|
|
7
|
+
// filters drafts + future-dated entries (visibleReleases). The release list
|
|
8
|
+
// itself is CONTENT and is NOT translated — only the chrome comes from the
|
|
9
|
+
// catalogs. Entry links are locale-prefixed via `withLocalePrefix`.
|
|
10
10
|
|
|
11
11
|
import type { ReactNode } from 'react'
|
|
12
12
|
import type { PageMeta } from '@voltro/web'
|
|
13
|
+
import { useLoaderData } from '@voltro/web'
|
|
14
|
+
import { getCollection } from '@voltro/content'
|
|
13
15
|
import { T, useLocale } from '@voltro/i18n'
|
|
14
|
-
import { releases } from '../
|
|
16
|
+
import { releases, tagsOf, visibleReleases, type ReleaseData, type ReleaseEntry } from '../collections/releases.collection'
|
|
15
17
|
import { getCatalog, withLocalePrefix } from '../lib/locale'
|
|
16
18
|
|
|
17
19
|
export const renderMode = 'static' as const
|
|
@@ -25,9 +27,13 @@ export const meta = ({ locale }: { locale: string }): PageMeta => {
|
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
export const loader = async (): Promise<ReadonlyArray<ReleaseEntry>> =>
|
|
31
|
+
visibleReleases(await getCollection<ReleaseData>(releases.name))
|
|
32
|
+
|
|
28
33
|
export default function ChangelogIndex(): ReactNode {
|
|
34
|
+
const entries = useLoaderData<ReadonlyArray<ReleaseEntry>>()
|
|
29
35
|
const locale = useLocale()
|
|
30
|
-
if (
|
|
36
|
+
if (entries.length === 0) {
|
|
31
37
|
return (
|
|
32
38
|
<p>
|
|
33
39
|
<T id="empty.body" values={{ code: (chunks: ReactNode) => <code>{chunks}</code> }} />
|
|
@@ -36,18 +42,18 @@ export default function ChangelogIndex(): ReactNode {
|
|
|
36
42
|
}
|
|
37
43
|
return (
|
|
38
44
|
<div>
|
|
39
|
-
{
|
|
45
|
+
{entries.map((release) => (
|
|
40
46
|
<article key={release.slug} className="changelog-entry">
|
|
41
47
|
<p className="changelog-meta">
|
|
42
|
-
<time dateTime={release.releasedAt}>{release.releasedAt}</time> · v{release.version}
|
|
43
|
-
{release.
|
|
48
|
+
<time dateTime={release.data.releasedAt}>{release.data.releasedAt}</time> · v{release.data.version}
|
|
49
|
+
{tagsOf(release.data).map((tag) => (
|
|
44
50
|
<span key={tag} className="changelog-tag">{tag}</span>
|
|
45
51
|
))}
|
|
46
52
|
</p>
|
|
47
53
|
<h2>
|
|
48
|
-
<a href={withLocalePrefix(`/${release.slug}`, locale)}>{release.title}</a>
|
|
54
|
+
<a href={withLocalePrefix(`/${release.slug}`, locale)}>{release.data.title}</a>
|
|
49
55
|
</h2>
|
|
50
|
-
<p>{release.summary}</p>
|
|
56
|
+
<p>{release.data.summary}</p>
|
|
51
57
|
</article>
|
|
52
58
|
))}
|
|
53
59
|
</div>
|
|
@@ -12,18 +12,18 @@
|
|
|
12
12
|
"test": "voltro test"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@{{projectName}}/api": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/client": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/i18n": "0.
|
|
20
|
-
"@voltro/ui-shadcn": "0.
|
|
21
|
-
"@voltro/web": "0.
|
|
15
|
+
"@{{projectName}}/api": "0.53.0",
|
|
16
|
+
"@voltro/cli": "0.53.0",
|
|
17
|
+
"@voltro/client": "0.53.0",
|
|
18
|
+
"@voltro/env": "0.53.0",
|
|
19
|
+
"@voltro/i18n": "0.53.0",
|
|
20
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
21
|
+
"@voltro/web": "0.53.0",
|
|
22
22
|
"react": "^19.0.0",
|
|
23
23
|
"react-dom": "^19.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/devtools": "0.
|
|
26
|
+
"@voltro/devtools": "0.53.0",
|
|
27
27
|
"@types/react": "^19.0.0",
|
|
28
28
|
"@types/react-dom": "^19.0.0",
|
|
29
29
|
"jsdom": "^30.0.0",
|
|
@@ -12,19 +12,19 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@{{projectName}}/api": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/client": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/i18n": "0.
|
|
20
|
-
"@voltro/ui-shadcn": "0.
|
|
21
|
-
"@voltro/web": "0.
|
|
15
|
+
"@{{projectName}}/api": "0.53.0",
|
|
16
|
+
"@voltro/cli": "0.53.0",
|
|
17
|
+
"@voltro/client": "0.53.0",
|
|
18
|
+
"@voltro/env": "0.53.0",
|
|
19
|
+
"@voltro/i18n": "0.53.0",
|
|
20
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
21
|
+
"@voltro/web": "0.53.0",
|
|
22
22
|
"react": "^19.0.0",
|
|
23
23
|
"react-dom": "^19.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/devtools": "0.
|
|
27
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/devtools": "0.53.0",
|
|
27
|
+
"@voltro/testing": "0.53.0",
|
|
28
28
|
"@types/react": "^19.0.0",
|
|
29
29
|
"@types/react-dom": "^19.0.0",
|
|
30
30
|
"jsdom": "^30.0.0",
|
|
@@ -12,18 +12,18 @@
|
|
|
12
12
|
"test": "voltro test"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@{{projectName}}/api": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/client": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/i18n": "0.
|
|
20
|
-
"@voltro/ui-shadcn": "0.
|
|
21
|
-
"@voltro/web": "0.
|
|
15
|
+
"@{{projectName}}/api": "0.53.0",
|
|
16
|
+
"@voltro/cli": "0.53.0",
|
|
17
|
+
"@voltro/client": "0.53.0",
|
|
18
|
+
"@voltro/env": "0.53.0",
|
|
19
|
+
"@voltro/i18n": "0.53.0",
|
|
20
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
21
|
+
"@voltro/web": "0.53.0",
|
|
22
22
|
"react": "^19.0.0",
|
|
23
23
|
"react-dom": "^19.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/devtools": "0.
|
|
26
|
+
"@voltro/devtools": "0.53.0",
|
|
27
27
|
"@types/react": "^19.0.0",
|
|
28
28
|
"@types/react-dom": "^19.0.0",
|
|
29
29
|
"jsdom": "^30.0.0",
|
|
@@ -12,17 +12,17 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@voltro/cli": "0.
|
|
16
|
-
"@voltro/client": "0.
|
|
17
|
-
"@voltro/env": "0.
|
|
18
|
-
"@voltro/i18n": "0.
|
|
19
|
-
"@voltro/ui-shadcn": "0.
|
|
20
|
-
"@voltro/web": "0.
|
|
15
|
+
"@voltro/cli": "0.53.0",
|
|
16
|
+
"@voltro/client": "0.53.0",
|
|
17
|
+
"@voltro/env": "0.53.0",
|
|
18
|
+
"@voltro/i18n": "0.53.0",
|
|
19
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
20
|
+
"@voltro/web": "0.53.0",
|
|
21
21
|
"react": "^19.0.0",
|
|
22
22
|
"react-dom": "^19.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/devtools": "0.
|
|
25
|
+
"@voltro/devtools": "0.53.0",
|
|
26
26
|
"@types/react": "^19.0.0",
|
|
27
27
|
"@types/react-dom": "^19.0.0",
|
|
28
28
|
"jsdom": "^30.0.0",
|
|
@@ -12,19 +12,19 @@
|
|
|
12
12
|
"test": "voltro test"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@{{projectName}}/api": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/client": "0.
|
|
18
|
-
"@voltro/cms": "0.
|
|
19
|
-
"@voltro/env": "0.
|
|
20
|
-
"@voltro/i18n": "0.
|
|
21
|
-
"@voltro/ui-shadcn": "0.
|
|
22
|
-
"@voltro/web": "0.
|
|
15
|
+
"@{{projectName}}/api": "0.53.0",
|
|
16
|
+
"@voltro/cli": "0.53.0",
|
|
17
|
+
"@voltro/client": "0.53.0",
|
|
18
|
+
"@voltro/cms": "0.53.0",
|
|
19
|
+
"@voltro/env": "0.53.0",
|
|
20
|
+
"@voltro/i18n": "0.53.0",
|
|
21
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
22
|
+
"@voltro/web": "0.53.0",
|
|
23
23
|
"react": "^19.0.0",
|
|
24
24
|
"react-dom": "^19.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/devtools": "0.
|
|
27
|
+
"@voltro/devtools": "0.53.0",
|
|
28
28
|
"@types/react": "^19.0.0",
|
|
29
29
|
"@types/react-dom": "^19.0.0",
|
|
30
30
|
"jsdom": "^30.0.0",
|
|
@@ -12,20 +12,20 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@{{projectName}}/api": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/client": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/i18n": "0.
|
|
20
|
-
"@voltro/local-first": "0.
|
|
21
|
-
"@voltro/ui-shadcn": "0.
|
|
22
|
-
"@voltro/web": "0.
|
|
15
|
+
"@{{projectName}}/api": "0.53.0",
|
|
16
|
+
"@voltro/cli": "0.53.0",
|
|
17
|
+
"@voltro/client": "0.53.0",
|
|
18
|
+
"@voltro/env": "0.53.0",
|
|
19
|
+
"@voltro/i18n": "0.53.0",
|
|
20
|
+
"@voltro/local-first": "0.53.0",
|
|
21
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
22
|
+
"@voltro/web": "0.53.0",
|
|
23
23
|
"react": "^19.0.0",
|
|
24
24
|
"react-dom": "^19.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/devtools": "0.
|
|
28
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/devtools": "0.53.0",
|
|
28
|
+
"@voltro/testing": "0.53.0",
|
|
29
29
|
"@types/react": "^19.0.0",
|
|
30
30
|
"@types/react-dom": "^19.0.0",
|
|
31
31
|
"jsdom": "^30.0.0",
|
|
@@ -15,18 +15,18 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@effect/platform": "^0.97.0",
|
|
18
|
-
"@voltro/cli": "0.
|
|
19
|
-
"@voltro/client": "0.
|
|
20
|
-
"@voltro/env": "0.
|
|
21
|
-
"@voltro/i18n": "0.
|
|
22
|
-
"@voltro/serverless": "0.
|
|
23
|
-
"@voltro/web": "0.
|
|
18
|
+
"@voltro/cli": "0.53.0",
|
|
19
|
+
"@voltro/client": "0.53.0",
|
|
20
|
+
"@voltro/env": "0.53.0",
|
|
21
|
+
"@voltro/i18n": "0.53.0",
|
|
22
|
+
"@voltro/serverless": "0.53.0",
|
|
23
|
+
"@voltro/web": "0.53.0",
|
|
24
24
|
"effect": "^3.22.0",
|
|
25
25
|
"react": "^19.0.0",
|
|
26
26
|
"react-dom": "^19.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@voltro/devtools": "0.
|
|
29
|
+
"@voltro/devtools": "0.53.0",
|
|
30
30
|
"@types/react": "^19.0.0",
|
|
31
31
|
"@types/react-dom": "^19.0.0",
|
|
32
32
|
"jsdom": "^30.0.0",
|
|
@@ -12,17 +12,17 @@
|
|
|
12
12
|
"test": "voltro test"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@voltro/cli": "0.
|
|
16
|
-
"@voltro/client": "0.
|
|
17
|
-
"@voltro/env": "0.
|
|
18
|
-
"@voltro/i18n": "0.
|
|
19
|
-
"@voltro/ui-shadcn": "0.
|
|
20
|
-
"@voltro/web": "0.
|
|
15
|
+
"@voltro/cli": "0.53.0",
|
|
16
|
+
"@voltro/client": "0.53.0",
|
|
17
|
+
"@voltro/env": "0.53.0",
|
|
18
|
+
"@voltro/i18n": "0.53.0",
|
|
19
|
+
"@voltro/ui-shadcn": "0.53.0",
|
|
20
|
+
"@voltro/web": "0.53.0",
|
|
21
21
|
"react": "^19.0.0",
|
|
22
22
|
"react-dom": "^19.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/devtools": "0.
|
|
25
|
+
"@voltro/devtools": "0.53.0",
|
|
26
26
|
"@types/react": "^19.0.0",
|
|
27
27
|
"@types/react-dom": "^19.0.0",
|
|
28
28
|
"jsdom": "^30.0.0",
|
|
@@ -12,16 +12,18 @@
|
|
|
12
12
|
"test": "voltro test"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@voltro/
|
|
16
|
-
"
|
|
17
|
-
"@voltro/
|
|
18
|
-
"@voltro/
|
|
19
|
-
"@voltro/
|
|
15
|
+
"@voltro/content": "0.53.0",
|
|
16
|
+
"effect": "^3.22.0",
|
|
17
|
+
"@voltro/cli": "0.53.0",
|
|
18
|
+
"@voltro/client": "0.53.0",
|
|
19
|
+
"@voltro/env": "0.53.0",
|
|
20
|
+
"@voltro/i18n": "0.53.0",
|
|
21
|
+
"@voltro/web": "0.53.0",
|
|
20
22
|
"react": "^19.0.0",
|
|
21
23
|
"react-dom": "^19.0.0"
|
|
22
24
|
},
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"@voltro/devtools": "0.
|
|
26
|
+
"@voltro/devtools": "0.53.0",
|
|
25
27
|
"@types/react": "^19.0.0",
|
|
26
28
|
"@types/react-dom": "^19.0.0",
|
|
27
29
|
"jsdom": "^30.0.0",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The docs content collection — bilingual markdown under
|
|
2
|
+
// content/docs/{en,de}/**/*.md. The SLUG comes from the path below the
|
|
3
|
+
// locale segment (`en/intro/getting-started.md` → `intro/getting-started`),
|
|
4
|
+
// identical across locales, so the /de mirror serves the same slugs from the
|
|
5
|
+
// German tree. A missing translation falls back to the default locale's
|
|
6
|
+
// entry (marked `fallback: true`) instead of 404ing — incomplete
|
|
7
|
+
// translations are the normal case.
|
|
8
|
+
|
|
9
|
+
import { Schema } from 'effect'
|
|
10
|
+
import { defineCollection } from '@voltro/content'
|
|
11
|
+
|
|
12
|
+
export const docs = defineCollection({
|
|
13
|
+
name: 'docs',
|
|
14
|
+
directory: 'content/docs',
|
|
15
|
+
schema: Schema.Struct({
|
|
16
|
+
title: Schema.String,
|
|
17
|
+
}),
|
|
18
|
+
i18n: { locales: ['en', 'de'], defaultLocale: 'en', missing: 'fallback' },
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export type Doc = Schema.Schema.Type<typeof docs.schema>
|
|
@@ -10,11 +10,6 @@ export default defineLocale<typeof en>()({
|
|
|
10
10
|
|
|
11
11
|
'home.title': '{project} Dokumentation',
|
|
12
12
|
|
|
13
|
-
'docs.getting-started.title': 'Erste Schritte',
|
|
14
|
-
'docs.getting-started.body': 'Willkommen in der {{capProjectName}}-Dokumentation.',
|
|
15
|
-
'docs.first-page.title': 'Deine erste Seite',
|
|
16
|
-
'docs.first-page.body': 'Lege eine `*.tsx`-Datei in src/pages/ ab.',
|
|
17
|
-
|
|
18
13
|
'docs.notFound.title': 'Nicht gefunden',
|
|
19
14
|
'docs.notFound.body': 'Kein Dokument unter <code>{slug}</code>.',
|
|
20
15
|
|
|
@@ -14,11 +14,6 @@ export default defineCatalog({
|
|
|
14
14
|
// `{project}` is the scaffold-substituted app name, passed as a <T> value.
|
|
15
15
|
'home.title': '{project} docs',
|
|
16
16
|
|
|
17
|
-
'docs.getting-started.title': 'Getting started',
|
|
18
|
-
'docs.getting-started.body': 'Welcome to the {{capProjectName}} docs.',
|
|
19
|
-
'docs.first-page.title': 'Your first page',
|
|
20
|
-
'docs.first-page.body': 'Drop a `*.tsx` file into src/pages/.',
|
|
21
|
-
|
|
22
17
|
'docs.notFound.title': 'Not found',
|
|
23
18
|
'docs.notFound.body': 'No doc at <code>{slug}</code>.',
|
|
24
19
|
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
// Locale mirror of the catch-all docs route → renders `/de/docs/<slug>`.
|
|
2
|
-
// Re-exports the bare `[...slug]` page
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
2
|
+
// Re-exports the bare `[...slug]` page's component + meta; the LOADER here
|
|
3
|
+
// reads the URL locale's tree of the `docs` collection (with fallback to
|
|
4
|
+
// the default locale for untranslated entries). This is a DYNAMIC route
|
|
5
|
+
// mirrored under a DYNAMIC locale segment, so `getStaticPaths` emits the
|
|
6
|
+
// CROSS-PRODUCT of every non-default locale × every doc slug.
|
|
7
|
+
import { getCollection, getEntry, type ContentEntry } from '@voltro/content'
|
|
8
|
+
import { docs, type Doc } from '../../../../collections/docs.collection'
|
|
7
9
|
import { SUPPORTED_LOCALES, DEFAULT_LOCALE } from '../../../../lib/locale'
|
|
8
|
-
import { DOCS } from '../../../docs/[...slug]/page'
|
|
9
10
|
|
|
10
11
|
export { default } from '../../../docs/[...slug]/page'
|
|
11
12
|
export { renderMode, interactive, meta } from '../../../docs/[...slug]/page'
|
|
12
13
|
|
|
14
|
+
export const loader = async ({ params }: {
|
|
15
|
+
readonly params: { readonly slug: string; readonly locale: string }
|
|
16
|
+
}): Promise<ContentEntry<Doc> | null> =>
|
|
17
|
+
await getEntry<Doc>(docs.name, params.slug, { locale: params.locale })
|
|
18
|
+
|
|
13
19
|
export const getStaticPaths = async (): Promise<
|
|
14
20
|
Array<{ params: { locale: string; slug: string } }>
|
|
15
|
-
> =>
|
|
16
|
-
|
|
21
|
+
> => {
|
|
22
|
+
const entries = await getCollection(docs.name)
|
|
23
|
+
return SUPPORTED_LOCALES
|
|
17
24
|
.filter((l) => l !== DEFAULT_LOCALE)
|
|
18
|
-
.flatMap((locale) =>
|
|
25
|
+
.flatMap((locale) => entries.map((d) => ({ params: { locale, slug: d.slug } })))
|
|
26
|
+
}
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
// non-default locale × every doc slug.
|
|
9
9
|
|
|
10
10
|
import { describe, expect, test, vi } from 'vitest'
|
|
11
|
+
import { dirname, join } from 'node:path'
|
|
12
|
+
import { fileURLToPath } from 'node:url'
|
|
13
|
+
import { setContentRoot } from '@voltro/content'
|
|
14
|
+
|
|
15
|
+
setContentRoot(join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..'))
|
|
11
16
|
|
|
12
17
|
// The mirrors transitively import the base pages, which import @voltro/i18n
|
|
13
18
|
// and @voltro/web. Stub both so importing the modules doesn't require the
|
|
@@ -50,17 +55,17 @@ describe('home mirror — getStaticPaths', () => {
|
|
|
50
55
|
describe('docs [...slug] mirror — getStaticPaths (locale × slug cross-product)', () => {
|
|
51
56
|
test('emits every non-default locale paired with every doc slug', async () => {
|
|
52
57
|
const paths = await slugMirror.getStaticPaths()
|
|
58
|
+
// getCollection sorts by slug.
|
|
53
59
|
expect(paths).toEqual([
|
|
54
|
-
{ params: { locale: 'de', slug: 'intro/getting-started' } },
|
|
55
60
|
{ params: { locale: 'de', slug: 'guides/first-page' } },
|
|
61
|
+
{ params: { locale: 'de', slug: 'intro/getting-started' } },
|
|
56
62
|
])
|
|
57
63
|
})
|
|
58
64
|
|
|
59
|
-
test('re-exports the base page component + its per-locale meta function', () => {
|
|
65
|
+
test('re-exports the base page component + its per-locale meta function', async () => {
|
|
60
66
|
expect(typeof slugMirror.default).toBe('function')
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
).toBe('Deine erste Seite')
|
|
67
|
+
const deDoc = await slugMirror.loader({ params: { slug: 'guides/first-page', locale: 'de' } })
|
|
68
|
+
expect(slugMirror.meta({ locale: 'de', loaderData: deDoc }).title).toBe('Deine erste Seite')
|
|
64
69
|
expect(slugMirror.renderMode).toBe('static')
|
|
65
70
|
expect(slugMirror.interactive).toBe('none')
|
|
66
71
|
})
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
// (the component reads its locale from the URL via the layout's provider);
|
|
3
3
|
// `getStaticPaths` tells `voltro build` which locale-prefixed paths to emit.
|
|
4
4
|
// The default locale is NOT listed here — it lives at the bare `/`.
|
|
5
|
+
import { getCollection, type ContentEntry } from '@voltro/content'
|
|
6
|
+
import { docs, type Doc } from '../../collections/docs.collection'
|
|
5
7
|
import { SUPPORTED_LOCALES, DEFAULT_LOCALE } from '../../lib/locale'
|
|
6
8
|
|
|
7
9
|
export { default } from '../page'
|
|
8
10
|
export { renderMode, interactive, meta } from '../page'
|
|
9
11
|
|
|
12
|
+
// The URL locale selects the collection tree (German titles on /de).
|
|
13
|
+
export const loader = async ({ params }: {
|
|
14
|
+
readonly params: { readonly locale: string }
|
|
15
|
+
}): Promise<ReadonlyArray<ContentEntry<Doc>>> =>
|
|
16
|
+
await getCollection<Doc>(docs.name, { locale: params.locale })
|
|
17
|
+
|
|
10
18
|
export const getStaticPaths = async (): Promise<Array<{ params: { locale: string } }>> =>
|
|
11
19
|
SUPPORTED_LOCALES
|
|
12
20
|
.filter((l) => l !== DEFAULT_LOCALE)
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
2
|
//
|
|
3
3
|
// `/docs/[...slug]` catch-all — its `getStaticPaths` export (enumerates the
|
|
4
|
-
// pre-rendered doc slugs
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// pre-rendered doc slugs from the `docs` CONTENT COLLECTION), the loader
|
|
5
|
+
// (locale-tree selection + fallback), the per-doc meta, and the page render
|
|
6
|
+
// for a matched vs. unknown slug. The collection reads this app's REAL
|
|
7
|
+
// content/docs/{en,de}/**/*.md files — no fixture copies to drift.
|
|
8
8
|
|
|
9
9
|
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
|
|
10
10
|
import { act, createElement, type ReactNode } from 'react'
|
|
11
11
|
import { createRoot, type Root } from 'react-dom/client'
|
|
12
|
+
import { dirname, join } from 'node:path'
|
|
13
|
+
import { fileURLToPath } from 'node:url'
|
|
14
|
+
import { setContentRoot, type ContentEntry } from '@voltro/content'
|
|
15
|
+
import type { Doc } from '../../../collections/docs.collection'
|
|
12
16
|
import en from '../../../locales/en'
|
|
13
17
|
import de from '../../../locales/de'
|
|
14
18
|
|
|
19
|
+
// The server half of the collection reads files under the app root.
|
|
20
|
+
setContentRoot(join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..'))
|
|
21
|
+
|
|
15
22
|
const params = vi.fn<() => Record<string, string>>()
|
|
16
|
-
vi.
|
|
23
|
+
const loaderData = vi.fn<() => ContentEntry<Doc> | null>()
|
|
24
|
+
vi.mock('@voltro/web', () => ({
|
|
25
|
+
useParams: () => params(),
|
|
26
|
+
useLoaderData: () => loaderData(),
|
|
27
|
+
}))
|
|
17
28
|
|
|
18
29
|
const catalogs: Record<string, Record<string, string>> = { en, de }
|
|
19
30
|
let currentLocale = 'en'
|
|
@@ -37,7 +48,7 @@ vi.mock('@voltro/i18n', () => ({
|
|
|
37
48
|
fill(catalogs[currentLocale]?.[id] ?? id, values),
|
|
38
49
|
}))
|
|
39
50
|
|
|
40
|
-
const { default: DocPage, getStaticPaths, meta, renderMode, interactive } = await import('./page')
|
|
51
|
+
const { default: DocPage, getStaticPaths, loader, meta, renderMode, interactive } = await import('./page')
|
|
41
52
|
|
|
42
53
|
;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
|
|
43
54
|
|
|
@@ -53,7 +64,10 @@ const render = (node: ReactNode): void => {
|
|
|
53
64
|
})
|
|
54
65
|
}
|
|
55
66
|
|
|
56
|
-
beforeEach(() =>
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
params.mockReset()
|
|
69
|
+
loaderData.mockReset()
|
|
70
|
+
})
|
|
57
71
|
|
|
58
72
|
afterEach(() => {
|
|
59
73
|
currentLocale = 'en'
|
|
@@ -70,36 +84,59 @@ describe('docs [...slug] — config + getStaticPaths', () => {
|
|
|
70
84
|
|
|
71
85
|
test('enumerates every doc slug as a single `/`-joined string', async () => {
|
|
72
86
|
const paths = await getStaticPaths()
|
|
87
|
+
// getCollection sorts by slug.
|
|
73
88
|
expect(paths.map((p) => p.params.slug)).toEqual([
|
|
74
|
-
'intro/getting-started',
|
|
75
89
|
'guides/first-page',
|
|
90
|
+
'intro/getting-started',
|
|
76
91
|
])
|
|
77
92
|
})
|
|
78
93
|
})
|
|
79
94
|
|
|
95
|
+
describe('docs [...slug] — loader (collection + locale trees)', () => {
|
|
96
|
+
test('loads the default-locale entry with rendered html', async () => {
|
|
97
|
+
const doc = await loader({ params: { slug: 'guides/first-page' } })
|
|
98
|
+
expect(doc?.data.title).toBe('Your first page')
|
|
99
|
+
expect(doc?.html).toContain('<code>*.tsx</code>')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('loads the German tree when a locale is passed', async () => {
|
|
103
|
+
const doc = await loader({ params: { slug: 'guides/first-page' }, locale: 'de' })
|
|
104
|
+
expect(doc?.data.title).toBe('Deine erste Seite')
|
|
105
|
+
expect(doc?.html).toContain('Lege eine')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
test('returns null for an unknown slug', async () => {
|
|
109
|
+
expect(await loader({ params: { slug: 'does/not-exist' } })).toBeNull()
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
80
113
|
describe('docs [...slug] — localized meta', () => {
|
|
81
|
-
test('reads the per-doc title from the
|
|
82
|
-
|
|
83
|
-
|
|
114
|
+
test('reads the per-doc title from the entry frontmatter, per locale', async () => {
|
|
115
|
+
const enDoc = await loader({ params: { slug: 'guides/first-page' } })
|
|
116
|
+
const deDoc = await loader({ params: { slug: 'guides/first-page' }, locale: 'de' })
|
|
117
|
+
expect(meta({ locale: 'en', loaderData: enDoc }).title).toBe('Your first page')
|
|
118
|
+
expect(meta({ locale: 'de', loaderData: deDoc }).title).toBe('Deine erste Seite')
|
|
84
119
|
})
|
|
85
120
|
|
|
86
121
|
test('falls back to the not-found title for an unknown slug', () => {
|
|
87
|
-
expect(meta({ locale: 'en',
|
|
122
|
+
expect(meta({ locale: 'en', loaderData: null }).title).toBe('Not found')
|
|
88
123
|
})
|
|
89
124
|
})
|
|
90
125
|
|
|
91
|
-
describe('docs [...slug] —
|
|
92
|
-
test('renders the matched doc title + body (English) for a known slug', () => {
|
|
126
|
+
describe('docs [...slug] — render', () => {
|
|
127
|
+
test('renders the matched doc title + body (English) for a known slug', async () => {
|
|
93
128
|
currentLocale = 'en'
|
|
94
129
|
params.mockReturnValue({ slug: 'guides/first-page' })
|
|
130
|
+
loaderData.mockReturnValue(await loader({ params: { slug: 'guides/first-page' } }))
|
|
95
131
|
render(createElement(DocPage))
|
|
96
132
|
expect(container.querySelector('h1')?.textContent).toBe('Your first page')
|
|
97
133
|
expect(container.textContent).toContain('Drop a')
|
|
98
134
|
})
|
|
99
135
|
|
|
100
|
-
test('renders the matched doc title + body (German) for a known slug', () => {
|
|
136
|
+
test('renders the matched doc title + body (German) for a known slug', async () => {
|
|
101
137
|
currentLocale = 'de'
|
|
102
138
|
params.mockReturnValue({ slug: 'guides/first-page' })
|
|
139
|
+
loaderData.mockReturnValue(await loader({ params: { slug: 'guides/first-page' }, locale: 'de' }))
|
|
103
140
|
render(createElement(DocPage))
|
|
104
141
|
expect(container.querySelector('h1')?.textContent).toBe('Deine erste Seite')
|
|
105
142
|
expect(container.textContent).toContain('Lege eine')
|
|
@@ -108,6 +145,7 @@ describe('docs [...slug] — localized render', () => {
|
|
|
108
145
|
test('renders the localized not-found fallback for an unknown slug', () => {
|
|
109
146
|
currentLocale = 'en'
|
|
110
147
|
params.mockReturnValue({ slug: 'does/not-exist' })
|
|
148
|
+
loaderData.mockReturnValue(null)
|
|
111
149
|
render(createElement(DocPage))
|
|
112
150
|
expect(container.querySelector('h1')?.textContent).toBe('Not found')
|
|
113
151
|
expect(container.textContent).toContain('does/not-exist')
|