create-velox-app 0.4.14 → 0.6.25

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 (113) hide show
  1. package/README.md +2 -43
  2. package/dist/cli.js +23 -13
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +26 -8
  5. package/dist/index.js.map +1 -1
  6. package/dist/templates/auth.d.ts.map +1 -1
  7. package/dist/templates/auth.js +24 -0
  8. package/dist/templates/auth.js.map +1 -1
  9. package/dist/templates/fullstack.d.ts +15 -0
  10. package/dist/templates/fullstack.d.ts.map +1 -0
  11. package/dist/templates/fullstack.js +110 -0
  12. package/dist/templates/fullstack.js.map +1 -0
  13. package/dist/templates/index.d.ts +1 -1
  14. package/dist/templates/index.d.ts.map +1 -1
  15. package/dist/templates/index.js +27 -5
  16. package/dist/templates/index.js.map +1 -1
  17. package/dist/templates/placeholders.d.ts +6 -1
  18. package/dist/templates/placeholders.d.ts.map +1 -1
  19. package/dist/templates/placeholders.js +15 -5
  20. package/dist/templates/placeholders.js.map +1 -1
  21. package/dist/templates/rsc.d.ts +15 -0
  22. package/dist/templates/rsc.d.ts.map +1 -0
  23. package/dist/templates/rsc.js +192 -0
  24. package/dist/templates/rsc.js.map +1 -0
  25. package/dist/templates/shared/root.d.ts +1 -0
  26. package/dist/templates/shared/root.d.ts.map +1 -1
  27. package/dist/templates/shared/root.js +4 -0
  28. package/dist/templates/shared/root.js.map +1 -1
  29. package/dist/templates/spa.d.ts +12 -0
  30. package/dist/templates/spa.d.ts.map +1 -0
  31. package/dist/templates/spa.js +101 -0
  32. package/dist/templates/spa.js.map +1 -0
  33. package/dist/templates/trpc.d.ts.map +1 -1
  34. package/dist/templates/trpc.js +16 -0
  35. package/dist/templates/trpc.js.map +1 -1
  36. package/dist/templates/types.d.ts +14 -1
  37. package/dist/templates/types.d.ts.map +1 -1
  38. package/dist/templates/types.js +35 -10
  39. package/dist/templates/types.js.map +1 -1
  40. package/package.json +3 -3
  41. package/src/templates/source/api/config/auth.ts +2 -2
  42. package/src/templates/source/api/config/database.ts +44 -10
  43. package/src/templates/source/api/index.auth.ts +10 -16
  44. package/src/templates/source/api/index.default.ts +10 -9
  45. package/src/templates/source/api/index.trpc.ts +9 -28
  46. package/src/templates/source/api/package.auth.json +7 -6
  47. package/src/templates/source/api/package.default.json +5 -4
  48. package/src/templates/source/api/prisma/schema.auth.prisma +3 -2
  49. package/src/templates/source/api/prisma/schema.default.prisma +3 -2
  50. package/src/templates/source/api/prisma.config.ts +7 -1
  51. package/src/templates/source/api/procedures/auth.ts +38 -66
  52. package/src/templates/source/api/procedures/health.ts +4 -9
  53. package/src/templates/source/api/procedures/users.auth.ts +7 -11
  54. package/src/templates/source/api/procedures/users.default.ts +7 -11
  55. package/src/templates/source/api/router.auth.ts +31 -0
  56. package/src/templates/source/api/router.default.ts +29 -0
  57. package/src/templates/source/api/router.trpc.ts +37 -0
  58. package/src/templates/source/api/router.types.auth.ts +88 -0
  59. package/src/templates/source/api/router.types.default.ts +73 -0
  60. package/src/templates/source/api/router.types.trpc.ts +73 -0
  61. package/src/templates/source/api/routes.auth.ts +66 -0
  62. package/src/templates/source/api/routes.default.ts +53 -0
  63. package/src/templates/source/api/schemas/auth.ts +79 -0
  64. package/src/templates/source/api/schemas/health.ts +21 -0
  65. package/src/templates/source/api/schemas/user.ts +62 -12
  66. package/src/templates/source/api/utils/auth.ts +157 -0
  67. package/src/templates/source/root/.cursorrules +187 -0
  68. package/src/templates/source/root/CLAUDE.auth.md +264 -0
  69. package/src/templates/source/root/CLAUDE.default.md +185 -0
  70. package/src/templates/source/root/package.json +7 -1
  71. package/src/templates/source/rsc/CLAUDE.md +104 -0
  72. package/src/templates/source/rsc/app/actions/posts.ts +93 -0
  73. package/src/templates/source/rsc/app/actions/users.ts +83 -0
  74. package/src/templates/source/rsc/app/layouts/dashboard.tsx +127 -0
  75. package/src/templates/source/rsc/app/layouts/marketing.tsx +25 -0
  76. package/src/templates/source/rsc/app/layouts/minimal.tsx +30 -0
  77. package/src/templates/source/rsc/app/layouts/root.tsx +241 -0
  78. package/src/templates/source/rsc/app/pages/(dashboard)/profile.tsx +71 -0
  79. package/src/templates/source/rsc/app/pages/(dashboard)/settings.tsx +104 -0
  80. package/src/templates/source/rsc/app/pages/(marketing)/about.tsx +52 -0
  81. package/src/templates/source/rsc/app/pages/_not-found.tsx +149 -0
  82. package/src/templates/source/rsc/app/pages/docs/[...slug].tsx +211 -0
  83. package/src/templates/source/rsc/app/pages/index.tsx +50 -0
  84. package/src/templates/source/rsc/app/pages/print.tsx +80 -0
  85. package/src/templates/source/rsc/app/pages/users/[id]/posts/[postId].tsx +89 -0
  86. package/src/templates/source/rsc/app/pages/users/[id]/posts/index.tsx +76 -0
  87. package/src/templates/source/rsc/app/pages/users/[id]/posts/new.tsx +79 -0
  88. package/src/templates/source/rsc/app/pages/users/[id].tsx +64 -0
  89. package/src/templates/source/rsc/app/pages/users/_layout.tsx +104 -0
  90. package/src/templates/source/rsc/app/pages/users.tsx +44 -0
  91. package/src/templates/source/rsc/app.config.ts +12 -0
  92. package/src/templates/source/rsc/env.example +6 -0
  93. package/src/templates/source/rsc/gitignore +34 -0
  94. package/src/templates/source/rsc/package.json +41 -0
  95. package/src/templates/source/rsc/prisma/schema.prisma +34 -0
  96. package/src/templates/source/rsc/prisma.config.ts +22 -0
  97. package/src/templates/source/rsc/public/favicon.svg +4 -0
  98. package/src/templates/source/rsc/src/api/database.ts +72 -0
  99. package/src/templates/source/rsc/src/api/handler.ts +53 -0
  100. package/src/templates/source/rsc/src/api/procedures/health.ts +48 -0
  101. package/src/templates/source/rsc/src/api/procedures/posts.ts +151 -0
  102. package/src/templates/source/rsc/src/api/procedures/users.ts +87 -0
  103. package/src/templates/source/rsc/src/api/schemas/post.ts +53 -0
  104. package/src/templates/source/rsc/src/api/schemas/user.ts +38 -0
  105. package/src/templates/source/rsc/src/entry.client.tsx +28 -0
  106. package/src/templates/source/rsc/src/entry.server.tsx +304 -0
  107. package/src/templates/source/rsc/tsconfig.json +24 -0
  108. package/src/templates/source/web/App.module.css +1 -1
  109. package/src/templates/source/web/api.ts +8 -1
  110. package/src/templates/source/web/main.tsx +4 -4
  111. package/src/templates/source/web/package.json +6 -6
  112. package/src/templates/source/web/routes/__root.tsx +2 -2
  113. package/src/templates/source/web/routes/index.auth.tsx +3 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Root Layout
3
+ *
4
+ * The root layout wraps all pages with common UI elements.
5
+ * This is a Server Component that provides the HTML structure.
6
+ */
7
+
8
+ import type { ReactNode } from 'react';
9
+
10
+ interface RootLayoutProps {
11
+ children: ReactNode;
12
+ params?: Record<string, string>;
13
+ }
14
+
15
+ export default function RootLayout({ children }: RootLayoutProps) {
16
+ return (
17
+ <html lang="en">
18
+ <head>
19
+ <meta charSet="utf-8" />
20
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
21
+ <title>VeloxTS App</title>
22
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
23
+ <style>{`
24
+ * {
25
+ box-sizing: border-box;
26
+ margin: 0;
27
+ padding: 0;
28
+ }
29
+
30
+ body {
31
+ font-family: system-ui, -apple-system, sans-serif;
32
+ line-height: 1.6;
33
+ color: #1a1a2e;
34
+ background: #f8f9fa;
35
+ }
36
+
37
+ .layout {
38
+ min-height: 100vh;
39
+ display: flex;
40
+ flex-direction: column;
41
+ }
42
+
43
+ .nav {
44
+ background: #1a1a2e;
45
+ padding: 1rem 2rem;
46
+ }
47
+
48
+ .nav-list {
49
+ display: flex;
50
+ gap: 2rem;
51
+ list-style: none;
52
+ max-width: 1200px;
53
+ margin: 0 auto;
54
+ }
55
+
56
+ .nav-link {
57
+ color: #e8e8e8;
58
+ text-decoration: none;
59
+ font-weight: 500;
60
+ transition: color 0.2s;
61
+ }
62
+
63
+ .nav-link:hover {
64
+ color: #6366f1;
65
+ }
66
+
67
+ .main {
68
+ flex: 1;
69
+ padding: 2rem;
70
+ max-width: 1200px;
71
+ margin: 0 auto;
72
+ width: 100%;
73
+ }
74
+
75
+ .footer {
76
+ background: #1a1a2e;
77
+ color: #a8a8b8;
78
+ text-align: center;
79
+ padding: 1rem;
80
+ font-size: 0.875rem;
81
+ }
82
+
83
+ /* Page styles */
84
+ .home-page .hero {
85
+ text-align: center;
86
+ padding: 3rem 0;
87
+ }
88
+
89
+ .home-page h1 {
90
+ font-size: 2.5rem;
91
+ margin-bottom: 0.5rem;
92
+ }
93
+
94
+ .home-page .tagline {
95
+ color: #666;
96
+ font-size: 1.25rem;
97
+ }
98
+
99
+ .stats {
100
+ display: flex;
101
+ gap: 1rem;
102
+ justify-content: center;
103
+ margin: 2rem 0;
104
+ }
105
+
106
+ .stat-card {
107
+ background: white;
108
+ padding: 1.5rem 2rem;
109
+ border-radius: 8px;
110
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
111
+ text-align: center;
112
+ }
113
+
114
+ .stat-value {
115
+ display: block;
116
+ font-size: 2rem;
117
+ font-weight: 700;
118
+ color: #6366f1;
119
+ }
120
+
121
+ .stat-label {
122
+ color: #666;
123
+ font-size: 0.875rem;
124
+ }
125
+
126
+ .features {
127
+ background: white;
128
+ padding: 2rem;
129
+ border-radius: 8px;
130
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
131
+ }
132
+
133
+ .features h2 {
134
+ margin-bottom: 1rem;
135
+ }
136
+
137
+ .features ul {
138
+ list-style: none;
139
+ }
140
+
141
+ .features li {
142
+ padding: 0.5rem 0;
143
+ border-bottom: 1px solid #eee;
144
+ }
145
+
146
+ .features li:last-child {
147
+ border-bottom: none;
148
+ }
149
+
150
+ .cta {
151
+ text-align: center;
152
+ margin-top: 2rem;
153
+ color: #666;
154
+ }
155
+
156
+ code {
157
+ background: #f0f0f0;
158
+ padding: 0.2rem 0.4rem;
159
+ border-radius: 4px;
160
+ font-family: monospace;
161
+ }
162
+
163
+ /* Users page */
164
+ .users-page h1 {
165
+ margin-bottom: 1rem;
166
+ }
167
+
168
+ .empty-state {
169
+ color: #666;
170
+ padding: 2rem;
171
+ text-align: center;
172
+ background: white;
173
+ border-radius: 8px;
174
+ }
175
+
176
+ .user-list {
177
+ list-style: none;
178
+ display: grid;
179
+ gap: 1rem;
180
+ }
181
+
182
+ .user-card {
183
+ background: white;
184
+ padding: 1rem;
185
+ border-radius: 8px;
186
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
187
+ display: flex;
188
+ justify-content: space-between;
189
+ align-items: center;
190
+ }
191
+
192
+ .user-name {
193
+ font-weight: 600;
194
+ }
195
+
196
+ .user-email {
197
+ color: #666;
198
+ }
199
+ `}</style>
200
+ </head>
201
+ <body>
202
+ <div className="layout">
203
+ <nav className="nav">
204
+ <ul className="nav-list">
205
+ <li>
206
+ <a href="/" className="nav-link">
207
+ Home
208
+ </a>
209
+ </li>
210
+ <li>
211
+ <a href="/users" className="nav-link">
212
+ Users
213
+ </a>
214
+ </li>
215
+ <li>
216
+ <a href="/settings" className="nav-link">
217
+ Settings
218
+ </a>
219
+ </li>
220
+ <li>
221
+ <a href="/docs/getting-started" className="nav-link">
222
+ Docs
223
+ </a>
224
+ </li>
225
+ <li>
226
+ <a href="/api/health" className="nav-link">
227
+ API
228
+ </a>
229
+ </li>
230
+ </ul>
231
+ </nav>
232
+
233
+ <main className="main">{children}</main>
234
+
235
+ <footer className="footer">Built with VeloxTS &bull; React Server Components</footer>
236
+ </div>
237
+ <script src="/_build/entry.client.js" type="module" />
238
+ </body>
239
+ </html>
240
+ );
241
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Profile Page
3
+ *
4
+ * A React Server Component for user profile management.
5
+ * Demonstrates route groups: (dashboard)/profile.tsx -> /profile
6
+ * Uses DashboardLayout via the (dashboard) route group.
7
+ */
8
+
9
+ interface PageProps {
10
+ params: Record<string, string>;
11
+ searchParams: Record<string, string | string[]>;
12
+ }
13
+
14
+ export default async function ProfilePage(_props: PageProps) {
15
+ // In a real app, this would come from auth context
16
+ const mockUser = {
17
+ name: 'Demo User',
18
+ email: 'demo@veloxts.dev',
19
+ role: 'Administrator',
20
+ joinedAt: new Date('2024-01-01'),
21
+ };
22
+
23
+ return (
24
+ <div className="profile-page">
25
+ <h1>Profile</h1>
26
+ <p className="page-description">
27
+ Manage your profile information. This page shares the DashboardLayout with Settings.
28
+ </p>
29
+
30
+ <section className="profile-card">
31
+ <div className="profile-avatar">
32
+ <span className="avatar-placeholder">{mockUser.name.charAt(0).toUpperCase()}</span>
33
+ </div>
34
+
35
+ <div className="profile-info">
36
+ <h2>{mockUser.name}</h2>
37
+ <p className="role">{mockUser.role}</p>
38
+ </div>
39
+ </section>
40
+
41
+ <section className="profile-details">
42
+ <h3>Account Details</h3>
43
+ <dl>
44
+ <dt>Email</dt>
45
+ <dd>{mockUser.email}</dd>
46
+
47
+ <dt>Role</dt>
48
+ <dd>{mockUser.role}</dd>
49
+
50
+ <dt>Member Since</dt>
51
+ <dd>{mockUser.joinedAt.toLocaleDateString()}</dd>
52
+ </dl>
53
+ </section>
54
+
55
+ <section className="profile-actions">
56
+ <h3>Quick Actions</h3>
57
+ <nav className="action-links">
58
+ <a href="/settings">Edit Settings</a>
59
+ <a href="/settings?tab=security">Change Password</a>
60
+ <a href="/users">View All Users</a>
61
+ </nav>
62
+ </section>
63
+
64
+ <footer className="page-footer">
65
+ <p>
66
+ <small>Route group: (dashboard) | Layout: DashboardLayout</small>
67
+ </p>
68
+ </footer>
69
+ </div>
70
+ );
71
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Settings Page
3
+ *
4
+ * A React Server Component for application settings.
5
+ * Demonstrates route groups: (dashboard)/settings.tsx -> /settings
6
+ * The (dashboard) folder groups related pages without affecting the URL.
7
+ */
8
+
9
+ interface PageProps {
10
+ params: Record<string, string>;
11
+ searchParams: Record<string, string | string[]>;
12
+ }
13
+
14
+ export default async function SettingsPage({ searchParams }: PageProps) {
15
+ const tab = (searchParams.tab as string) || 'general';
16
+
17
+ return (
18
+ <div className="settings-page">
19
+ <h1>Settings</h1>
20
+ <p className="page-description">
21
+ Manage your application settings. This page is in the (dashboard) route group.
22
+ </p>
23
+
24
+ <nav className="settings-tabs">
25
+ <a href="/settings?tab=general" className={tab === 'general' ? 'active' : ''}>
26
+ General
27
+ </a>
28
+ <a href="/settings?tab=notifications" className={tab === 'notifications' ? 'active' : ''}>
29
+ Notifications
30
+ </a>
31
+ <a href="/settings?tab=security" className={tab === 'security' ? 'active' : ''}>
32
+ Security
33
+ </a>
34
+ </nav>
35
+
36
+ <section className="settings-content">
37
+ {tab === 'general' && (
38
+ <div className="settings-section">
39
+ <h2>General Settings</h2>
40
+ <form className="settings-form">
41
+ <div className="form-group">
42
+ <label htmlFor="siteName">Site Name</label>
43
+ <input type="text" id="siteName" defaultValue="My VeloxTS App" />
44
+ </div>
45
+ <div className="form-group">
46
+ <label htmlFor="timezone">Timezone</label>
47
+ <select id="timezone" defaultValue="UTC">
48
+ <option value="UTC">UTC</option>
49
+ <option value="America/New_York">Eastern Time</option>
50
+ <option value="America/Los_Angeles">Pacific Time</option>
51
+ </select>
52
+ </div>
53
+ <button type="submit">Save Changes</button>
54
+ </form>
55
+ </div>
56
+ )}
57
+
58
+ {tab === 'notifications' && (
59
+ <div className="settings-section">
60
+ <h2>Notification Settings</h2>
61
+ <form className="settings-form">
62
+ <div className="form-group">
63
+ <label>
64
+ <input type="checkbox" defaultChecked /> Email notifications
65
+ </label>
66
+ </div>
67
+ <div className="form-group">
68
+ <label>
69
+ <input type="checkbox" /> Push notifications
70
+ </label>
71
+ </div>
72
+ <button type="submit">Save Changes</button>
73
+ </form>
74
+ </div>
75
+ )}
76
+
77
+ {tab === 'security' && (
78
+ <div className="settings-section">
79
+ <h2>Security Settings</h2>
80
+ <form className="settings-form">
81
+ <div className="form-group">
82
+ <label>
83
+ <input type="checkbox" defaultChecked /> Two-factor authentication
84
+ </label>
85
+ </div>
86
+ <div className="form-group">
87
+ <label>
88
+ <input type="checkbox" defaultChecked /> Session timeout after 30 minutes
89
+ </label>
90
+ </div>
91
+ <button type="submit">Save Changes</button>
92
+ </form>
93
+ </div>
94
+ )}
95
+ </section>
96
+
97
+ <footer className="page-footer">
98
+ <p>
99
+ <small>Route group: (dashboard) | Layout: DashboardLayout</small>
100
+ </p>
101
+ </footer>
102
+ </div>
103
+ );
104
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * About Page
3
+ *
4
+ * This page is in the (marketing) route group.
5
+ * The URL is /about (not /marketing/about).
6
+ *
7
+ * Route groups let you organize pages without affecting the URL structure.
8
+ * They're useful for:
9
+ * - Applying shared layouts to a subset of pages
10
+ * - Organizing pages by team or feature
11
+ * - Grouping related pages without nesting URLs
12
+ */
13
+
14
+ import type { PageProps } from '@veloxts/web';
15
+
16
+ export default function AboutPage({ params: _params }: PageProps) {
17
+ return (
18
+ <div className="page about-page">
19
+ <h1>About VeloxTS</h1>
20
+
21
+ <section className="about-section">
22
+ <h2>What is VeloxTS?</h2>
23
+ <p>
24
+ VeloxTS is a Laravel-inspired TypeScript full-stack web framework designed for exceptional
25
+ developer experience and type safety.
26
+ </p>
27
+ </section>
28
+
29
+ <section className="about-section">
30
+ <h2>Key Features</h2>
31
+ <ul>
32
+ <li>Type safety without code generation</li>
33
+ <li>React Server Components with streaming</li>
34
+ <li>File-based routing with route groups</li>
35
+ <li>Built on Fastify, tRPC, and Prisma</li>
36
+ </ul>
37
+ </section>
38
+
39
+ <section className="about-section route-group-demo">
40
+ <h2>Route Groups Demo</h2>
41
+ <p>
42
+ This page lives at <code>app/pages/(marketing)/about.tsx</code> but is served at{' '}
43
+ <code>/about</code>.
44
+ </p>
45
+ <p>
46
+ The <code>(marketing)</code> directory is a route group - it organizes files without
47
+ affecting the URL structure.
48
+ </p>
49
+ </section>
50
+ </div>
51
+ );
52
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * 404 Not Found Page
3
+ *
4
+ * This page is displayed when no route matches the requested URL.
5
+ * The _not-found.tsx naming convention is recognized by the file router.
6
+ */
7
+
8
+ interface PageProps {
9
+ params: Record<string, string>;
10
+ searchParams: Record<string, string | string[]>;
11
+ }
12
+
13
+ export default async function NotFoundPage(_props: PageProps) {
14
+ return (
15
+ <div className="not-found-page">
16
+ <style>{`
17
+ .not-found-page {
18
+ text-align: center;
19
+ padding: 4rem 2rem;
20
+ min-height: 60vh;
21
+ display: flex;
22
+ flex-direction: column;
23
+ justify-content: center;
24
+ align-items: center;
25
+ }
26
+
27
+ .error-code {
28
+ font-size: 8rem;
29
+ font-weight: 700;
30
+ color: #e0e0e0;
31
+ line-height: 1;
32
+ margin-bottom: 1rem;
33
+ }
34
+
35
+ .not-found-page h1 {
36
+ font-size: 2rem;
37
+ color: #1a1a2e;
38
+ margin-bottom: 0.5rem;
39
+ }
40
+
41
+ .not-found-page p {
42
+ color: #666;
43
+ max-width: 400px;
44
+ margin-bottom: 2rem;
45
+ }
46
+
47
+ .action-links {
48
+ display: flex;
49
+ gap: 1rem;
50
+ }
51
+
52
+ .action-links a {
53
+ padding: 0.75rem 1.5rem;
54
+ border-radius: 8px;
55
+ text-decoration: none;
56
+ font-weight: 500;
57
+ transition: all 0.2s;
58
+ }
59
+
60
+ .action-links .primary {
61
+ background: #6366f1;
62
+ color: white;
63
+ }
64
+
65
+ .action-links .primary:hover {
66
+ background: #4f46e5;
67
+ }
68
+
69
+ .action-links .secondary {
70
+ background: #f0f0f0;
71
+ color: #1a1a2e;
72
+ }
73
+
74
+ .action-links .secondary:hover {
75
+ background: #e0e0e0;
76
+ }
77
+
78
+ .suggestions {
79
+ margin-top: 3rem;
80
+ padding-top: 2rem;
81
+ border-top: 1px solid #eee;
82
+ color: #888;
83
+ }
84
+
85
+ .suggestions h3 {
86
+ font-size: 0.875rem;
87
+ text-transform: uppercase;
88
+ margin-bottom: 1rem;
89
+ }
90
+
91
+ .suggestions ul {
92
+ list-style: none;
93
+ display: flex;
94
+ gap: 1rem;
95
+ flex-wrap: wrap;
96
+ justify-content: center;
97
+ }
98
+
99
+ .suggestions a {
100
+ color: #6366f1;
101
+ text-decoration: none;
102
+ }
103
+
104
+ .suggestions a:hover {
105
+ text-decoration: underline;
106
+ }
107
+ `}</style>
108
+
109
+ <div className="error-code">404</div>
110
+
111
+ <h1>Page Not Found</h1>
112
+
113
+ <p>
114
+ The page you're looking for doesn't exist or has been moved. Check the URL or navigate using
115
+ the links below.
116
+ </p>
117
+
118
+ <div className="action-links">
119
+ <a href="/" className="primary">
120
+ Go Home
121
+ </a>
122
+ <a href="/users" className="secondary">
123
+ View Users
124
+ </a>
125
+ </div>
126
+
127
+ <div className="suggestions">
128
+ <h3>Popular Pages</h3>
129
+ <ul>
130
+ <li>
131
+ <a href="/">Home</a>
132
+ </li>
133
+ <li>
134
+ <a href="/users">Users</a>
135
+ </li>
136
+ <li>
137
+ <a href="/settings">Settings</a>
138
+ </li>
139
+ <li>
140
+ <a href="/profile">Profile</a>
141
+ </li>
142
+ <li>
143
+ <a href="/docs/getting-started">Documentation</a>
144
+ </li>
145
+ </ul>
146
+ </div>
147
+ </div>
148
+ );
149
+ }