create-frootkit 1.2.1 → 1.2.2
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/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/templates/auth.d.ts +0 -3
- package/dist/templates/auth.d.ts.map +0 -1
- package/dist/templates/auth.js +0 -487
- package/dist/templates/auth.js.map +0 -1
- package/dist/templates/blog.d.ts +0 -3
- package/dist/templates/blog.d.ts.map +0 -1
- package/dist/templates/blog.js +0 -369
- package/dist/templates/blog.js.map +0 -1
- package/dist/templates/common.d.ts +0 -5
- package/dist/templates/common.d.ts.map +0 -1
- package/dist/templates/common.js +0 -116
- package/dist/templates/common.js.map +0 -1
- package/dist/templates/ecommerce.d.ts +0 -3
- package/dist/templates/ecommerce.d.ts.map +0 -1
- package/dist/templates/ecommerce.js +0 -474
- package/dist/templates/ecommerce.js.map +0 -1
- package/dist/templates/empty.d.ts +0 -3
- package/dist/templates/empty.d.ts.map +0 -1
- package/dist/templates/empty.js +0 -85
- package/dist/templates/empty.js.map +0 -1
- package/dist/templates/starter.d.ts +0 -3
- package/dist/templates/starter.d.ts.map +0 -1
- package/dist/templates/starter.js +0 -308
- package/dist/templates/starter.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { scaffoldProject } from './scaffold.js';
|
|
|
11
11
|
export * from './template.js';
|
|
12
12
|
export * from './scaffold.js';
|
|
13
13
|
export * from './ui.js';
|
|
14
|
-
const VERSION = '1.2.
|
|
14
|
+
const VERSION = '1.2.2';
|
|
15
15
|
function parseCliArgs(argv) {
|
|
16
16
|
const raw = argv.slice(2);
|
|
17
17
|
const args = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-frootkit",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Interactive CLI for scaffolding high-performance FrootKit (Next.js Alternative) applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"main": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsc",
|
|
13
|
+
"build": "node -e \"const fs=require('fs'); fs.rmSync('dist', {recursive:true, force:true});\" && tsc",
|
|
14
14
|
"test": "node --test tests/*.test.ts"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
package/dist/templates/auth.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/templates/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,kBA+e1B,CAAC"}
|
package/dist/templates/auth.js
DELETED
|
@@ -1,487 +0,0 @@
|
|
|
1
|
-
import { getBaseFiles } from './common.js';
|
|
2
|
-
export const authTemplate = {
|
|
3
|
-
id: 'auth',
|
|
4
|
-
name: 'SaaS & Authentication',
|
|
5
|
-
description: 'Fullstack SaaS starter with login, signup, protected dashboard layout, and session API',
|
|
6
|
-
generate: (projectName) => {
|
|
7
|
-
const files = getBaseFiles(projectName);
|
|
8
|
-
files['src/lib/auth.ts'] = `export interface UserSession {
|
|
9
|
-
id: string;
|
|
10
|
-
name: string;
|
|
11
|
-
email: string;
|
|
12
|
-
role: 'admin' | 'member';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const DEMO_USER: UserSession = {
|
|
16
|
-
id: 'usr_01jk982',
|
|
17
|
-
name: 'Sarah Connor',
|
|
18
|
-
email: 'sarah@frootkit.dev',
|
|
19
|
-
role: 'admin',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export function getSessionFromHeaders(headers: Headers): UserSession | null {
|
|
23
|
-
const authHeader = headers.get('authorization');
|
|
24
|
-
const cookie = headers.get('cookie') || '';
|
|
25
|
-
|
|
26
|
-
if (authHeader?.startsWith('Bearer ') || cookie.includes('froot_session=')) {
|
|
27
|
-
return DEMO_USER;
|
|
28
|
-
}
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
`;
|
|
32
|
-
files['src/components/Navbar.tsx'] = `export function Navbar() {
|
|
33
|
-
return (
|
|
34
|
-
<header class="border-b border-slate-800/80 bg-slate-950/70 backdrop-blur-md sticky top-0 z-50">
|
|
35
|
-
<div class="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between">
|
|
36
|
-
<a href="/" class="flex items-center gap-2.5 font-bold text-white text-lg tracking-tight hover:opacity-90">
|
|
37
|
-
<span class="w-8 h-8 rounded-xl bg-gradient-to-tr from-emerald-500 to-cyan-400 flex items-center justify-center text-slate-950 font-black text-sm">
|
|
38
|
-
F
|
|
39
|
-
</span>
|
|
40
|
-
<span>Froot<span class="text-emerald-400">SaaS</span></span>
|
|
41
|
-
</a>
|
|
42
|
-
|
|
43
|
-
<nav class="flex items-center gap-6 text-sm font-medium">
|
|
44
|
-
<a href="/dashboard" class="text-slate-300 hover:text-white transition-colors">
|
|
45
|
-
Dashboard
|
|
46
|
-
</a>
|
|
47
|
-
<a href="/login" class="text-slate-300 hover:text-white transition-colors">
|
|
48
|
-
Sign In
|
|
49
|
-
</a>
|
|
50
|
-
<a
|
|
51
|
-
href="/signup"
|
|
52
|
-
class="px-4 py-2 rounded-xl bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-all shadow-md shadow-emerald-500/20"
|
|
53
|
-
>
|
|
54
|
-
Get Started
|
|
55
|
-
</a>
|
|
56
|
-
</nav>
|
|
57
|
-
</div>
|
|
58
|
-
</header>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
`;
|
|
62
|
-
files['src/components/Sidebar.tsx'] = `export function Sidebar() {
|
|
63
|
-
const links = [
|
|
64
|
-
{ label: 'Overview', href: '/dashboard', icon: '📊' },
|
|
65
|
-
{ label: 'Analytics', href: '/dashboard#analytics', icon: '📈' },
|
|
66
|
-
{ label: 'Team', href: '/dashboard#team', icon: '👥' },
|
|
67
|
-
{ label: 'API Keys', href: '/api/auth', icon: '🔑' },
|
|
68
|
-
{ label: 'Settings', href: '/dashboard#settings', icon: '⚙️' },
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<aside class="w-64 border-r border-slate-800/80 bg-slate-950/80 p-6 flex flex-col justify-between">
|
|
73
|
-
<div>
|
|
74
|
-
<div class="flex items-center gap-2.5 font-bold text-white text-lg mb-8">
|
|
75
|
-
<span class="w-7 h-7 rounded-lg bg-emerald-500 flex items-center justify-center text-slate-950 font-black text-xs">
|
|
76
|
-
F
|
|
77
|
-
</span>
|
|
78
|
-
<span>Workspace</span>
|
|
79
|
-
</div>
|
|
80
|
-
|
|
81
|
-
<nav class="space-y-1 text-sm font-medium">
|
|
82
|
-
{links.map((link) => (
|
|
83
|
-
<a
|
|
84
|
-
key={link.label}
|
|
85
|
-
href={link.href}
|
|
86
|
-
class="flex items-center gap-3 px-3.5 py-2.5 rounded-xl text-slate-300 hover:text-white hover:bg-slate-900/80 transition-colors"
|
|
87
|
-
>
|
|
88
|
-
<span>{link.icon}</span>
|
|
89
|
-
<span>{link.label}</span>
|
|
90
|
-
</a>
|
|
91
|
-
))}
|
|
92
|
-
</nav>
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
<div class="pt-6 border-t border-slate-800/80 flex items-center justify-between">
|
|
96
|
-
<div class="flex items-center gap-2.5">
|
|
97
|
-
<div class="w-8 h-8 rounded-full bg-emerald-500/20 border border-emerald-500/30 flex items-center justify-center font-bold text-xs text-emerald-400">
|
|
98
|
-
SC
|
|
99
|
-
</div>
|
|
100
|
-
<div class="text-xs">
|
|
101
|
-
<div class="font-bold text-white">Sarah Connor</div>
|
|
102
|
-
<div class="text-slate-500">Pro Plan</div>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
<a href="/login" class="text-slate-500 hover:text-rose-400 text-xs transition-colors" title="Sign out">
|
|
106
|
-
→
|
|
107
|
-
</a>
|
|
108
|
-
</div>
|
|
109
|
-
</aside>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
`;
|
|
113
|
-
files['src/app/layout.tsx'] = `import type { ComponentChildren } from 'preact';
|
|
114
|
-
|
|
115
|
-
export interface RootLayoutProps {
|
|
116
|
-
children: ComponentChildren;
|
|
117
|
-
metadata?: {
|
|
118
|
-
title?: string;
|
|
119
|
-
description?: string;
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export default function RootLayout({ children, metadata }: RootLayoutProps) {
|
|
124
|
-
const title = metadata?.title || 'FrootSaaS — Modern SaaS Starter';
|
|
125
|
-
const description = metadata?.description || 'Fullstack SaaS kit with authentication, dashboard, and API routes.';
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
<html lang="en" class="dark scroll-smooth">
|
|
129
|
-
<head>
|
|
130
|
-
<meta charSet="UTF-8" />
|
|
131
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
132
|
-
<title>{title}</title>
|
|
133
|
-
<meta name="description" content={description} />
|
|
134
|
-
<link rel="stylesheet" href="/styles.css" />
|
|
135
|
-
</head>
|
|
136
|
-
<body class="bg-[#030712] text-slate-100 min-h-screen antialiased selection:bg-emerald-500/20 selection:text-emerald-300">
|
|
137
|
-
{children}
|
|
138
|
-
</body>
|
|
139
|
-
</html>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
`;
|
|
143
|
-
files['src/app/page.tsx'] = `import { Navbar } from '../components/Navbar.js';
|
|
144
|
-
|
|
145
|
-
export const metadata = {
|
|
146
|
-
title: 'FrootSaaS — Fullstack Auth & Dashboard Kit',
|
|
147
|
-
description: 'Launch your next subscription SaaS product in minutes with FrootKit.',
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
export default function SaaSMarketingPage() {
|
|
151
|
-
return (
|
|
152
|
-
<div class="min-h-screen flex flex-col justify-between">
|
|
153
|
-
<Navbar />
|
|
154
|
-
|
|
155
|
-
<main class="max-w-5xl mx-auto px-6 py-20 text-center flex-1 flex flex-col justify-center">
|
|
156
|
-
<div class="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs font-semibold text-emerald-400 mb-8 mx-auto">
|
|
157
|
-
Production SaaS Template • Preact SSR • Auth Engine
|
|
158
|
-
</div>
|
|
159
|
-
|
|
160
|
-
<h1 class="text-4xl sm:text-6xl md:text-7xl font-extrabold text-white tracking-tight mb-6 leading-tight">
|
|
161
|
-
Launch Your Next App with{' '}
|
|
162
|
-
<span class="bg-gradient-to-r from-emerald-400 via-teal-300 to-cyan-400 bg-clip-text text-transparent">
|
|
163
|
-
Built-In Auth & Dashboard
|
|
164
|
-
</span>
|
|
165
|
-
</h1>
|
|
166
|
-
|
|
167
|
-
<p class="text-slate-300 text-lg sm:text-xl max-w-2xl mx-auto mb-10 leading-relaxed">
|
|
168
|
-
Pre-configured sign-in, registration, nested dashboard layouts, and standard session API routes ready to connect to any database.
|
|
169
|
-
</p>
|
|
170
|
-
|
|
171
|
-
<div class="flex flex-wrap items-center justify-center gap-4 mb-20">
|
|
172
|
-
<a
|
|
173
|
-
href="/dashboard"
|
|
174
|
-
class="px-7 py-3.5 rounded-xl bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/25"
|
|
175
|
-
>
|
|
176
|
-
Open Live Dashboard →
|
|
177
|
-
</a>
|
|
178
|
-
<a
|
|
179
|
-
href="/login"
|
|
180
|
-
class="px-7 py-3.5 rounded-xl bg-slate-900 border border-slate-800 text-slate-200 font-semibold hover:bg-slate-800 transition-all"
|
|
181
|
-
>
|
|
182
|
-
Try Sign In Flow
|
|
183
|
-
</a>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{/* Feature Grid */}
|
|
187
|
-
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 text-left">
|
|
188
|
-
<div class="p-6 rounded-2xl border border-slate-800 bg-slate-900/40">
|
|
189
|
-
<div class="text-2xl mb-3">🔐</div>
|
|
190
|
-
<h3 class="font-bold text-white text-base mb-1">Session-Based Auth</h3>
|
|
191
|
-
<p class="text-xs text-slate-400 leading-relaxed">
|
|
192
|
-
Native API route handlers verifying headers and cookies without external dependencies.
|
|
193
|
-
</p>
|
|
194
|
-
</div>
|
|
195
|
-
<div class="p-6 rounded-2xl border border-slate-800 bg-slate-900/40">
|
|
196
|
-
<div class="text-2xl mb-3">📊</div>
|
|
197
|
-
<h3 class="font-bold text-white text-base mb-1">Nested Dashboard</h3>
|
|
198
|
-
<p class="text-xs text-slate-400 leading-relaxed">
|
|
199
|
-
Scoped sidebar navigation and layout hierarchy preserving state across pages.
|
|
200
|
-
</p>
|
|
201
|
-
</div>
|
|
202
|
-
<div class="p-6 rounded-2xl border border-slate-800 bg-slate-900/40">
|
|
203
|
-
<div class="text-2xl mb-3">⚡</div>
|
|
204
|
-
<h3 class="font-bold text-white text-base mb-1">Sub-Millisecond SSR</h3>
|
|
205
|
-
<p class="text-xs text-slate-400 leading-relaxed">
|
|
206
|
-
Instant Preact SSR with zero layout shifts and instant HTML delivery.
|
|
207
|
-
</p>
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</main>
|
|
211
|
-
|
|
212
|
-
<footer class="border-t border-slate-800/80 py-8 text-center text-xs text-slate-500">
|
|
213
|
-
© 2026 FrootSaaS. Built with FrootKit.
|
|
214
|
-
</footer>
|
|
215
|
-
</div>
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
`;
|
|
219
|
-
files['src/app/login/page.tsx'] = `export const metadata = {
|
|
220
|
-
title: 'Sign In — FrootSaaS',
|
|
221
|
-
description: 'Log into your workspace account.',
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
export default function LoginPage() {
|
|
225
|
-
return (
|
|
226
|
-
<main class="min-h-screen flex items-center justify-center p-6 bg-slate-950">
|
|
227
|
-
<div class="w-full max-w-md p-8 rounded-3xl border border-slate-800 bg-[#070b14] shadow-2xl">
|
|
228
|
-
<div class="text-center mb-8">
|
|
229
|
-
<a href="/" class="inline-flex items-center gap-2 font-bold text-white text-xl mb-4">
|
|
230
|
-
<span class="w-8 h-8 rounded-xl bg-emerald-500 flex items-center justify-center text-slate-950 font-black text-sm">
|
|
231
|
-
F
|
|
232
|
-
</span>
|
|
233
|
-
<span>Froot<span class="text-emerald-400">SaaS</span></span>
|
|
234
|
-
</a>
|
|
235
|
-
<h1 class="text-2xl font-extrabold text-white tracking-tight">Welcome back</h1>
|
|
236
|
-
<p class="text-xs text-slate-400 mt-1">Enter your credentials to access your dashboard</p>
|
|
237
|
-
</div>
|
|
238
|
-
|
|
239
|
-
<div class="p-3 mb-6 rounded-xl bg-emerald-500/10 border border-emerald-500/20 text-xs text-emerald-300 text-center font-mono">
|
|
240
|
-
Demo: sarah@frootkit.dev / password
|
|
241
|
-
</div>
|
|
242
|
-
|
|
243
|
-
<form action="/dashboard" method="GET" class="space-y-4">
|
|
244
|
-
<div>
|
|
245
|
-
<label class="block text-xs font-semibold text-slate-300 mb-1.5">Email address</label>
|
|
246
|
-
<input
|
|
247
|
-
type="email"
|
|
248
|
-
name="email"
|
|
249
|
-
value="sarah@frootkit.dev"
|
|
250
|
-
required
|
|
251
|
-
class="w-full px-3.5 py-2.5 rounded-xl border border-slate-800 bg-slate-900 text-sm text-white focus:outline-none focus:border-emerald-500 font-mono text-xs"
|
|
252
|
-
/>
|
|
253
|
-
</div>
|
|
254
|
-
|
|
255
|
-
<div>
|
|
256
|
-
<div class="flex items-center justify-between mb-1.5">
|
|
257
|
-
<label class="text-xs font-semibold text-slate-300">Password</label>
|
|
258
|
-
<a href="#" class="text-xs text-emerald-400 hover:underline">Forgot password?</a>
|
|
259
|
-
</div>
|
|
260
|
-
<input
|
|
261
|
-
type="password"
|
|
262
|
-
name="password"
|
|
263
|
-
value="••••••••••••"
|
|
264
|
-
required
|
|
265
|
-
class="w-full px-3.5 py-2.5 rounded-xl border border-slate-800 bg-slate-900 text-sm text-white focus:outline-none focus:border-emerald-500 text-xs"
|
|
266
|
-
/>
|
|
267
|
-
</div>
|
|
268
|
-
|
|
269
|
-
<button
|
|
270
|
-
type="submit"
|
|
271
|
-
class="w-full py-3 rounded-xl bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-all shadow-md shadow-emerald-500/25 mt-2"
|
|
272
|
-
>
|
|
273
|
-
Sign In →
|
|
274
|
-
</button>
|
|
275
|
-
</form>
|
|
276
|
-
|
|
277
|
-
<div class="text-center text-xs text-slate-500 mt-6">
|
|
278
|
-
Don't have an account?{' '}
|
|
279
|
-
<a href="/signup" class="text-emerald-400 font-semibold hover:underline">Create an account</a>
|
|
280
|
-
</div>
|
|
281
|
-
</div>
|
|
282
|
-
</main>
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
`;
|
|
286
|
-
files['src/app/signup/page.tsx'] = `export const metadata = {
|
|
287
|
-
title: 'Sign Up — FrootSaaS',
|
|
288
|
-
description: 'Create a new FrootSaaS workspace.',
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
export default function SignupPage() {
|
|
292
|
-
return (
|
|
293
|
-
<main class="min-h-screen flex items-center justify-center p-6 bg-slate-950">
|
|
294
|
-
<div class="w-full max-w-md p-8 rounded-3xl border border-slate-800 bg-[#070b14] shadow-2xl">
|
|
295
|
-
<div class="text-center mb-8">
|
|
296
|
-
<a href="/" class="inline-flex items-center gap-2 font-bold text-white text-xl mb-4">
|
|
297
|
-
<span class="w-8 h-8 rounded-xl bg-emerald-500 flex items-center justify-center text-slate-950 font-black text-sm">
|
|
298
|
-
F
|
|
299
|
-
</span>
|
|
300
|
-
<span>Froot<span class="text-emerald-400">SaaS</span></span>
|
|
301
|
-
</a>
|
|
302
|
-
<h1 class="text-2xl font-extrabold text-white tracking-tight">Create your account</h1>
|
|
303
|
-
<p class="text-xs text-slate-400 mt-1">Start your 14-day free trial. No card required.</p>
|
|
304
|
-
</div>
|
|
305
|
-
|
|
306
|
-
<form action="/dashboard" method="GET" class="space-y-4">
|
|
307
|
-
<div>
|
|
308
|
-
<label class="block text-xs font-semibold text-slate-300 mb-1.5">Full Name</label>
|
|
309
|
-
<input
|
|
310
|
-
type="text"
|
|
311
|
-
name="name"
|
|
312
|
-
placeholder="Sarah Connor"
|
|
313
|
-
required
|
|
314
|
-
class="w-full px-3.5 py-2.5 rounded-xl border border-slate-800 bg-slate-900 text-sm text-white focus:outline-none focus:border-emerald-500 text-xs"
|
|
315
|
-
/>
|
|
316
|
-
</div>
|
|
317
|
-
|
|
318
|
-
<div>
|
|
319
|
-
<label class="block text-xs font-semibold text-slate-300 mb-1.5">Work Email</label>
|
|
320
|
-
<input
|
|
321
|
-
type="email"
|
|
322
|
-
name="email"
|
|
323
|
-
placeholder="sarah@company.com"
|
|
324
|
-
required
|
|
325
|
-
class="w-full px-3.5 py-2.5 rounded-xl border border-slate-800 bg-slate-900 text-sm text-white focus:outline-none focus:border-emerald-500 font-mono text-xs"
|
|
326
|
-
/>
|
|
327
|
-
</div>
|
|
328
|
-
|
|
329
|
-
<div>
|
|
330
|
-
<label class="block text-xs font-semibold text-slate-300 mb-1.5">Password</label>
|
|
331
|
-
<input
|
|
332
|
-
type="password"
|
|
333
|
-
name="password"
|
|
334
|
-
placeholder="At least 8 characters"
|
|
335
|
-
required
|
|
336
|
-
class="w-full px-3.5 py-2.5 rounded-xl border border-slate-800 bg-slate-900 text-sm text-white focus:outline-none focus:border-emerald-500 text-xs"
|
|
337
|
-
/>
|
|
338
|
-
</div>
|
|
339
|
-
|
|
340
|
-
<button
|
|
341
|
-
type="submit"
|
|
342
|
-
class="w-full py-3 rounded-xl bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-all shadow-md shadow-emerald-500/25 mt-2"
|
|
343
|
-
>
|
|
344
|
-
Create Account →
|
|
345
|
-
</button>
|
|
346
|
-
</form>
|
|
347
|
-
|
|
348
|
-
<div class="text-center text-xs text-slate-500 mt-6">
|
|
349
|
-
Already have an account?{' '}
|
|
350
|
-
<a href="/login" class="text-emerald-400 font-semibold hover:underline">Sign in</a>
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
</main>
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
`;
|
|
357
|
-
files['src/app/dashboard/layout.tsx'] = `import type { ComponentChildren } from 'preact';
|
|
358
|
-
import { Sidebar } from '../../components/Sidebar.js';
|
|
359
|
-
|
|
360
|
-
export interface DashboardLayoutProps {
|
|
361
|
-
children: ComponentChildren;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
export default function DashboardLayout({ children }: DashboardLayoutProps) {
|
|
365
|
-
return (
|
|
366
|
-
<div class="flex min-h-screen bg-slate-950">
|
|
367
|
-
<Sidebar />
|
|
368
|
-
<div class="flex-1 flex flex-col">
|
|
369
|
-
<header class="h-16 border-b border-slate-800/80 px-8 flex items-center justify-between bg-slate-950/40">
|
|
370
|
-
<div class="text-xs font-mono text-slate-400">
|
|
371
|
-
Environment: <span class="text-emerald-400 font-bold">production-us-east</span>
|
|
372
|
-
</div>
|
|
373
|
-
<div class="flex items-center gap-3 text-xs">
|
|
374
|
-
<span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
|
|
375
|
-
<span class="text-slate-300 font-mono">System Healthy</span>
|
|
376
|
-
</div>
|
|
377
|
-
</header>
|
|
378
|
-
<main class="flex-1 p-8 overflow-y-auto">
|
|
379
|
-
{children}
|
|
380
|
-
</main>
|
|
381
|
-
</div>
|
|
382
|
-
</div>
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
`;
|
|
386
|
-
files['src/app/dashboard/page.tsx'] = `import { DEMO_USER } from '../../lib/auth.js';
|
|
387
|
-
|
|
388
|
-
export const metadata = {
|
|
389
|
-
title: 'Dashboard Overview — FrootSaaS',
|
|
390
|
-
description: 'Manage your SaaS operations and monitor real-time metrics.',
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
export default function DashboardOverviewPage() {
|
|
394
|
-
const metrics = [
|
|
395
|
-
{ label: 'Active Subscribers', value: '1,428', change: '+12.4%', isPositive: true },
|
|
396
|
-
{ label: 'Monthly Recurring', value: '$28,490', change: '+8.1%', isPositive: true },
|
|
397
|
-
{ label: 'Avg Latency (SSR)', value: '0.48ms', change: '-24%', isPositive: true },
|
|
398
|
-
{ label: 'Server Uptime', value: '99.99%', change: 'Normal', isPositive: true },
|
|
399
|
-
];
|
|
400
|
-
|
|
401
|
-
const recentUsers = [
|
|
402
|
-
{ name: 'Sarah Connor', email: 'sarah@frootkit.dev', role: 'Owner', date: 'Just now' },
|
|
403
|
-
{ name: 'Michael Scott', email: 'm.scott@dunder.com', role: 'Editor', date: '2h ago' },
|
|
404
|
-
{ name: 'Elena Rostova', email: 'elena@solaris.io', role: 'Viewer', date: '5h ago' },
|
|
405
|
-
];
|
|
406
|
-
|
|
407
|
-
return (
|
|
408
|
-
<div class="max-w-5xl space-y-8">
|
|
409
|
-
<div>
|
|
410
|
-
<h1 class="text-3xl font-extrabold text-white tracking-tight">
|
|
411
|
-
Welcome back, {DEMO_USER.name}
|
|
412
|
-
</h1>
|
|
413
|
-
<p class="text-xs text-slate-400 mt-1">
|
|
414
|
-
Here is what is happening across your application today.
|
|
415
|
-
</p>
|
|
416
|
-
</div>
|
|
417
|
-
|
|
418
|
-
{/* Metrics Grid */}
|
|
419
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
420
|
-
{metrics.map((m) => (
|
|
421
|
-
<div key={m.label} class="p-5 rounded-2xl border border-slate-800 bg-[#070b14]">
|
|
422
|
-
<div class="text-xs text-slate-400 mb-1">{m.label}</div>
|
|
423
|
-
<div class="text-2xl font-black text-white">{m.value}</div>
|
|
424
|
-
<div class="text-xs font-mono text-emerald-400 mt-2">{m.change} from last month</div>
|
|
425
|
-
</div>
|
|
426
|
-
))}
|
|
427
|
-
</div>
|
|
428
|
-
|
|
429
|
-
{/* Recent Activity Table */}
|
|
430
|
-
<div class="rounded-2xl border border-slate-800 bg-[#070b14] overflow-hidden">
|
|
431
|
-
<div class="p-5 border-b border-slate-800 flex items-center justify-between">
|
|
432
|
-
<h2 class="text-sm font-bold text-white">Recent Team Activity</h2>
|
|
433
|
-
<a href="/api/auth" class="text-xs font-mono text-emerald-400 hover:underline">/api/auth →</a>
|
|
434
|
-
</div>
|
|
435
|
-
<div class="divide-y divide-slate-800/80">
|
|
436
|
-
{recentUsers.map((u) => (
|
|
437
|
-
<div key={u.email} class="p-4 flex items-center justify-between text-xs">
|
|
438
|
-
<div>
|
|
439
|
-
<div class="font-bold text-white">{u.name}</div>
|
|
440
|
-
<div class="text-slate-500 font-mono">{u.email}</div>
|
|
441
|
-
</div>
|
|
442
|
-
<div class="flex items-center gap-4">
|
|
443
|
-
<span class="px-2 py-0.5 rounded-full bg-slate-900 border border-slate-800 text-slate-300 font-mono">
|
|
444
|
-
{u.role}
|
|
445
|
-
</span>
|
|
446
|
-
<span class="text-slate-500">{u.date}</span>
|
|
447
|
-
</div>
|
|
448
|
-
</div>
|
|
449
|
-
))}
|
|
450
|
-
</div>
|
|
451
|
-
</div>
|
|
452
|
-
</div>
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
`;
|
|
456
|
-
files['src/app/api/auth/route.ts'] = `import { DEMO_USER } from '../../../lib/auth.js';
|
|
457
|
-
|
|
458
|
-
export async function GET(request: Request) {
|
|
459
|
-
return Response.json({
|
|
460
|
-
authenticated: true,
|
|
461
|
-
user: DEMO_USER,
|
|
462
|
-
sessionExpires: new Date(Date.now() + 86400 * 1000).toISOString(),
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
export async function POST(request: Request) {
|
|
467
|
-
const body = await request.json().catch(() => ({}));
|
|
468
|
-
const { email, password } = body as { email?: string; password?: string };
|
|
469
|
-
|
|
470
|
-
if (email === 'sarah@frootkit.dev' && password === 'password') {
|
|
471
|
-
return Response.json({
|
|
472
|
-
success: true,
|
|
473
|
-
token: 'frt_' + Math.random().toString(36).substring(2),
|
|
474
|
-
user: DEMO_USER,
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return Response.json(
|
|
479
|
-
{ success: false, error: 'Invalid credentials. Use sarah@frootkit.dev / password' },
|
|
480
|
-
{ status: 401 }
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
`;
|
|
484
|
-
return files;
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/templates/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,CAAC,MAAM,YAAY,GAAuB;IAC9C,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,wFAAwF;IACrG,QAAQ,EAAE,CAAC,WAAmB,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;QAExC,KAAK,CAAC,iBAAiB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuB9B,CAAC;QAEE,KAAK,CAAC,2BAA2B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BxC,CAAC;QAEE,KAAK,CAAC,4BAA4B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDzC,CAAC;QAEE,KAAK,CAAC,oBAAoB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BjC,CAAC;QAEE,KAAK,CAAC,kBAAkB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2E/B,CAAC;QAEE,KAAK,CAAC,wBAAwB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkErC,CAAC;QAEE,KAAK,CAAC,yBAAyB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEtC,CAAC;QAEE,KAAK,CAAC,8BAA8B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B3C,CAAC;QAEE,KAAK,CAAC,4BAA4B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEzC,CAAC;QAEE,KAAK,CAAC,2BAA2B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BxC,CAAC;QAEE,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
|
package/dist/templates/blog.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../../src/templates/blog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,kBAwX1B,CAAC"}
|