toiljs 0.0.10 → 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.
Files changed (128) hide show
  1. package/README.md +315 -1
  2. package/assets/logo.svg +37 -0
  3. package/build/cli/.tsbuildinfo +1 -1
  4. package/build/cli/configure.js +10 -4
  5. package/build/cli/create.js +60 -32
  6. package/build/cli/diagnostics.d.ts +55 -0
  7. package/build/cli/diagnostics.js +333 -0
  8. package/build/cli/doctor.d.ts +6 -0
  9. package/build/cli/doctor.js +249 -0
  10. package/build/cli/index.js +26 -0
  11. package/build/cli/proc.d.ts +5 -0
  12. package/build/cli/proc.js +20 -0
  13. package/build/cli/ui.d.ts +1 -0
  14. package/build/cli/ui.js +1 -0
  15. package/build/cli/update.d.ts +7 -0
  16. package/build/cli/update.js +117 -0
  17. package/build/cli/updates.d.ts +10 -0
  18. package/build/cli/updates.js +45 -0
  19. package/build/client/.tsbuildinfo +1 -1
  20. package/build/client/dev/error-overlay.js +1 -1
  21. package/build/client/head/metadata.js +3 -1
  22. package/build/client/index.d.ts +5 -1
  23. package/build/client/index.js +2 -0
  24. package/build/client/navigation/navigation.js +1 -1
  25. package/build/client/routing/Router.js +2 -2
  26. package/build/client/search/search.d.ts +26 -0
  27. package/build/client/search/search.js +101 -0
  28. package/build/client/search/use-page-search.d.ts +8 -0
  29. package/build/client/search/use-page-search.js +21 -0
  30. package/build/compiler/.tsbuildinfo +1 -1
  31. package/build/compiler/generate.js +35 -26
  32. package/build/compiler/index.d.ts +2 -0
  33. package/build/compiler/index.js +1 -0
  34. package/build/compiler/pages.d.ts +8 -0
  35. package/build/compiler/pages.js +37 -0
  36. package/build/compiler/plugin.js +3 -1
  37. package/build/compiler/prerender.d.ts +1 -0
  38. package/build/compiler/prerender.js +11 -5
  39. package/build/compiler/seo.js +10 -3
  40. package/build/compiler/vite.js +7 -0
  41. package/build/io/.tsbuildinfo +1 -1
  42. package/examples/basic/client/components/Header.tsx +43 -38
  43. package/examples/basic/client/components/HoneycombBackground.tsx +223 -230
  44. package/examples/basic/client/layout.tsx +4 -1
  45. package/examples/basic/client/public/index.html +18 -16
  46. package/examples/basic/client/routes/(legal)/privacy.tsx +18 -0
  47. package/examples/basic/client/routes/(legal)/terms.tsx +15 -0
  48. package/examples/basic/client/routes/about.tsx +21 -19
  49. package/examples/basic/client/routes/blog/[id].tsx +26 -12
  50. package/examples/basic/client/routes/features/actions.tsx +67 -0
  51. package/examples/basic/client/routes/features/error/error.tsx +16 -0
  52. package/examples/basic/client/routes/features/error/index.tsx +27 -0
  53. package/examples/basic/client/routes/features/head.tsx +38 -0
  54. package/examples/basic/client/routes/features/index.tsx +83 -0
  55. package/examples/basic/client/routes/features/realtime.tsx +34 -0
  56. package/examples/basic/client/routes/features/script.tsx +31 -0
  57. package/examples/basic/client/routes/features/seo.tsx +39 -0
  58. package/examples/basic/client/routes/features/template/b.tsx +14 -0
  59. package/examples/basic/client/routes/features/template/index.tsx +20 -0
  60. package/examples/basic/client/routes/features/template/template.tsx +16 -0
  61. package/examples/basic/client/routes/files/[[...slug]].tsx +21 -0
  62. package/examples/basic/client/routes/gallery/@modal/(.)photo/[id].tsx +23 -0
  63. package/examples/basic/client/routes/gallery/index.tsx +42 -0
  64. package/examples/basic/client/routes/gallery/layout.tsx +13 -0
  65. package/examples/basic/client/routes/gallery/photo/[id].tsx +18 -0
  66. package/examples/basic/client/routes/get-started.tsx +157 -84
  67. package/examples/basic/client/routes/index.tsx +137 -87
  68. package/examples/basic/client/routes/loader-demo/index.tsx +59 -50
  69. package/examples/basic/client/routes/search.tsx +61 -0
  70. package/examples/basic/client/routes/test.tsx +7 -8
  71. package/examples/basic/client/styles/main.css +624 -552
  72. package/examples/basic/client/toil.tsx +2 -4
  73. package/package.json +3 -2
  74. package/presets/eslint.js +10 -3
  75. package/src/cli/configure.ts +363 -353
  76. package/src/cli/create.ts +563 -530
  77. package/src/cli/diagnostics.ts +421 -0
  78. package/src/cli/doctor.ts +318 -0
  79. package/src/cli/features.ts +166 -160
  80. package/src/cli/index.ts +242 -211
  81. package/src/cli/proc.ts +30 -0
  82. package/src/cli/ui.ts +111 -103
  83. package/src/cli/update.ts +150 -0
  84. package/src/cli/updates.ts +69 -0
  85. package/src/client/components/Image.tsx +91 -89
  86. package/src/client/dev/error-overlay.tsx +193 -197
  87. package/src/client/head/metadata.ts +94 -92
  88. package/src/client/index.ts +79 -64
  89. package/src/client/navigation/Link.tsx +94 -100
  90. package/src/client/navigation/navigation.ts +215 -218
  91. package/src/client/routing/Router.tsx +210 -193
  92. package/src/client/routing/hooks.ts +110 -114
  93. package/src/client/routing/lazy.ts +77 -81
  94. package/src/client/search/search.ts +189 -0
  95. package/src/client/search/use-page-search.ts +73 -0
  96. package/src/compiler/config.ts +173 -171
  97. package/src/compiler/fonts.ts +89 -87
  98. package/src/compiler/generate.ts +378 -364
  99. package/src/compiler/image-report.ts +88 -85
  100. package/src/compiler/index.ts +2 -0
  101. package/src/compiler/pages.ts +70 -0
  102. package/src/compiler/plugin.ts +51 -47
  103. package/src/compiler/prerender.ts +152 -130
  104. package/src/compiler/routes.ts +132 -131
  105. package/src/compiler/seo.ts +381 -356
  106. package/src/compiler/vite.ts +155 -130
  107. package/src/io/FastSet.ts +99 -96
  108. package/test/configure.test.ts +94 -90
  109. package/test/doctor.test.ts +140 -0
  110. package/test/dom/Image.test.tsx +73 -46
  111. package/test/dom/Script.test.tsx +48 -45
  112. package/test/dom/action.test.tsx +146 -129
  113. package/test/dom/error-overlay.test.tsx +44 -44
  114. package/test/dom/loader.test.tsx +2 -2
  115. package/test/dom/revalidate.test.tsx +1 -1
  116. package/test/dom/route-head.test.tsx +35 -2
  117. package/test/dom/slot.test.tsx +131 -109
  118. package/test/dom/view-transitions.test.tsx +53 -51
  119. package/test/features.test.ts +149 -142
  120. package/test/fonts.test.ts +28 -26
  121. package/test/head.test.ts +45 -35
  122. package/test/metadata.test.ts +42 -41
  123. package/test/pages.test.ts +105 -0
  124. package/test/prerender.test.ts +54 -46
  125. package/test/search.test.ts +114 -0
  126. package/test/seo.test.ts +164 -142
  127. package/test/slot-layouts.test.ts +69 -0
  128. package/test/update.test.ts +44 -0
@@ -1,84 +1,157 @@
1
- export default function GetStarted() {
2
- return (
3
- <div className="gs-page">
4
-
5
- {/* Hero */}
6
- <div className="gs-hero">
7
- <h1 className="gs-title">Get Started</h1>
8
- <p className="gs-desc">Everything you need to build your first ToilJS app.</p>
9
- </div>
10
-
11
-
12
- {/* Info grid */}
13
- <section className="gs-section">
14
- <h2 className="gs-section-title">Project Structure</h2>
15
- <div className="gs-grid">
16
-
17
- <div className="gs-card gs-card--accent1">
18
- <div className="gs-card-icon">
19
- <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><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"/></svg>
20
- </div>
21
- <h3>File-based Routing</h3>
22
- <p>Every <code>.tsx</code> file in <code>client/routes/</code> becomes a route. No config required.</p>
23
- <pre><code>{`index.tsx → /
24
- about.tsx → /about
25
- [id].tsx → /:id
26
- [...slug].tsx → /*`}</code></pre>
27
- </div>
28
-
29
- <div className="gs-card gs-card--accent2">
30
- <div className="gs-card-icon">
31
- <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
32
- </div>
33
- <h3>Public Folder</h3>
34
- <p>Files in <code>public/</code> are copied as-is to the build root. Reference them with an absolute path.</p>
35
- <pre><code>{`public/images/logo.svg
36
- /images/logo.svg`}</code></pre>
37
- </div>
38
-
39
- <div className="gs-card gs-card--accent3">
40
- <div className="gs-card-icon">
41
- <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
42
- </div>
43
- <h3>Layout</h3>
44
- <p><code>client/layout.tsx</code> wraps every page. Use it for your nav, footer, providers, and global styles.</p>
45
- </div>
46
-
47
- <div className="gs-card gs-card--accent4">
48
- <div className="gs-card-icon">
49
- <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
50
- </div>
51
- <h3>Entry Point</h3>
52
- <p><code>client/toil.tsx</code> is the app entry. Import global CSS and call <code>Toil.mount()</code>, runs once on startup.</p>
53
- </div>
54
-
55
- </div>
56
- </section>
57
-
58
- {/* Navigation section */}
59
- <section className="gs-section">
60
- <h2 className="gs-section-title">Navigation</h2>
61
- <div className="gs-card gs-card--flat">
62
- <div className="gs-card-icon">
63
- <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
64
- </div>
65
- <h3>Use <code>{'<Toil.Link>'}</code> for client-side navigation</h3>
66
- <p>Avoids full page reloads and keeps transitions instant. Use a regular <code>{'<a>'}</code> only for external links.</p>
67
- <pre><code>{`// Internal navigation
68
- <Toil.Link href="/about">About</Toil.Link>
69
-
70
- // ✅ External link
71
- <a href="https://toil.org" target="_blank">Docs</a>`}</code></pre>
72
- </div>
73
- </section>
74
-
75
- <div className="gs-actions">
76
- <Toil.Link href="/" className="btn btn-secondary">← Back home</Toil.Link>
77
- <a href="https://toil.org/docs" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
78
- Read the Docs
79
- </a>
80
- </div>
81
-
82
- </div>
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
+ }
@@ -1,87 +1,137 @@
1
- const GitHubIcon = () => (
2
- <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
3
- <path d="M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.009-.868-.013-1.703-2.782.604-3.369-1.341-3.369-1.341-.454-1.154-1.11-1.462-1.11-1.462-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836a9.59 9.59 0 0 1 2.504.337c1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.579.688.481C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z" />
4
- </svg>
5
- );
6
-
7
- const icons = {
8
- hmr: (
9
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
10
- <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
11
- </svg>
12
- ),
13
- routing: (
14
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
15
- <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" />
16
- </svg>
17
- ),
18
- typescript: (
19
- <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
20
- <rect x="2" y="2" width="20" height="20" rx="3" fill="currentColor" />
21
- <path d="M13.5 12H15.5V18H17V12H19V10.5H13.5V12Z" fill="var(--bg)" />
22
- <path d="M11 10.5C9.07 10.5 7.5 12.07 7.5 14C7.5 15.45 8.38 16.69 9.65 17.23L7.5 18H11C12.93 18 14.5 16.43 14.5 14.5C14.5 13.26 13.86 12.17 12.9 11.55C12.42 11.22 11.73 10.5 11 10.5ZM11 12C12.1 12 13 12.9 13 14C13 15.1 12.1 16 11 16H9.72C9.28 15.57 9 14.81 9 14C9 12.9 9.9 12 11 12Z" fill="var(--bg)" />
23
- </svg>
24
- ),
25
- builds: (
26
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
27
- <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
28
- <polyline points="3.27 6.96 12 12.01 20.73 6.96" />
29
- <line x1="12" y1="22.08" x2="12" y2="12" />
30
- </svg>
31
- ),
32
- };
33
-
34
- const features = [
35
- { icon: icons.hmr, label: 'Instant HMR' },
36
- { icon: icons.routing, label: 'File Routing' },
37
- { icon: icons.typescript, label: 'TypeScript' },
38
- { icon: icons.builds, label: 'Optimized Builds' },
39
- ];
40
-
41
- export default function Home() {
42
- return (
43
- <section className="hero">
44
- <div className="hero-logo">
45
- <img src="images/logo.svg" className="hero-logo-glow" alt="" aria-hidden="true" width={96} height={96} />
46
- <Toil.Image
47
- src="images/logo.svg"
48
- className="hero-logo-img"
49
- alt="ToilJS"
50
- width={96}
51
- height={96}
52
- priority
53
- />
54
- </div>
55
-
56
- <h1 className="hero-title">ToilJS</h1>
57
-
58
- <p className="hero-tagline">
59
- Next-gen React.<br />
60
- <span>Zero config.</span>
61
- </p>
62
-
63
- <p className="hero-desc">
64
- File-based routing, blazing-fast HMR, and full TypeScript.
65
- <br />All powered by Vite.
66
- </p>
67
-
68
- <ul className="features">
69
- {features.map(f => (
70
- <li key={f.label} className="feature-badge">
71
- {f.icon}{f.label}
72
- </li>
73
- ))}
74
- </ul>
75
-
76
- <div className="hero-cta">
77
- <Toil.Link href="/get-started" className="btn btn-primary">
78
- Get Started
79
- </Toil.Link>
80
- <a className="btn btn-secondary" href="https://github.com/btc-vision/toiljs" target="_blank" rel="noopener noreferrer">
81
- <GitHubIcon />
82
- GitHub
83
- </a>
84
- </div>
85
- </section>
86
- );
87
- }
1
+ // The home page sets its own title with an absolute template (`%s`), so the tab reads exactly this
2
+ // rather than being suffixed by the layout's "%s | ToilJS".
3
+ export const metadata: Toil.Metadata = {
4
+ title: 'ToilJS, the modern React framework',
5
+ titleTemplate: '%s',
6
+ description: 'File-based routing, instant HMR, build-time SEO, and a WebAssembly backend. Zero config.',
7
+ openGraph: { title: 'ToilJS', type: 'website' }
8
+ };
9
+
10
+ const GitHubIcon = () => (
11
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
12
+ <path d="M12 2C6.477 2 2 6.477 2 12c0 4.418 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.009-.868-.013-1.703-2.782.604-3.369-1.341-3.369-1.341-.454-1.154-1.11-1.462-1.11-1.462-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836a9.59 9.59 0 0 1 2.504.337c1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.579.688.481C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z" />
13
+ </svg>
14
+ );
15
+
16
+ const icons = {
17
+ hmr: (
18
+ <svg
19
+ width="16"
20
+ height="16"
21
+ viewBox="0 0 24 24"
22
+ fill="none"
23
+ stroke="currentColor"
24
+ strokeWidth="2"
25
+ strokeLinecap="round"
26
+ strokeLinejoin="round">
27
+ <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
28
+ </svg>
29
+ ),
30
+ routing: (
31
+ <svg
32
+ width="16"
33
+ height="16"
34
+ viewBox="0 0 24 24"
35
+ fill="none"
36
+ stroke="currentColor"
37
+ strokeWidth="2"
38
+ strokeLinecap="round"
39
+ strokeLinejoin="round">
40
+ <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" />
41
+ </svg>
42
+ ),
43
+ typescript: (
44
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
45
+ <rect x="2" y="2" width="20" height="20" rx="3" fill="currentColor" />
46
+ <path d="M13.5 12H15.5V18H17V12H19V10.5H13.5V12Z" fill="var(--bg)" />
47
+ <path
48
+ d="M11 10.5C9.07 10.5 7.5 12.07 7.5 14C7.5 15.45 8.38 16.69 9.65 17.23L7.5 18H11C12.93 18 14.5 16.43 14.5 14.5C14.5 13.26 13.86 12.17 12.9 11.55C12.42 11.22 11.73 10.5 11 10.5ZM11 12C12.1 12 13 12.9 13 14C13 15.1 12.1 16 11 16H9.72C9.28 15.57 9 14.81 9 14C9 12.9 9.9 12 11 12Z"
49
+ fill="var(--bg)"
50
+ />
51
+ </svg>
52
+ ),
53
+ builds: (
54
+ <svg
55
+ width="16"
56
+ height="16"
57
+ viewBox="0 0 24 24"
58
+ fill="none"
59
+ stroke="currentColor"
60
+ strokeWidth="2"
61
+ strokeLinecap="round"
62
+ strokeLinejoin="round">
63
+ <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
64
+ <polyline points="3.27 6.96 12 12.01 20.73 6.96" />
65
+ <line x1="12" y1="22.08" x2="12" y2="12" />
66
+ </svg>
67
+ )
68
+ };
69
+
70
+ const features = [
71
+ { icon: icons.hmr, label: 'Instant HMR' },
72
+ { icon: icons.routing, label: 'File Routing' },
73
+ { icon: icons.typescript, label: 'TypeScript' },
74
+ { icon: icons.builds, label: 'Optimized Builds' }
75
+ ];
76
+
77
+ export default function Home() {
78
+ return (
79
+ <section className="hero">
80
+ <div className="hero-logo">
81
+ <img
82
+ src="/images/logo.svg"
83
+ className="hero-logo-glow"
84
+ alt=""
85
+ aria-hidden="true"
86
+ width={96}
87
+ height={96}
88
+ />
89
+ <Toil.Image
90
+ src="/images/logo.svg"
91
+ className="hero-logo-img"
92
+ alt="ToilJS"
93
+ width={96}
94
+ height={96}
95
+ priority
96
+ />
97
+ </div>
98
+
99
+ <h1 className="hero-title">ToilJS</h1>
100
+
101
+ <p className="hero-tagline">
102
+ Next-gen React.
103
+ <br />
104
+ <span>Zero config.</span>
105
+ </p>
106
+
107
+ <p className="hero-desc">
108
+ File-based routing, blazing-fast HMR, and full TypeScript.
109
+ <br />
110
+ All powered by Vite.
111
+ </p>
112
+
113
+ <ul className="features">
114
+ {features.map((f) => (
115
+ <li key={f.label} className="feature-badge">
116
+ {f.icon}
117
+ {f.label}
118
+ </li>
119
+ ))}
120
+ </ul>
121
+
122
+ <div className="hero-cta">
123
+ <Toil.Link href="/get-started" className="btn btn-primary">
124
+ Get Started
125
+ </Toil.Link>
126
+ <a
127
+ className="btn btn-secondary"
128
+ href="https://github.com/btc-vision/toiljs"
129
+ target="_blank"
130
+ rel="noopener noreferrer">
131
+ <GitHubIcon />
132
+ GitHub
133
+ </a>
134
+ </div>
135
+ </section>
136
+ );
137
+ }
@@ -1,50 +1,59 @@
1
- async function wait(ms: number): Promise<void> {
2
- return new Promise((resolve) => setTimeout(resolve, ms));
3
- }
4
-
5
- export const loader = async ({ searchParams }: Toil.LoaderArgs) => {
6
- await wait(2000);
7
- return { loadedAt: new Date().toISOString(), q: searchParams.get('q') };
8
- };
9
-
10
- // Cache this route's data for 10s: revisiting within 10s is instant (no 2s wait); after that it
11
- // refetches on navigation. Use `false` to cache forever, or omit for the default (refetch every nav).
12
- export const revalidate: Toil.Revalidate = 10;
13
-
14
- // Dynamic metadata derived from the loader's data (vs the static `metadata` export on /about).
15
- export const generateMetadata: Toil.GenerateMetadata<Awaited<ReturnType<typeof loader>>> = ({
16
- data,
17
- }) => ({ title: `Loader demo, loaded ${data.loadedAt}` });
18
-
19
- export default function LoaderDemo() {
20
- // Pass the loader to infer the data type from its return, no generics, no restating the shape.
21
- const data = Toil.useLoaderData(loader);
22
- const router = Toil.useRouter();
23
- return (
24
- <main>
25
- <h1>Loader demo</h1>
26
- <p>
27
- Data loaded before render (no <code>useEffect</code>): <code>{data.loadedAt}</code>
28
- {data.q !== null ? ` · q=${data.q}` : ''}
29
- </p>
30
- <p>
31
- <button type="button" onClick={() => { router.revalidate(); }}>
32
- Revalidate (refetch)
33
- </button>
34
- </p>
35
- {/* The write half: an action runs on submit, then revalidates this route's loader so
36
- `loadedAt` above updates, read → write → revalidate, no manual refetch. */}
37
- <Toil.Form action={async (form) => { await wait(500); console.log('saved', form.get('note')); }}>
38
- {({ pending }) => (
39
- <>
40
- <input name="note" placeholder="Leave a note" disabled={pending} />
41
- <button type="submit" disabled={pending}>
42
- {pending ? 'Saving…' : 'Save & revalidate'}
43
- </button>
44
- </>
45
- )}
46
- </Toil.Form>
47
- <Toil.Link href="/">Back home</Toil.Link>
48
- </main>
49
- );
50
- }
1
+ async function wait(ms: number): Promise<void> {
2
+ return new Promise((resolve) => setTimeout(resolve, ms));
3
+ }
4
+
5
+ export const loader = async ({ searchParams }: Toil.LoaderArgs) => {
6
+ await wait(2000);
7
+ return { loadedAt: new Date().toISOString(), q: searchParams.get('q') };
8
+ };
9
+
10
+ // Cache this route's data for 10s: revisiting within 10s is instant (no 2s wait); after that it
11
+ // refetches on navigation. Use `false` to cache forever, or omit for the default (refetch every nav).
12
+ export const revalidate: Toil.Revalidate = 10;
13
+
14
+ // Dynamic metadata derived from the loader's data (vs the static `metadata` export on /about).
15
+ export const generateMetadata: Toil.GenerateMetadata<Awaited<ReturnType<typeof loader>>> = ({ data }) => ({
16
+ title: `Loader demo, loaded ${data.loadedAt}`
17
+ });
18
+
19
+ export default function LoaderDemo() {
20
+ // Pass the loader to infer the data type from its return, no generics, no restating the shape.
21
+ const data = Toil.useLoaderData(loader);
22
+ const router = Toil.useRouter();
23
+ return (
24
+ <main>
25
+ <h1>Loader demo</h1>
26
+ <p>
27
+ Data loaded before render (no <code>useEffect</code>): <code>{data.loadedAt}</code>
28
+ {data.q !== null ? `, q=${data.q}` : ''}
29
+ </p>
30
+ <p>
31
+ <button
32
+ type="button"
33
+ onClick={() => {
34
+ router.revalidate();
35
+ }}>
36
+ Revalidate (refetch)
37
+ </button>
38
+ </p>
39
+ {/* The write half: an action runs on submit, then revalidates this route's loader so
40
+ `loadedAt` above updates, read, write, revalidate, no manual refetch. */}
41
+ <Toil.Form
42
+ action={async (form) => {
43
+ await wait(500);
44
+ console.log('saved', form.get('note'));
45
+ }}
46
+ revalidate>
47
+ {({ pending }) => (
48
+ <>
49
+ <input name="note" placeholder="Leave a note" disabled={pending} />
50
+ <button type="submit" disabled={pending}>
51
+ {pending ? 'Saving' : 'Save & revalidate'}
52
+ </button>
53
+ </>
54
+ )}
55
+ </Toil.Form>
56
+ <Toil.Link href="/">Back home</Toil.Link>
57
+ </main>
58
+ );
59
+ }