toiljs 0.0.11 → 0.0.12
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/README.md +2 -0
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/configure.js +10 -4
- package/build/cli/create.js +58 -30
- package/build/cli/diagnostics.d.ts +55 -0
- package/build/cli/diagnostics.js +333 -0
- package/build/cli/doctor.d.ts +6 -0
- package/build/cli/doctor.js +249 -0
- package/build/cli/index.js +26 -0
- package/build/cli/proc.d.ts +5 -0
- package/build/cli/proc.js +20 -0
- package/build/cli/ui.d.ts +1 -0
- package/build/cli/ui.js +1 -0
- package/build/cli/update.d.ts +7 -0
- package/build/cli/update.js +117 -0
- package/build/cli/updates.d.ts +10 -0
- package/build/cli/updates.js +45 -0
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/dev/error-overlay.js +1 -1
- package/build/client/head/metadata.js +3 -1
- package/build/client/index.d.ts +5 -1
- package/build/client/index.js +2 -0
- package/build/client/navigation/navigation.js +1 -1
- package/build/client/routing/Router.js +2 -2
- package/build/client/search/search.d.ts +26 -0
- package/build/client/search/search.js +101 -0
- package/build/client/search/use-page-search.d.ts +8 -0
- package/build/client/search/use-page-search.js +21 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/generate.js +26 -23
- package/build/compiler/index.d.ts +2 -0
- package/build/compiler/index.js +1 -0
- package/build/compiler/pages.d.ts +8 -0
- package/build/compiler/pages.js +37 -0
- package/build/compiler/plugin.js +3 -1
- package/build/compiler/prerender.d.ts +1 -0
- package/build/compiler/prerender.js +11 -5
- package/build/compiler/seo.js +10 -3
- package/build/io/.tsbuildinfo +1 -1
- package/examples/basic/client/components/Header.tsx +43 -41
- package/examples/basic/client/components/HoneycombBackground.tsx +223 -230
- package/examples/basic/client/public/index.html +18 -16
- package/examples/basic/client/routes/(legal)/privacy.tsx +18 -19
- package/examples/basic/client/routes/(legal)/terms.tsx +15 -16
- package/examples/basic/client/routes/about.tsx +21 -22
- package/examples/basic/client/routes/blog/[id].tsx +26 -18
- package/examples/basic/client/routes/features/actions.tsx +67 -67
- package/examples/basic/client/routes/features/error/index.tsx +27 -27
- package/examples/basic/client/routes/features/head.tsx +38 -38
- package/examples/basic/client/routes/features/index.tsx +83 -75
- package/examples/basic/client/routes/features/realtime.tsx +34 -32
- package/examples/basic/client/routes/features/script.tsx +31 -31
- package/examples/basic/client/routes/features/seo.tsx +39 -39
- package/examples/basic/client/routes/features/template/index.tsx +20 -20
- package/examples/basic/client/routes/features/template/template.tsx +16 -18
- package/examples/basic/client/routes/gallery/@modal/(.)photo/[id].tsx +23 -23
- package/examples/basic/client/routes/gallery/index.tsx +42 -42
- package/examples/basic/client/routes/gallery/photo/[id].tsx +18 -18
- package/examples/basic/client/routes/get-started.tsx +157 -84
- package/examples/basic/client/routes/index.tsx +137 -96
- package/examples/basic/client/routes/loader-demo/index.tsx +59 -52
- package/examples/basic/client/routes/search.tsx +61 -0
- package/examples/basic/client/routes/test.tsx +7 -8
- package/examples/basic/client/styles/main.css +624 -552
- package/package.json +2 -2
- package/presets/eslint.js +10 -3
- package/src/cli/configure.ts +363 -353
- package/src/cli/create.ts +563 -530
- package/src/cli/diagnostics.ts +421 -0
- package/src/cli/doctor.ts +318 -0
- package/src/cli/features.ts +166 -160
- package/src/cli/index.ts +242 -211
- package/src/cli/proc.ts +30 -0
- package/src/cli/ui.ts +111 -103
- package/src/cli/update.ts +150 -0
- package/src/cli/updates.ts +69 -0
- package/src/client/components/Image.tsx +91 -89
- package/src/client/dev/error-overlay.tsx +193 -197
- package/src/client/head/metadata.ts +94 -92
- package/src/client/index.ts +79 -64
- package/src/client/navigation/Link.tsx +94 -100
- package/src/client/navigation/navigation.ts +215 -218
- package/src/client/routing/Router.tsx +210 -193
- package/src/client/routing/hooks.ts +110 -114
- package/src/client/routing/lazy.ts +77 -81
- package/src/client/search/search.ts +189 -0
- package/src/client/search/use-page-search.ts +73 -0
- package/src/compiler/config.ts +173 -171
- package/src/compiler/fonts.ts +89 -87
- package/src/compiler/generate.ts +378 -373
- package/src/compiler/image-report.ts +88 -85
- package/src/compiler/index.ts +2 -0
- package/src/compiler/pages.ts +70 -0
- package/src/compiler/plugin.ts +51 -47
- package/src/compiler/prerender.ts +152 -130
- package/src/compiler/routes.ts +132 -131
- package/src/compiler/seo.ts +381 -356
- package/src/compiler/vite.ts +155 -145
- package/src/io/FastSet.ts +99 -96
- package/test/configure.test.ts +94 -90
- package/test/doctor.test.ts +140 -0
- package/test/dom/Image.test.tsx +73 -46
- package/test/dom/Script.test.tsx +48 -45
- package/test/dom/action.test.tsx +146 -129
- package/test/dom/error-overlay.test.tsx +44 -44
- package/test/dom/loader.test.tsx +2 -2
- package/test/dom/revalidate.test.tsx +1 -1
- package/test/dom/route-head.test.tsx +1 -2
- package/test/dom/slot.test.tsx +131 -109
- package/test/dom/view-transitions.test.tsx +53 -51
- package/test/features.test.ts +149 -142
- package/test/fonts.test.ts +28 -26
- package/test/head.test.ts +45 -35
- package/test/metadata.test.ts +42 -41
- package/test/pages.test.ts +105 -0
- package/test/prerender.test.ts +54 -46
- package/test/search.test.ts +114 -0
- package/test/seo.test.ts +164 -142
- package/test/update.test.ts +44 -0
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
// Route metadata: the declarative way to set this page's <title>, description, OpenGraph, and more.
|
|
2
|
-
// The router applies it before paint and the build bakes it into static HTML for crawlers.
|
|
3
|
-
//
|
|
4
|
-
// This route sets its OWN `titleTemplate: '%s'`, which overrides the layout's "%s | ToilJS" template,
|
|
5
|
-
// so the tab reads exactly "useReducer | React Hooks" with no site suffix. Drop the titleTemplate
|
|
6
|
-
// line and the same title renders as "useReducer | React Hooks | ToilJS".
|
|
7
|
-
export const metadata: Toil.Metadata = {
|
|
8
|
-
title: 'useReducer | React Hooks',
|
|
9
|
-
titleTemplate: '%s',
|
|
10
|
-
description: 'Manage complex state transitions with a reducer function using the useReducer hook.',
|
|
11
|
-
keywords: ['react', 'hooks', 'useReducer', 'state'],
|
|
12
|
-
canonical: 'https://toil.example/features/seo',
|
|
13
|
-
openGraph: {
|
|
14
|
-
title: 'useReducer | React Hooks',
|
|
15
|
-
description: 'Manage complex state transitions with a reducer.',
|
|
16
|
-
type: 'website'
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export default function SeoDemo() {
|
|
21
|
-
return (
|
|
22
|
-
<main>
|
|
23
|
-
<h1>Route metadata</h1>
|
|
24
|
-
<p>
|
|
25
|
-
The browser tab now reads <strong>useReducer | React Hooks</strong>, set entirely by
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</p>
|
|
29
|
-
<p>
|
|
30
|
-
It also emitted <code><meta name="description"></code>, keywords, a canonical
|
|
31
|
-
|
|
32
|
-
</p>
|
|
33
|
-
<p>
|
|
34
|
-
<Toil.Link href="/features/head">Prefer the imperative API?</Toil.Link>{' '}
|
|
35
|
-
<Toil.Link href="/features">Back to features</Toil.Link>
|
|
36
|
-
</p>
|
|
37
|
-
</main>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
1
|
+
// Route metadata: the declarative way to set this page's <title>, description, OpenGraph, and more.
|
|
2
|
+
// The router applies it before paint and the build bakes it into static HTML for crawlers.
|
|
3
|
+
//
|
|
4
|
+
// This route sets its OWN `titleTemplate: '%s'`, which overrides the layout's "%s | ToilJS" template,
|
|
5
|
+
// so the tab reads exactly "useReducer | React Hooks" with no site suffix. Drop the titleTemplate
|
|
6
|
+
// line and the same title renders as "useReducer | React Hooks | ToilJS".
|
|
7
|
+
export const metadata: Toil.Metadata = {
|
|
8
|
+
title: 'useReducer | React Hooks',
|
|
9
|
+
titleTemplate: '%s',
|
|
10
|
+
description: 'Manage complex state transitions with a reducer function using the useReducer hook.',
|
|
11
|
+
keywords: ['react', 'hooks', 'useReducer', 'state'],
|
|
12
|
+
canonical: 'https://toil.example/features/seo',
|
|
13
|
+
openGraph: {
|
|
14
|
+
title: 'useReducer | React Hooks',
|
|
15
|
+
description: 'Manage complex state transitions with a reducer.',
|
|
16
|
+
type: 'website'
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default function SeoDemo() {
|
|
21
|
+
return (
|
|
22
|
+
<main>
|
|
23
|
+
<h1>Route metadata</h1>
|
|
24
|
+
<p>
|
|
25
|
+
The browser tab now reads <strong>useReducer | React Hooks</strong>, set entirely by the{' '}
|
|
26
|
+
<code>metadata</code> export in <code>client/routes/features/seo.tsx</code>, with no{' '}
|
|
27
|
+
<code>useEffect</code> and no title suffix.
|
|
28
|
+
</p>
|
|
29
|
+
<p>
|
|
30
|
+
It also emitted <code><meta name="description"></code>, keywords, a canonical link, and the{' '}
|
|
31
|
+
<code>og:*</code> tags, all from that one object.
|
|
32
|
+
</p>
|
|
33
|
+
<p>
|
|
34
|
+
<Toil.Link href="/features/head">Prefer the imperative API?</Toil.Link>{' '}
|
|
35
|
+
<Toil.Link href="/features">Back to features</Toil.Link>
|
|
36
|
+
</p>
|
|
37
|
+
</main>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
export const metadata: Toil.Metadata = { title: 'Templates' };
|
|
2
|
-
|
|
3
|
-
export default function TemplateDemo() {
|
|
4
|
-
return (
|
|
5
|
-
<main>
|
|
6
|
-
<h1>Templates</h1>
|
|
7
|
-
<p>
|
|
8
|
-
The line above is rendered by <code>template.tsx</code>. Bounce between these two links
|
|
9
|
-
|
|
10
|
-
</p>
|
|
11
|
-
<p>
|
|
12
|
-
<Toil.Link href="/features/template">This page</Toil.Link>{' '}
|
|
13
|
-
<Toil.Link href="/features/template/b">Sibling page</Toil.Link>
|
|
14
|
-
</p>
|
|
15
|
-
<p>
|
|
16
|
-
<Toil.Link href="/features">Back to features</Toil.Link>
|
|
17
|
-
</p>
|
|
18
|
-
</main>
|
|
19
|
-
);
|
|
20
|
-
}
|
|
1
|
+
export const metadata: Toil.Metadata = { title: 'Templates' };
|
|
2
|
+
|
|
3
|
+
export default function TemplateDemo() {
|
|
4
|
+
return (
|
|
5
|
+
<main>
|
|
6
|
+
<h1>Templates</h1>
|
|
7
|
+
<p>
|
|
8
|
+
The line above is rendered by <code>template.tsx</code>. Bounce between these two links and watch the
|
|
9
|
+
mount number climb, the template remounts on every navigation.
|
|
10
|
+
</p>
|
|
11
|
+
<p>
|
|
12
|
+
<Toil.Link href="/features/template">This page</Toil.Link>{' '}
|
|
13
|
+
<Toil.Link href="/features/template/b">Sibling page</Toil.Link>
|
|
14
|
+
</p>
|
|
15
|
+
<p>
|
|
16
|
+
<Toil.Link href="/features">Back to features</Toil.Link>
|
|
17
|
+
</p>
|
|
18
|
+
</main>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { useState, type ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
// A template wraps a segment like a layout, but RE-MOUNTS on every navigation within it (a layout
|
|
4
|
-
// persists). This counter increments each time the template mounts, so navigating between the two
|
|
5
|
-
// child links below bumps it, proving the remount. Swap this file for `layout.tsx` and the number
|
|
6
|
-
// would hold steady instead.
|
|
7
|
-
let mounts = 0;
|
|
8
|
-
export default function PlaygroundTemplate({ children }: { children?: ReactNode }) {
|
|
9
|
-
const [mountId] = useState(() => ++mounts);
|
|
10
|
-
return (
|
|
11
|
-
<div>
|
|
12
|
-
<p style={{ opacity: 0.6 }}>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
);
|
|
18
|
-
}
|
|
1
|
+
import { useState, type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
// A template wraps a segment like a layout, but RE-MOUNTS on every navigation within it (a layout
|
|
4
|
+
// persists). This counter increments each time the template mounts, so navigating between the two
|
|
5
|
+
// child links below bumps it, proving the remount. Swap this file for `layout.tsx` and the number
|
|
6
|
+
// would hold steady instead.
|
|
7
|
+
let mounts = 0;
|
|
8
|
+
export default function PlaygroundTemplate({ children }: { children?: ReactNode }) {
|
|
9
|
+
const [mountId] = useState(() => ++mounts);
|
|
10
|
+
return (
|
|
11
|
+
<div>
|
|
12
|
+
<p style={{ opacity: 0.6 }}>template mount #{mountId} (it increments on every navigation here)</p>
|
|
13
|
+
{children}
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
// Intercepting route: `(.)photo/[id]` inside the `@modal` slot catches a soft navigation to
|
|
2
|
-
// /gallery/photo/:id and renders here instead, as an overlay, while the gallery stays mounted behind
|
|
3
|
-
// it. On a hard reload the interception does not apply and the full photo/[id].tsx page renders.
|
|
4
|
-
export default function PhotoModal() {
|
|
5
|
-
const { id } = Toil.useParams();
|
|
6
|
-
return (
|
|
7
|
-
<div
|
|
8
|
-
style={{
|
|
9
|
-
position: 'fixed',
|
|
10
|
-
inset: 0,
|
|
11
|
-
background: 'rgba(0,0,0,0.6)',
|
|
12
|
-
display: 'grid',
|
|
13
|
-
placeItems: 'center',
|
|
14
|
-
zIndex: 50
|
|
15
|
-
}}>
|
|
16
|
-
<div style={{ background: 'var(--bg, #0b0f14)', padding: 24, borderRadius: 12, minWidth: 240 }}>
|
|
17
|
-
<h2>Photo {id}</h2>
|
|
18
|
-
<p>This is the intercepted modal view (soft navigation).</p>
|
|
19
|
-
<Toil.Link href="/gallery">Close</Toil.Link>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
1
|
+
// Intercepting route: `(.)photo/[id]` inside the `@modal` slot catches a soft navigation to
|
|
2
|
+
// /gallery/photo/:id and renders here instead, as an overlay, while the gallery stays mounted behind
|
|
3
|
+
// it. On a hard reload the interception does not apply and the full photo/[id].tsx page renders.
|
|
4
|
+
export default function PhotoModal() {
|
|
5
|
+
const { id } = Toil.useParams();
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
style={{
|
|
9
|
+
position: 'fixed',
|
|
10
|
+
inset: 0,
|
|
11
|
+
background: 'rgba(0,0,0,0.6)',
|
|
12
|
+
display: 'grid',
|
|
13
|
+
placeItems: 'center',
|
|
14
|
+
zIndex: 50
|
|
15
|
+
}}>
|
|
16
|
+
<div style={{ background: 'var(--bg, #0b0f14)', padding: 24, borderRadius: 12, minWidth: 240 }}>
|
|
17
|
+
<h2>Photo {id}</h2>
|
|
18
|
+
<p>This is the intercepted modal view (soft navigation).</p>
|
|
19
|
+
<Toil.Link href="/gallery">Close</Toil.Link>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
export const metadata: Toil.Metadata = {
|
|
2
|
-
title: 'Gallery',
|
|
3
|
-
description: 'Parallel routes and intercepting routes: a photo opens as a modal on soft nav.'
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
const photos = [1, 2, 3, 4];
|
|
7
|
-
|
|
8
|
-
// Clicking a photo soft-navigates to /gallery/photo/:id. The intercepting route @modal/(.)photo/[id]
|
|
9
|
-
// catches that on soft nav and shows it as a modal over this grid. A hard reload of the same URL
|
|
10
|
-
// renders the full page (photo/[id].tsx) instead, deep links still work.
|
|
11
|
-
export default function Gallery() {
|
|
12
|
-
return (
|
|
13
|
-
<main>
|
|
14
|
-
<h1>Gallery</h1>
|
|
15
|
-
<p>
|
|
16
|
-
Click a photo, it opens as a modal (intercepting route). Reload that URL and you get
|
|
17
|
-
|
|
18
|
-
</p>
|
|
19
|
-
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
|
|
20
|
-
{photos.map((id) => (
|
|
21
|
-
<Toil.Link
|
|
22
|
-
key={id}
|
|
23
|
-
href={`/gallery/photo/${id}`}
|
|
24
|
-
style={{
|
|
25
|
-
width: 88,
|
|
26
|
-
height: 88,
|
|
27
|
-
display: 'grid',
|
|
28
|
-
placeItems: 'center',
|
|
29
|
-
border: '1px solid currentColor',
|
|
30
|
-
borderRadius: 8,
|
|
31
|
-
fontWeight: 700
|
|
32
|
-
}}>
|
|
33
|
-
{id}
|
|
34
|
-
</Toil.Link>
|
|
35
|
-
))}
|
|
36
|
-
</div>
|
|
37
|
-
<p style={{ marginTop: 16 }}>
|
|
38
|
-
<Toil.Link href="/features">Back to features</Toil.Link>
|
|
39
|
-
</p>
|
|
40
|
-
</main>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
1
|
+
export const metadata: Toil.Metadata = {
|
|
2
|
+
title: 'Gallery',
|
|
3
|
+
description: 'Parallel routes and intercepting routes: a photo opens as a modal on soft nav.'
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
const photos = [1, 2, 3, 4];
|
|
7
|
+
|
|
8
|
+
// Clicking a photo soft-navigates to /gallery/photo/:id. The intercepting route @modal/(.)photo/[id]
|
|
9
|
+
// catches that on soft nav and shows it as a modal over this grid. A hard reload of the same URL
|
|
10
|
+
// renders the full page (photo/[id].tsx) instead, deep links still work.
|
|
11
|
+
export default function Gallery() {
|
|
12
|
+
return (
|
|
13
|
+
<main>
|
|
14
|
+
<h1>Gallery</h1>
|
|
15
|
+
<p>
|
|
16
|
+
Click a photo, it opens as a modal (intercepting route). Reload that URL and you get the full page. Same
|
|
17
|
+
URL, two presentations.
|
|
18
|
+
</p>
|
|
19
|
+
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
|
|
20
|
+
{photos.map((id) => (
|
|
21
|
+
<Toil.Link
|
|
22
|
+
key={id}
|
|
23
|
+
href={`/gallery/photo/${id}`}
|
|
24
|
+
style={{
|
|
25
|
+
width: 88,
|
|
26
|
+
height: 88,
|
|
27
|
+
display: 'grid',
|
|
28
|
+
placeItems: 'center',
|
|
29
|
+
border: '1px solid currentColor',
|
|
30
|
+
borderRadius: 8,
|
|
31
|
+
fontWeight: 700
|
|
32
|
+
}}>
|
|
33
|
+
{id}
|
|
34
|
+
</Toil.Link>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
<p style={{ marginTop: 16 }}>
|
|
38
|
+
<Toil.Link href="/features">Back to features</Toil.Link>
|
|
39
|
+
</p>
|
|
40
|
+
</main>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
export const generateMetadata: Toil.GenerateMetadata = ({ params }) => ({
|
|
2
|
-
title: `Photo ${params.id}
|
|
3
|
-
});
|
|
4
|
-
|
|
5
|
-
// The full page for a photo, shown on a hard load or deep link to /gallery/photo/:id.
|
|
6
|
-
export default function PhotoPage() {
|
|
7
|
-
const { id } = Toil.useParams();
|
|
8
|
-
return (
|
|
9
|
-
<main>
|
|
10
|
-
<h1>Photo {id}</h1>
|
|
11
|
-
<p>
|
|
12
|
-
Full page at <code>gallery/photo/[id].tsx</code>. Reached directly (reload or deep
|
|
13
|
-
|
|
14
|
-
</p>
|
|
15
|
-
<Toil.Link href="/gallery">Back to gallery</Toil.Link>
|
|
16
|
-
</main>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
1
|
+
export const generateMetadata: Toil.GenerateMetadata = ({ params }) => ({
|
|
2
|
+
title: `Photo ${params.id}`
|
|
3
|
+
});
|
|
4
|
+
|
|
5
|
+
// The full page for a photo, shown on a hard load or deep link to /gallery/photo/:id.
|
|
6
|
+
export default function PhotoPage() {
|
|
7
|
+
const { id } = Toil.useParams();
|
|
8
|
+
return (
|
|
9
|
+
<main>
|
|
10
|
+
<h1>Photo {id}</h1>
|
|
11
|
+
<p>
|
|
12
|
+
Full page at <code>gallery/photo/[id].tsx</code>. Reached directly (reload or deep link), not
|
|
13
|
+
intercepted.
|
|
14
|
+
</p>
|
|
15
|
+
<Toil.Link href="/gallery">Back to gallery</Toil.Link>
|
|
16
|
+
</main>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -1,84 +1,157 @@
|
|
|
1
|
-
export default function GetStarted() {
|
|
2
|
-
return (
|
|
3
|
-
<div className="gs-page">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
</
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
→
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
1
|
+
export default function GetStarted() {
|
|
2
|
+
return (
|
|
3
|
+
<div className="gs-page">
|
|
4
|
+
{/* Hero */}
|
|
5
|
+
<div className="gs-hero">
|
|
6
|
+
<h1 className="gs-title">Get Started</h1>
|
|
7
|
+
<p className="gs-desc">Everything you need to build your first ToilJS app.</p>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
{/* Info grid */}
|
|
11
|
+
<section className="gs-section">
|
|
12
|
+
<h2 className="gs-section-title">Project Structure</h2>
|
|
13
|
+
<div className="gs-grid">
|
|
14
|
+
<div className="gs-card gs-card--accent1">
|
|
15
|
+
<div className="gs-card-icon">
|
|
16
|
+
<svg
|
|
17
|
+
width="22"
|
|
18
|
+
height="22"
|
|
19
|
+
viewBox="0 0 24 24"
|
|
20
|
+
fill="none"
|
|
21
|
+
stroke="currentColor"
|
|
22
|
+
strokeWidth="2"
|
|
23
|
+
strokeLinecap="round"
|
|
24
|
+
strokeLinejoin="round">
|
|
25
|
+
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
|
|
26
|
+
</svg>
|
|
27
|
+
</div>
|
|
28
|
+
<h3>File-based Routing</h3>
|
|
29
|
+
<p>
|
|
30
|
+
Every <code>.tsx</code> file in <code>client/routes/</code> becomes a route. No config
|
|
31
|
+
required.
|
|
32
|
+
</p>
|
|
33
|
+
<pre>
|
|
34
|
+
<code>{`index.tsx → /
|
|
35
|
+
about.tsx → /about
|
|
36
|
+
[id].tsx → /:id
|
|
37
|
+
[...slug].tsx → /*`}</code>
|
|
38
|
+
</pre>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div className="gs-card gs-card--accent2">
|
|
42
|
+
<div className="gs-card-icon">
|
|
43
|
+
<svg
|
|
44
|
+
width="22"
|
|
45
|
+
height="22"
|
|
46
|
+
viewBox="0 0 24 24"
|
|
47
|
+
fill="none"
|
|
48
|
+
stroke="currentColor"
|
|
49
|
+
strokeWidth="2"
|
|
50
|
+
strokeLinecap="round"
|
|
51
|
+
strokeLinejoin="round">
|
|
52
|
+
<rect x="2" y="3" width="20" height="14" rx="2" />
|
|
53
|
+
<path d="M8 21h8M12 17v4" />
|
|
54
|
+
</svg>
|
|
55
|
+
</div>
|
|
56
|
+
<h3>Public Folder</h3>
|
|
57
|
+
<p>
|
|
58
|
+
Files in <code>public/</code> are copied as-is to the build root. Reference them with an
|
|
59
|
+
absolute path.
|
|
60
|
+
</p>
|
|
61
|
+
<pre>
|
|
62
|
+
<code>{`public/images/logo.svg
|
|
63
|
+
→ /images/logo.svg`}</code>
|
|
64
|
+
</pre>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div className="gs-card gs-card--accent3">
|
|
68
|
+
<div className="gs-card-icon">
|
|
69
|
+
<svg
|
|
70
|
+
width="22"
|
|
71
|
+
height="22"
|
|
72
|
+
viewBox="0 0 24 24"
|
|
73
|
+
fill="none"
|
|
74
|
+
stroke="currentColor"
|
|
75
|
+
strokeWidth="2"
|
|
76
|
+
strokeLinecap="round"
|
|
77
|
+
strokeLinejoin="round">
|
|
78
|
+
<rect x="3" y="3" width="18" height="18" rx="2" />
|
|
79
|
+
<path d="M3 9h18M9 21V9" />
|
|
80
|
+
</svg>
|
|
81
|
+
</div>
|
|
82
|
+
<h3>Layout</h3>
|
|
83
|
+
<p>
|
|
84
|
+
<code>client/layout.tsx</code> wraps every page. Use it for your nav, footer, providers, and
|
|
85
|
+
global styles.
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div className="gs-card gs-card--accent4">
|
|
90
|
+
<div className="gs-card-icon">
|
|
91
|
+
<svg
|
|
92
|
+
width="22"
|
|
93
|
+
height="22"
|
|
94
|
+
viewBox="0 0 24 24"
|
|
95
|
+
fill="none"
|
|
96
|
+
stroke="currentColor"
|
|
97
|
+
strokeWidth="2"
|
|
98
|
+
strokeLinecap="round"
|
|
99
|
+
strokeLinejoin="round">
|
|
100
|
+
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
|
|
101
|
+
</svg>
|
|
102
|
+
</div>
|
|
103
|
+
<h3>Entry Point</h3>
|
|
104
|
+
<p>
|
|
105
|
+
<code>client/toil.tsx</code> is the app entry. Import global CSS and call{' '}
|
|
106
|
+
<code>Toil.mount()</code>, runs once on startup.
|
|
107
|
+
</p>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</section>
|
|
111
|
+
|
|
112
|
+
{/* Navigation section */}
|
|
113
|
+
<section className="gs-section">
|
|
114
|
+
<h2 className="gs-section-title">Navigation</h2>
|
|
115
|
+
<div className="gs-card gs-card--flat">
|
|
116
|
+
<div className="gs-card-icon">
|
|
117
|
+
<svg
|
|
118
|
+
width="22"
|
|
119
|
+
height="22"
|
|
120
|
+
viewBox="0 0 24 24"
|
|
121
|
+
fill="none"
|
|
122
|
+
stroke="currentColor"
|
|
123
|
+
strokeWidth="2"
|
|
124
|
+
strokeLinecap="round"
|
|
125
|
+
strokeLinejoin="round">
|
|
126
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
127
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
128
|
+
</svg>
|
|
129
|
+
</div>
|
|
130
|
+
<h3>
|
|
131
|
+
Use <code>{'<Toil.Link>'}</code> for client-side navigation
|
|
132
|
+
</h3>
|
|
133
|
+
<p>
|
|
134
|
+
Avoids full page reloads and keeps transitions instant. Use a regular <code>{'<a>'}</code> only
|
|
135
|
+
for external links.
|
|
136
|
+
</p>
|
|
137
|
+
<pre>
|
|
138
|
+
<code>{`// ✅ Internal navigation
|
|
139
|
+
<Toil.Link href="/about">About</Toil.Link>
|
|
140
|
+
|
|
141
|
+
// ✅ External link
|
|
142
|
+
<a href="https://toil.org" target="_blank">Docs</a>`}</code>
|
|
143
|
+
</pre>
|
|
144
|
+
</div>
|
|
145
|
+
</section>
|
|
146
|
+
|
|
147
|
+
<div className="gs-actions">
|
|
148
|
+
<Toil.Link href="/" className="btn btn-secondary">
|
|
149
|
+
← Back home
|
|
150
|
+
</Toil.Link>
|
|
151
|
+
<a href="https://toil.org/docs" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
|
|
152
|
+
Read the Docs
|
|
153
|
+
</a>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|