Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { Activity } from "react";
- Never annotate the result; the fetcher infers it. Put the shared contract on the feature's own `*Fetcher` type instead.
- `args` is required exactly when the route declares a body, params or a query.
- `captchaToken` for captcha-gated routes.
- `rawFetcher` only for generated Content Engine admin modules, which have no type to infer from. It is universal too, with the same server-only twin. A content type's *public* routes are typed: `module: "content/<publicApi.path>"`.
- `rawFetcher` only for generated Content Engine admin modules, which have no type to infer from. It is universal too, with the same server-only twin. A content type's _public_ routes are typed: `module: "content/<publicApi.path>"`.

### Caching APIs

Expand Down Expand Up @@ -102,7 +102,4 @@ npm i x
# Testing

- Write and run vitest unit tests for all new features and bug fixes - skip only if vitest isn't configured.
- Don't write tests:
- for trivial code unless they have complex logic or edge cases
- for tests where it uses a database or external API
- how UI should be rendered (use playwright for that to write e2e tests)
- Do not test trivial code, config, database models, third-party libraries or UI components.
11 changes: 8 additions & 3 deletions apps/web/content/docs/dev/routing/breadcrumbs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { useTranslations } from 'use-intl'
// [!code ++:7]
export const route = definePluginRoute({
breadcrumb: () => {
const t = useTranslations('@acme/site-notes')
const t = useTranslations('@acme/site-notes.home')

return t('title')
},
Expand Down Expand Up @@ -59,6 +59,7 @@ import {
definePluginRoute,
type PluginRoutePageProps,
} from '@vitnode/core/routing'
import { useTranslations } from 'use-intl'

interface Note {
content: string
Expand All @@ -75,8 +76,12 @@ export const route = definePluginRoute({
head: ({ loaderData, params }) => ({
title: loaderData?.title ?? params.slug,
}),
// [!code ++:1]
breadcrumb: ({ loaderData }) => loaderData.title,
// [!code ++:5]
breadcrumb: ({ loaderData }) => {
const t = useTranslations('@acme/site-notes.home')

return `${t('note')}: ${loaderData.title}`
},
})

const NotePage = ({ loaderData }: PluginRoutePageProps<Note>) => {
Expand Down
9 changes: 1 addition & 8 deletions apps/web/content/docs/dev/routing/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,5 @@
"title": "Routing",
"description": "Claim a URL, name the page, and let the router handle locales",
"icon": "Route",
"pages": [
"routes",
"navigation",
"metadata",
"breadcrumbs",
"loading",
"not-found"
]
"pages": ["routes", "navigation", "breadcrumbs", "loading", "not-found"]
}
19 changes: 13 additions & 6 deletions apps/web/content/docs/dev/routing/not-found.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,23 @@ When thrown, TanStack Router catches the signal and halts page execution, render

### Unmatched URLs keep the main shell

When a visitor navigates to a non-existent URL, `withCoreMainRoutes` catches the route **inside the main shell** (`_main.tsx`).
When a visitor navigates to a non-existent URL, the main shell (`_main.tsx`) is
still matched, so the route is caught **inside** it.

This ensures visitors never hit a blank, unstyled screen: they retain the main site header, navigation bar, and theme switcher, while search crawlers receive a real HTTP `404` status code:

```tsx title="apps/web/src/router.tsx"
const routeTree = withCoreMainRoutes(fileRouteTree, {
localeRouting,
mountUnder: mainShellRoute,
pageHead,
})
const routeTree = withVitNodeRoutes(
fileRouteTree,
pluginRouteSpecs(pluginRouteSources),
{
mountUnder: {
admin: adminShellRoute,
blank: fileRouteTree,
main: mainShellRoute,
},
},
)
```

{/* Image prompt: VitNode 404 error page displayed inside the main site layout with header, 404 heading, localized description, and "Go back" / "Back to home" action buttons in dark theme, 1440x900. */}
Expand Down
Loading
Loading