create-velox-app 0.6.31 → 0.6.51
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 +120 -0
- package/GUIDE.md +230 -0
- package/dist/cli.js +1 -0
- package/dist/index.js +14 -4
- package/dist/templates/auth.js +10 -0
- package/dist/templates/index.js +30 -1
- package/dist/templates/placeholders.js +0 -3
- package/dist/templates/rsc-auth.d.ts +12 -0
- package/dist/templates/rsc-auth.js +208 -0
- package/dist/templates/rsc.js +40 -1
- package/dist/templates/shared/css-generator.d.ts +26 -0
- package/dist/templates/shared/css-generator.js +553 -0
- package/dist/templates/shared/index.d.ts +3 -0
- package/dist/templates/shared/index.js +3 -0
- package/dist/templates/shared/rsc-styles.d.ts +54 -0
- package/dist/templates/shared/rsc-styles.js +68 -0
- package/dist/templates/shared/theme.d.ts +133 -0
- package/dist/templates/shared/theme.js +141 -0
- package/dist/templates/spa.js +10 -0
- package/dist/templates/trpc.js +10 -0
- package/dist/templates/types.d.ts +2 -1
- package/dist/templates/types.js +6 -0
- package/package.json +6 -3
- package/src/templates/source/api/config/database.ts +13 -32
- package/src/templates/source/api/docker-compose.yml +21 -0
- package/src/templates/source/root/CLAUDE.auth.md +6 -0
- package/src/templates/source/root/CLAUDE.default.md +6 -0
- package/src/templates/source/rsc/CLAUDE.md +56 -2
- package/src/templates/source/rsc/app/actions/posts.ts +1 -1
- package/src/templates/source/rsc/app/actions/users.ts +111 -20
- package/src/templates/source/rsc/app/layouts/dashboard.tsx +21 -16
- package/src/templates/source/rsc/app/layouts/marketing.tsx +34 -0
- package/src/templates/source/rsc/app/layouts/minimal-content.tsx +21 -0
- package/src/templates/source/rsc/app/layouts/minimal.tsx +86 -5
- package/src/templates/source/rsc/app/layouts/root.tsx +148 -44
- package/src/templates/source/rsc/docker-compose.yml +21 -0
- package/src/templates/source/rsc/package.json +3 -3
- package/src/templates/source/rsc/src/api/database.ts +13 -32
- package/src/templates/source/rsc/src/api/handler.ts +1 -1
- package/src/templates/source/rsc/src/entry.client.tsx +65 -18
- package/src/templates/source/rsc-auth/CLAUDE.md +230 -0
- package/src/templates/source/rsc-auth/app/actions/auth.ts +112 -0
- package/src/templates/source/rsc-auth/app/actions/users.ts +289 -0
- package/src/templates/source/rsc-auth/app/layouts/dashboard.tsx +132 -0
- package/src/templates/source/rsc-auth/app/layouts/marketing.tsx +59 -0
- package/src/templates/source/rsc-auth/app/layouts/minimal-content.tsx +21 -0
- package/src/templates/source/rsc-auth/app/layouts/minimal.tsx +111 -0
- package/src/templates/source/rsc-auth/app/layouts/root.tsx +355 -0
- package/src/templates/source/rsc-auth/app/pages/_not-found.tsx +15 -0
- package/src/templates/source/rsc-auth/app/pages/auth/login.tsx +198 -0
- package/src/templates/source/rsc-auth/app/pages/auth/register.tsx +225 -0
- package/src/templates/source/rsc-auth/app/pages/dashboard/index.tsx +267 -0
- package/src/templates/source/rsc-auth/app/pages/index.tsx +83 -0
- package/src/templates/source/rsc-auth/app/pages/users.tsx +47 -0
- package/src/templates/source/rsc-auth/app.config.ts +12 -0
- package/src/templates/source/rsc-auth/docker-compose.yml +21 -0
- package/src/templates/source/rsc-auth/env.example +11 -0
- package/src/templates/source/rsc-auth/gitignore +34 -0
- package/src/templates/source/rsc-auth/package.json +44 -0
- package/src/templates/source/rsc-auth/prisma/schema.prisma +23 -0
- package/src/templates/source/rsc-auth/prisma.config.ts +22 -0
- package/src/templates/source/rsc-auth/public/favicon.svg +4 -0
- package/src/templates/source/rsc-auth/src/api/database.ts +129 -0
- package/src/templates/source/rsc-auth/src/api/handler.ts +85 -0
- package/src/templates/source/rsc-auth/src/api/procedures/auth.ts +262 -0
- package/src/templates/source/rsc-auth/src/api/procedures/health.ts +48 -0
- package/src/templates/source/rsc-auth/src/api/procedures/users.ts +87 -0
- package/src/templates/source/rsc-auth/src/api/schemas/auth.ts +79 -0
- package/src/templates/source/rsc-auth/src/api/schemas/user.ts +38 -0
- package/src/templates/source/rsc-auth/src/api/utils/auth.ts +157 -0
- package/src/templates/source/rsc-auth/src/entry.client.tsx +63 -0
- package/src/templates/source/rsc-auth/src/entry.server.tsx +262 -0
- package/src/templates/source/rsc-auth/tsconfig.json +24 -0
- package/src/templates/source/shared/scripts/check-client-imports.sh +75 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS Generator Functions
|
|
3
|
+
*
|
|
4
|
+
* Generates CSS strings from the theme design system.
|
|
5
|
+
* These functions provide consistent dark mode styling across all RSC templates.
|
|
6
|
+
*/
|
|
7
|
+
import { colors, layout, spacing, transitions, typography } from './theme.js';
|
|
8
|
+
/**
|
|
9
|
+
* Global CSS reset and base styles for dark mode
|
|
10
|
+
*/
|
|
11
|
+
export function generateGlobalReset() {
|
|
12
|
+
return `
|
|
13
|
+
*,
|
|
14
|
+
*::before,
|
|
15
|
+
*::after {
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
font: inherit;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
html {
|
|
23
|
+
font-size: 16px;
|
|
24
|
+
-webkit-font-smoothing: antialiased;
|
|
25
|
+
-moz-osx-font-smoothing: grayscale;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
body {
|
|
29
|
+
background: ${colors.background};
|
|
30
|
+
color: ${colors.text};
|
|
31
|
+
font-family: ${typography.fontFamily.sans};
|
|
32
|
+
line-height: ${typography.lineHeight.normal};
|
|
33
|
+
min-height: 100svh;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
h1, h2, h3, h4, h5, h6 {
|
|
37
|
+
text-wrap: balance;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
p, li, figcaption {
|
|
41
|
+
text-wrap: pretty;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
img, picture, svg, video, canvas {
|
|
45
|
+
max-width: 100%;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
a {
|
|
49
|
+
color: ${colors.accent};
|
|
50
|
+
text-decoration: none;
|
|
51
|
+
transition: opacity ${transitions.normal};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
a:hover {
|
|
55
|
+
opacity: 0.8;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
code {
|
|
59
|
+
font-family: ${typography.fontFamily.mono};
|
|
60
|
+
background: ${colors.codeBg};
|
|
61
|
+
padding: 0.2em 0.4em;
|
|
62
|
+
border-radius: ${layout.borderRadius.sm};
|
|
63
|
+
font-size: ${typography.fontSize.md};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
::selection {
|
|
67
|
+
background: ${colors.selection};
|
|
68
|
+
color: ${colors.selectionText};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
::-webkit-scrollbar {
|
|
72
|
+
width: 8px;
|
|
73
|
+
height: 8px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
::-webkit-scrollbar-track {
|
|
77
|
+
background: ${colors.scrollbarTrack};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
::-webkit-scrollbar-thumb {
|
|
81
|
+
background: ${colors.scrollbarThumb};
|
|
82
|
+
border-radius: ${layout.borderRadius.sm};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
::-webkit-scrollbar-thumb:hover {
|
|
86
|
+
background: ${colors.scrollbarThumbHover};
|
|
87
|
+
}
|
|
88
|
+
`.trim();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Root layout styles - Navigation, footer, and main content area
|
|
92
|
+
*/
|
|
93
|
+
export function generateRscRootStyles() {
|
|
94
|
+
return `
|
|
95
|
+
${generateGlobalReset()}
|
|
96
|
+
|
|
97
|
+
.layout {
|
|
98
|
+
min-height: 100vh;
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: column;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.nav {
|
|
104
|
+
background: ${colors.surface};
|
|
105
|
+
padding: ${spacing[4]} ${spacing[8]};
|
|
106
|
+
border-bottom: 1px solid ${colors.border};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.nav-list {
|
|
110
|
+
display: flex;
|
|
111
|
+
gap: ${spacing[8]};
|
|
112
|
+
list-style: none;
|
|
113
|
+
max-width: ${layout.maxWidth};
|
|
114
|
+
margin: 0 auto;
|
|
115
|
+
align-items: center;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.nav-link {
|
|
119
|
+
color: ${colors.text};
|
|
120
|
+
text-decoration: none;
|
|
121
|
+
font-weight: ${typography.fontWeight.medium};
|
|
122
|
+
transition: color ${transitions.normal};
|
|
123
|
+
padding: ${spacing[2]} ${spacing[3]};
|
|
124
|
+
border-radius: ${layout.borderRadius.sm};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.nav-link:hover {
|
|
128
|
+
color: ${colors.accent};
|
|
129
|
+
background: ${colors.surfaceHover};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.main {
|
|
133
|
+
flex: 1;
|
|
134
|
+
padding: ${spacing[8]};
|
|
135
|
+
max-width: ${layout.maxWidth};
|
|
136
|
+
margin: 0 auto;
|
|
137
|
+
width: 100%;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.footer {
|
|
141
|
+
background: ${colors.surface};
|
|
142
|
+
color: ${colors.textMuted};
|
|
143
|
+
text-align: center;
|
|
144
|
+
padding: ${spacing[4]};
|
|
145
|
+
font-size: ${typography.fontSize.base};
|
|
146
|
+
border-top: 1px solid ${colors.border};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Home page hero section */
|
|
150
|
+
.home-page .hero {
|
|
151
|
+
text-align: center;
|
|
152
|
+
padding: ${spacing[12]} 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.home-page h1 {
|
|
156
|
+
font-size: ${typography.fontSize['4xl']};
|
|
157
|
+
margin-bottom: ${spacing[3]};
|
|
158
|
+
font-weight: ${typography.fontWeight.bold};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.home-page .tagline {
|
|
162
|
+
color: ${colors.textMuted};
|
|
163
|
+
font-size: ${typography.fontSize.xl};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* Stats cards */
|
|
167
|
+
.stats {
|
|
168
|
+
display: flex;
|
|
169
|
+
gap: ${spacing[4]};
|
|
170
|
+
justify-content: center;
|
|
171
|
+
margin: ${spacing[8]} 0;
|
|
172
|
+
flex-wrap: wrap;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.stat-card {
|
|
176
|
+
background: ${colors.surface};
|
|
177
|
+
padding: ${spacing[6]} ${spacing[8]};
|
|
178
|
+
border-radius: ${layout.borderRadius.lg};
|
|
179
|
+
border: 1px solid ${colors.border};
|
|
180
|
+
text-align: center;
|
|
181
|
+
min-width: 150px;
|
|
182
|
+
transition: border-color ${transitions.normal};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.stat-card:hover {
|
|
186
|
+
border-color: ${colors.accent};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.stat-value {
|
|
190
|
+
display: block;
|
|
191
|
+
font-size: ${typography.fontSize['3xl']};
|
|
192
|
+
font-weight: ${typography.fontWeight.bold};
|
|
193
|
+
color: ${colors.accent};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.stat-label {
|
|
197
|
+
color: ${colors.textMuted};
|
|
198
|
+
font-size: ${typography.fontSize.base};
|
|
199
|
+
margin-top: ${spacing[2]};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Features section */
|
|
203
|
+
.features {
|
|
204
|
+
background: ${colors.surface};
|
|
205
|
+
padding: ${spacing[8]};
|
|
206
|
+
border-radius: ${layout.borderRadius.lg};
|
|
207
|
+
border: 1px solid ${colors.border};
|
|
208
|
+
margin-top: ${spacing[8]};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.features h2 {
|
|
212
|
+
margin-bottom: ${spacing[6]};
|
|
213
|
+
font-size: ${typography.fontSize['2xl']};
|
|
214
|
+
font-weight: ${typography.fontWeight.semibold};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.features ul {
|
|
218
|
+
list-style: none;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.features li {
|
|
222
|
+
padding: ${spacing[3]} 0;
|
|
223
|
+
border-bottom: 1px solid ${colors.border};
|
|
224
|
+
color: ${colors.text};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.features li:last-child {
|
|
228
|
+
border-bottom: none;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.cta {
|
|
232
|
+
text-align: center;
|
|
233
|
+
margin-top: ${spacing[8]};
|
|
234
|
+
color: ${colors.textMuted};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* Users page */
|
|
238
|
+
.users-page h1 {
|
|
239
|
+
margin-bottom: ${spacing[6]};
|
|
240
|
+
font-size: ${typography.fontSize['3xl']};
|
|
241
|
+
font-weight: ${typography.fontWeight.bold};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.empty-state {
|
|
245
|
+
color: ${colors.textMuted};
|
|
246
|
+
padding: ${spacing[8]};
|
|
247
|
+
text-align: center;
|
|
248
|
+
background: ${colors.surface};
|
|
249
|
+
border-radius: ${layout.borderRadius.lg};
|
|
250
|
+
border: 1px solid ${colors.border};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.user-list {
|
|
254
|
+
list-style: none;
|
|
255
|
+
display: grid;
|
|
256
|
+
gap: ${spacing[4]};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.user-card {
|
|
260
|
+
background: ${colors.surface};
|
|
261
|
+
padding: ${spacing[4]};
|
|
262
|
+
border-radius: ${layout.borderRadius.lg};
|
|
263
|
+
border: 1px solid ${colors.border};
|
|
264
|
+
display: flex;
|
|
265
|
+
justify-content: space-between;
|
|
266
|
+
align-items: center;
|
|
267
|
+
transition: border-color ${transitions.normal};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.user-card:hover {
|
|
271
|
+
border-color: ${colors.accent};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.user-name {
|
|
275
|
+
font-weight: ${typography.fontWeight.semibold};
|
|
276
|
+
color: ${colors.text};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.user-email {
|
|
280
|
+
color: ${colors.textMuted};
|
|
281
|
+
font-size: ${typography.fontSize.base};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* About page */
|
|
285
|
+
.about-page h1 {
|
|
286
|
+
font-size: ${typography.fontSize['3xl']};
|
|
287
|
+
margin-bottom: ${spacing[6]};
|
|
288
|
+
font-weight: ${typography.fontWeight.bold};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.about-page h2 {
|
|
292
|
+
font-size: ${typography.fontSize['2xl']};
|
|
293
|
+
margin-top: ${spacing[8]};
|
|
294
|
+
margin-bottom: ${spacing[4]};
|
|
295
|
+
font-weight: ${typography.fontWeight.semibold};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.about-page p {
|
|
299
|
+
color: ${colors.textMuted};
|
|
300
|
+
margin-bottom: ${spacing[4]};
|
|
301
|
+
line-height: ${typography.lineHeight.relaxed};
|
|
302
|
+
}
|
|
303
|
+
`.trim();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Dashboard layout styles - Sidebar navigation
|
|
307
|
+
*/
|
|
308
|
+
export function generateRscDashboardStyles() {
|
|
309
|
+
return `
|
|
310
|
+
.dashboard-layout {
|
|
311
|
+
display: flex;
|
|
312
|
+
gap: ${spacing[8]};
|
|
313
|
+
min-height: 60vh;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.dashboard-sidebar {
|
|
317
|
+
width: ${layout.sidebarWidth};
|
|
318
|
+
flex-shrink: 0;
|
|
319
|
+
background: ${colors.surface};
|
|
320
|
+
border-radius: ${layout.borderRadius.lg};
|
|
321
|
+
padding: ${spacing[6]};
|
|
322
|
+
border: 1px solid ${colors.border};
|
|
323
|
+
height: fit-content;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.dashboard-sidebar h3 {
|
|
327
|
+
font-size: ${typography.fontSize.sm};
|
|
328
|
+
text-transform: uppercase;
|
|
329
|
+
color: ${colors.textMuted};
|
|
330
|
+
margin-bottom: ${spacing[3]};
|
|
331
|
+
padding: 0 ${spacing[3]};
|
|
332
|
+
font-weight: ${typography.fontWeight.semibold};
|
|
333
|
+
letter-spacing: 0.05em;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.sidebar-nav {
|
|
337
|
+
list-style: none;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.sidebar-nav a {
|
|
341
|
+
display: block;
|
|
342
|
+
padding: ${spacing[3]};
|
|
343
|
+
color: ${colors.text};
|
|
344
|
+
text-decoration: none;
|
|
345
|
+
border-radius: ${layout.borderRadius.sm};
|
|
346
|
+
transition: background ${transitions.normal};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.sidebar-nav a:hover {
|
|
350
|
+
background: ${colors.surfaceHover};
|
|
351
|
+
color: ${colors.accent};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.sidebar-nav a.active {
|
|
355
|
+
background: ${colors.accent};
|
|
356
|
+
color: ${colors.textInverse};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.dashboard-content {
|
|
360
|
+
flex: 1;
|
|
361
|
+
background: ${colors.surface};
|
|
362
|
+
border-radius: ${layout.borderRadius.lg};
|
|
363
|
+
padding: ${spacing[6]};
|
|
364
|
+
border: 1px solid ${colors.border};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.dashboard-badge {
|
|
368
|
+
display: inline-block;
|
|
369
|
+
background: ${colors.accent};
|
|
370
|
+
color: ${colors.textInverse};
|
|
371
|
+
font-size: ${typography.fontSize.xs};
|
|
372
|
+
text-transform: uppercase;
|
|
373
|
+
padding: ${spacing[2]} ${spacing[3]};
|
|
374
|
+
border-radius: ${layout.borderRadius.sm};
|
|
375
|
+
margin-bottom: ${spacing[4]};
|
|
376
|
+
font-weight: ${typography.fontWeight.semibold};
|
|
377
|
+
letter-spacing: 0.05em;
|
|
378
|
+
}
|
|
379
|
+
`.trim();
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Minimal layout styles - For auth pages, centered content
|
|
383
|
+
*/
|
|
384
|
+
export function generateRscMinimalStyles() {
|
|
385
|
+
return `
|
|
386
|
+
${generateGlobalReset()}
|
|
387
|
+
|
|
388
|
+
.minimal-body {
|
|
389
|
+
min-height: 100vh;
|
|
390
|
+
display: flex;
|
|
391
|
+
align-items: center;
|
|
392
|
+
justify-content: center;
|
|
393
|
+
padding: ${spacing[8]};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.minimal-content {
|
|
397
|
+
width: 100%;
|
|
398
|
+
max-width: 450px;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* Auth card container */
|
|
402
|
+
.auth-card {
|
|
403
|
+
background: ${colors.surface};
|
|
404
|
+
padding: ${spacing[8]};
|
|
405
|
+
border-radius: ${layout.borderRadius.lg};
|
|
406
|
+
border: 1px solid ${colors.border};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.auth-card h1 {
|
|
410
|
+
font-size: ${typography.fontSize['2xl']};
|
|
411
|
+
font-weight: ${typography.fontWeight.bold};
|
|
412
|
+
margin-bottom: ${spacing[6]};
|
|
413
|
+
text-align: center;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Form styles */
|
|
417
|
+
.auth-form {
|
|
418
|
+
margin-top: ${spacing[6]};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.form-group {
|
|
422
|
+
margin-bottom: ${spacing[5]};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.form-label {
|
|
426
|
+
display: block;
|
|
427
|
+
margin-bottom: ${spacing[2]};
|
|
428
|
+
color: ${colors.text};
|
|
429
|
+
font-weight: ${typography.fontWeight.medium};
|
|
430
|
+
font-size: ${typography.fontSize.base};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.form-input {
|
|
434
|
+
width: 100%;
|
|
435
|
+
padding: ${spacing[3]} ${spacing[4]};
|
|
436
|
+
border-radius: ${layout.borderRadius.sm};
|
|
437
|
+
border: 1px solid ${colors.border};
|
|
438
|
+
background: ${colors.background};
|
|
439
|
+
color: ${colors.text};
|
|
440
|
+
font-size: ${typography.fontSize.base};
|
|
441
|
+
transition: border-color ${transitions.normal}, background ${transitions.normal};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.form-input:focus {
|
|
445
|
+
outline: none;
|
|
446
|
+
border-color: ${colors.borderFocus};
|
|
447
|
+
background: ${colors.surface};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.form-input:hover {
|
|
451
|
+
border-color: ${colors.borderHover};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.form-hint {
|
|
455
|
+
display: block;
|
|
456
|
+
color: ${colors.textMuted};
|
|
457
|
+
font-size: ${typography.fontSize.sm};
|
|
458
|
+
margin-top: ${spacing[2]};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* Buttons */
|
|
462
|
+
.btn {
|
|
463
|
+
width: 100%;
|
|
464
|
+
padding: ${spacing[3]} ${spacing[5]};
|
|
465
|
+
border: none;
|
|
466
|
+
border-radius: ${layout.borderRadius.sm};
|
|
467
|
+
cursor: pointer;
|
|
468
|
+
font-weight: ${typography.fontWeight.medium};
|
|
469
|
+
font-size: ${typography.fontSize.base};
|
|
470
|
+
transition: background ${transitions.normal}, opacity ${transitions.normal};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.btn-primary {
|
|
474
|
+
background: ${colors.accent};
|
|
475
|
+
color: ${colors.textInverse};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.btn-primary:hover:not(:disabled) {
|
|
479
|
+
background: ${colors.accentHover};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.btn-primary:disabled {
|
|
483
|
+
opacity: 0.6;
|
|
484
|
+
cursor: not-allowed;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/* Error message */
|
|
488
|
+
.error-message {
|
|
489
|
+
padding: ${spacing[3]};
|
|
490
|
+
background: ${colors.errorBg};
|
|
491
|
+
color: ${colors.errorText};
|
|
492
|
+
border-radius: ${layout.borderRadius.sm};
|
|
493
|
+
margin-bottom: ${spacing[4]};
|
|
494
|
+
border: 1px solid ${colors.error};
|
|
495
|
+
font-size: ${typography.fontSize.base};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* Footer text */
|
|
499
|
+
.auth-footer {
|
|
500
|
+
margin-top: ${spacing[6]};
|
|
501
|
+
text-align: center;
|
|
502
|
+
color: ${colors.textMuted};
|
|
503
|
+
font-size: ${typography.fontSize.base};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.auth-footer a {
|
|
507
|
+
color: ${colors.accent};
|
|
508
|
+
font-weight: ${typography.fontWeight.medium};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.auth-footer a:hover {
|
|
512
|
+
opacity: 0.8;
|
|
513
|
+
}
|
|
514
|
+
`.trim();
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Marketing layout styles - Banner/badge
|
|
518
|
+
*/
|
|
519
|
+
export function generateRscMarketingStyles() {
|
|
520
|
+
return `
|
|
521
|
+
.marketing-layout {
|
|
522
|
+
position: relative;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.marketing-banner {
|
|
526
|
+
background: ${colors.surface};
|
|
527
|
+
border: 1px solid ${colors.border};
|
|
528
|
+
border-radius: ${layout.borderRadius.lg};
|
|
529
|
+
padding: ${spacing[4]} ${spacing[6]};
|
|
530
|
+
margin-bottom: ${spacing[6]};
|
|
531
|
+
display: flex;
|
|
532
|
+
align-items: center;
|
|
533
|
+
gap: ${spacing[4]};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.marketing-banner .badge {
|
|
537
|
+
display: inline-block;
|
|
538
|
+
background: ${colors.accent};
|
|
539
|
+
color: ${colors.textInverse};
|
|
540
|
+
font-size: ${typography.fontSize.xs};
|
|
541
|
+
text-transform: uppercase;
|
|
542
|
+
padding: ${spacing[2]} ${spacing[3]};
|
|
543
|
+
border-radius: ${layout.borderRadius.sm};
|
|
544
|
+
font-weight: ${typography.fontWeight.semibold};
|
|
545
|
+
letter-spacing: 0.05em;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.marketing-banner span:not(.badge) {
|
|
549
|
+
color: ${colors.textMuted};
|
|
550
|
+
font-size: ${typography.fontSize.base};
|
|
551
|
+
}
|
|
552
|
+
`.trim();
|
|
553
|
+
}
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Re-exports all shared template generators for workspace projects.
|
|
5
5
|
*/
|
|
6
|
+
export * from './css-generator.js';
|
|
6
7
|
export * from './root.js';
|
|
8
|
+
export * from './rsc-styles.js';
|
|
9
|
+
export * from './theme.js';
|
|
7
10
|
export * from './web-base.js';
|
|
8
11
|
export * from './web-styles.js';
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Re-exports all shared template generators for workspace projects.
|
|
5
5
|
*/
|
|
6
|
+
export * from './css-generator.js';
|
|
6
7
|
export * from './root.js';
|
|
8
|
+
export * from './rsc-styles.js';
|
|
9
|
+
export * from './theme.js';
|
|
7
10
|
export * from './web-base.js';
|
|
8
11
|
export * from './web-styles.js';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSC Navigation Configurations
|
|
3
|
+
*
|
|
4
|
+
* Provides navigation item configs for RSC templates.
|
|
5
|
+
* Separates basic RSC nav from auth-aware RSC nav.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Navigation item structure
|
|
9
|
+
*/
|
|
10
|
+
export interface NavItem {
|
|
11
|
+
href: string;
|
|
12
|
+
label: string;
|
|
13
|
+
authRequired?: boolean;
|
|
14
|
+
guestOnly?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Navigation items for basic RSC template (no auth)
|
|
18
|
+
*
|
|
19
|
+
* Routes:
|
|
20
|
+
* - / (Home)
|
|
21
|
+
* - /users (Users list)
|
|
22
|
+
* - /about (About page)
|
|
23
|
+
* - /docs/getting-started (Documentation)
|
|
24
|
+
*/
|
|
25
|
+
export declare const RSC_NAV_ITEMS: NavItem[];
|
|
26
|
+
/**
|
|
27
|
+
* Navigation items for RSC-Auth template (with authentication)
|
|
28
|
+
*
|
|
29
|
+
* Routes:
|
|
30
|
+
* - / (Home)
|
|
31
|
+
* - /users (Users list)
|
|
32
|
+
* - /dashboard (Dashboard - auth required)
|
|
33
|
+
* - /auth/login (Login - guest only)
|
|
34
|
+
* - /auth/register (Register - guest only)
|
|
35
|
+
*/
|
|
36
|
+
export declare const RSC_AUTH_NAV_ITEMS: NavItem[];
|
|
37
|
+
/**
|
|
38
|
+
* Filter navigation items based on authentication status
|
|
39
|
+
*
|
|
40
|
+
* @param items - Full navigation items list
|
|
41
|
+
* @param isAuthenticated - Whether the user is authenticated
|
|
42
|
+
* @returns Filtered navigation items
|
|
43
|
+
*/
|
|
44
|
+
export declare function filterNavByAuth(items: NavItem[], isAuthenticated: boolean): NavItem[];
|
|
45
|
+
/**
|
|
46
|
+
* Detect authentication from cookie header (server-side)
|
|
47
|
+
*
|
|
48
|
+
* This is a simple cookie-based auth detection for navigation purposes.
|
|
49
|
+
* The actual auth validation happens in the API layer.
|
|
50
|
+
*
|
|
51
|
+
* @param cookieHeader - Cookie header string from request
|
|
52
|
+
* @returns Whether an access token cookie exists
|
|
53
|
+
*/
|
|
54
|
+
export declare function hasAuthToken(cookieHeader: string | undefined | null): boolean;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSC Navigation Configurations
|
|
3
|
+
*
|
|
4
|
+
* Provides navigation item configs for RSC templates.
|
|
5
|
+
* Separates basic RSC nav from auth-aware RSC nav.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Navigation items for basic RSC template (no auth)
|
|
9
|
+
*
|
|
10
|
+
* Routes:
|
|
11
|
+
* - / (Home)
|
|
12
|
+
* - /users (Users list)
|
|
13
|
+
* - /about (About page)
|
|
14
|
+
* - /docs/getting-started (Documentation)
|
|
15
|
+
*/
|
|
16
|
+
export const RSC_NAV_ITEMS = [
|
|
17
|
+
{ href: '/', label: 'Home' },
|
|
18
|
+
{ href: '/users', label: 'Users' },
|
|
19
|
+
{ href: '/about', label: 'About' },
|
|
20
|
+
{ href: '/docs/getting-started', label: 'Docs' },
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Navigation items for RSC-Auth template (with authentication)
|
|
24
|
+
*
|
|
25
|
+
* Routes:
|
|
26
|
+
* - / (Home)
|
|
27
|
+
* - /users (Users list)
|
|
28
|
+
* - /dashboard (Dashboard - auth required)
|
|
29
|
+
* - /auth/login (Login - guest only)
|
|
30
|
+
* - /auth/register (Register - guest only)
|
|
31
|
+
*/
|
|
32
|
+
export const RSC_AUTH_NAV_ITEMS = [
|
|
33
|
+
{ href: '/', label: 'Home' },
|
|
34
|
+
{ href: '/users', label: 'Users' },
|
|
35
|
+
{ href: '/dashboard', label: 'Dashboard', authRequired: true },
|
|
36
|
+
{ href: '/auth/login', label: 'Login', guestOnly: true },
|
|
37
|
+
{ href: '/auth/register', label: 'Register', guestOnly: true },
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Filter navigation items based on authentication status
|
|
41
|
+
*
|
|
42
|
+
* @param items - Full navigation items list
|
|
43
|
+
* @param isAuthenticated - Whether the user is authenticated
|
|
44
|
+
* @returns Filtered navigation items
|
|
45
|
+
*/
|
|
46
|
+
export function filterNavByAuth(items, isAuthenticated) {
|
|
47
|
+
return items.filter((item) => {
|
|
48
|
+
if (item.authRequired && !isAuthenticated)
|
|
49
|
+
return false;
|
|
50
|
+
if (item.guestOnly && isAuthenticated)
|
|
51
|
+
return false;
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect authentication from cookie header (server-side)
|
|
57
|
+
*
|
|
58
|
+
* This is a simple cookie-based auth detection for navigation purposes.
|
|
59
|
+
* The actual auth validation happens in the API layer.
|
|
60
|
+
*
|
|
61
|
+
* @param cookieHeader - Cookie header string from request
|
|
62
|
+
* @returns Whether an access token cookie exists
|
|
63
|
+
*/
|
|
64
|
+
export function hasAuthToken(cookieHeader) {
|
|
65
|
+
if (!cookieHeader)
|
|
66
|
+
return false;
|
|
67
|
+
return cookieHeader.includes('accessToken=');
|
|
68
|
+
}
|