create-frootkit 1.2.0 → 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.
@@ -1,474 +0,0 @@
1
- import { getBaseFiles } from './common.js';
2
- export const ecommerceTemplate = {
3
- id: 'ecommerce',
4
- name: 'E-Commerce Store',
5
- description: 'Modern storefront with product catalogue, [id] details, cart view, and checkout API',
6
- generate: (projectName) => {
7
- const files = getBaseFiles(projectName);
8
- files['src/types/store.ts'] = `export interface Product {
9
- id: string;
10
- name: string;
11
- price: number;
12
- category: string;
13
- rating: number;
14
- reviewsCount: number;
15
- image: string;
16
- description: string;
17
- features: string[];
18
- inStock: boolean;
19
- }
20
- `;
21
- files['src/data/products.ts'] = `import type { Product } from '../types/store.js';
22
-
23
- export const PRODUCTS: Product[] = [
24
- {
25
- id: 'nordic-mechanical-keyboard',
26
- name: 'Nordic Minimal Mechanical Keyboard',
27
- price: 149.0,
28
- category: 'Keyboards',
29
- rating: 4.9,
30
- reviewsCount: 128,
31
- image: 'https://images.unsplash.com/photo-1587829741301-dc798b83add3?w=600&auto=format&fit=crop&q=80',
32
- description: 'Ultra-tactile mechanical keyboard crafted with aircraft-grade aluminum, hot-swappable switches, and sound-dampening acoustic silicone pads.',
33
- features: ['Hot-swappable switches', 'Gasket mount design', 'QMK/VIA programmable', 'USB-C / 2.4GHz / Bluetooth'],
34
- inStock: true,
35
- },
36
- {
37
- id: 'ergonomic-precision-mouse',
38
- name: 'Precision Wireless Ergo Mouse',
39
- price: 89.0,
40
- category: 'Mice',
41
- rating: 4.8,
42
- reviewsCount: 94,
43
- image: 'https://images.unsplash.com/photo-1615663245857-ac93bb7c39e7?w=600&auto=format&fit=crop&q=80',
44
- description: 'Sculpted for natural palm alignment with a 26K DPI optical sensor, ultra-lightweight magnesium alloy chassis, and 80-hour battery life.',
45
- features: ['26,000 DPI Optical Sensor', '58g lightweight chassis', 'Magnetic fast-charging dock', 'Lag-free 4K polling'],
46
- inStock: true,
47
- },
48
- {
49
- id: 'studio-desk-mat',
50
- name: 'Merino Wool Felt Desk Mat',
51
- price: 49.0,
52
- category: 'Accessories',
53
- rating: 4.7,
54
- reviewsCount: 76,
55
- image: 'https://images.unsplash.com/photo-1527864550417-7fd91fc51a46?w=600&auto=format&fit=crop&q=80',
56
- description: 'High-density natural merino wool desk mat with natural anti-slip cork backing. Protects surfaces while providing an acoustic dampener for typing.',
57
- features: ['100% Natural Merino Wool', 'Natural Cork Backing', 'Water-repellent coating', 'Dimensions: 900mm x 400mm'],
58
- inStock: true,
59
- },
60
- {
61
- id: 'monitor-light-bar',
62
- name: 'ScreenBar Pro Monitor Light',
63
- price: 119.0,
64
- category: 'Lighting',
65
- rating: 4.9,
66
- reviewsCount: 210,
67
- image: 'https://images.unsplash.com/photo-1593642632823-8f785ba67e45?w=600&auto=format&fit=crop&q=80',
68
- description: 'Asymmetric optical design illuminates your desk without any screen glare. Features wireless rotary remote dial and auto-dimming ambient sensors.',
69
- features: ['Zero screen reflection', 'Wireless desktop dial', 'Auto ambient light dimming', 'Ra95 high CRI rating'],
70
- inStock: true,
71
- },
72
- ];
73
- `;
74
- files['src/components/Navbar.tsx'] = `export function Navbar() {
75
- return (
76
- <header class="border-b border-slate-800/80 bg-slate-950/70 backdrop-blur-md sticky top-0 z-50">
77
- <div class="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between">
78
- <a href="/" class="flex items-center gap-2.5 font-bold text-white text-lg tracking-tight hover:opacity-90">
79
- <span class="w-8 h-8 rounded-xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-400 font-extrabold text-base">
80
- ✦
81
- </span>
82
- <span>Aura<span class="text-emerald-400">Desk</span></span>
83
- </a>
84
-
85
- <nav class="hidden sm:flex items-center gap-6 text-sm font-medium">
86
- <a href="/" class="text-slate-300 hover:text-white transition-colors">Products</a>
87
- <a href="/cart" class="text-slate-300 hover:text-white transition-colors">Cart</a>
88
- <a href="/api/products" class="text-slate-400 hover:text-emerald-400 font-mono text-xs px-2 py-1 rounded bg-slate-900 border border-slate-800">
89
- /api/products
90
- </a>
91
- </nav>
92
-
93
- <div class="flex items-center gap-3">
94
- <a
95
- href="/cart"
96
- class="px-3.5 py-1.5 rounded-lg bg-emerald-500/10 border border-emerald-500/25 text-emerald-400 text-xs font-bold hover:bg-emerald-500/20 transition-all flex items-center gap-2"
97
- >
98
- <span>Cart</span>
99
- <span class="w-5 h-5 rounded-full bg-emerald-500 text-slate-950 flex items-center justify-center text-[10px] font-extrabold">
100
- 2
101
- </span>
102
- </a>
103
- </div>
104
- </div>
105
- </header>
106
- );
107
- }
108
- `;
109
- files['src/components/Footer.tsx'] = `export function Footer() {
110
- return (
111
- <footer class="border-t border-slate-800/80 mt-20 py-12 bg-slate-950/60 text-xs text-slate-400">
112
- <div class="max-w-6xl mx-auto px-6 grid grid-cols-1 md:grid-cols-4 gap-8 mb-10">
113
- <div class="md:col-span-2">
114
- <div class="font-bold text-white text-base mb-2">AuraDesk Store</div>
115
- <p class="text-slate-400 max-w-sm leading-relaxed">
116
- Engineered workspace gear powered by FrootKit. Sub-millisecond Preact SSR with native Tailwind CSS v4 styling.
117
- </p>
118
- </div>
119
- <div>
120
- <div class="font-bold text-white mb-3">Store Navigation</div>
121
- <ul class="space-y-2">
122
- <li><a href="/" class="hover:text-white transition-colors">Featured Gear</a></li>
123
- <li><a href="/cart" class="hover:text-white transition-colors">Shopping Cart</a></li>
124
- <li><a href="/api/products" class="hover:text-white transition-colors">Products API</a></li>
125
- </ul>
126
- </div>
127
- <div>
128
- <div class="font-bold text-white mb-3">Platform</div>
129
- <ul class="space-y-2">
130
- <li><a href="https://frootjs.org" target="_blank" rel="noreferrer" class="hover:text-white transition-colors">Froot Documentation</a></li>
131
- <li><a href="https://github.com/orbitnorth/frootkit" target="_blank" rel="noreferrer" class="hover:text-white transition-colors">GitHub Repository</a></li>
132
- </ul>
133
- </div>
134
- </div>
135
- <div class="max-w-6xl mx-auto px-6 pt-6 border-t border-slate-800/60 flex flex-col sm:flex-row items-center justify-between gap-4">
136
- <div>&copy; 2026 AuraDesk. Powered by FrootKit.</div>
137
- <div class="flex items-center gap-4 text-emerald-400 font-mono text-[11px]">
138
- <span>Fast Shipping</span> &bull; <span>30-Day Guarantee</span> &bull; <span>Secure Checkout</span>
139
- </div>
140
- </div>
141
- </footer>
142
- );
143
- }
144
- `;
145
- files['src/components/ProductCard.tsx'] = `import type { Product } from '../types/store.js';
146
-
147
- export function ProductCard({ product }: { product: Product }) {
148
- return (
149
- <div class="rounded-2xl border border-slate-800/80 bg-slate-900/40 overflow-hidden hover:border-emerald-500/30 transition-all hover:-translate-y-1 group flex flex-col justify-between">
150
- <div>
151
- <div class="aspect-4/3 overflow-hidden bg-slate-950 relative">
152
- <img
153
- src={product.image}
154
- alt={product.name}
155
- class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
156
- />
157
- <div class="absolute top-3 left-3 px-2 py-0.5 rounded-full bg-slate-950/80 backdrop-blur-md text-[10px] font-mono text-emerald-400 border border-emerald-500/20">
158
- {product.category}
159
- </div>
160
- </div>
161
-
162
- <div class="p-5">
163
- <div class="flex items-center gap-1.5 text-xs text-amber-400 mb-2 font-mono">
164
- <span>★</span>
165
- <span class="font-bold">{product.rating}</span>
166
- <span class="text-slate-500">({product.reviewsCount})</span>
167
- </div>
168
-
169
- <h3 class="text-base font-bold text-white mb-2 leading-snug group-hover:text-emerald-300 transition-colors">
170
- <a href={\`/products/\${product.id}\`}>{product.name}</a>
171
- </h3>
172
-
173
- <p class="text-xs text-slate-400 line-clamp-2 leading-relaxed">
174
- {product.description}
175
- </p>
176
- </div>
177
- </div>
178
-
179
- <div class="p-5 pt-0 flex items-center justify-between border-t border-slate-800/60 mt-4">
180
- <div>
181
- <span class="text-xs text-slate-500 block">Price</span>
182
- <span class="text-lg font-extrabold text-white">\${product.price.toFixed(2)}</span>
183
- </div>
184
- <a
185
- href={\`/products/\${product.id}\`}
186
- class="px-3.5 py-2 rounded-xl bg-emerald-500 text-slate-950 text-xs font-bold hover:bg-emerald-400 transition-all shadow-md shadow-emerald-500/20"
187
- >
188
- View Details &rarr;
189
- </a>
190
- </div>
191
- </div>
192
- );
193
- }
194
- `;
195
- files['src/app/layout.tsx'] = `import type { ComponentChildren } from 'preact';
196
- import { Navbar } from '../components/Navbar.js';
197
- import { Footer } from '../components/Footer.js';
198
-
199
- export interface RootLayoutProps {
200
- children: ComponentChildren;
201
- metadata?: {
202
- title?: string;
203
- description?: string;
204
- };
205
- }
206
-
207
- export default function RootLayout({ children, metadata }: RootLayoutProps) {
208
- const title = metadata?.title || 'AuraDesk — Precision Workspace Hardware';
209
- const description = metadata?.description || 'Engineered keyboards, ergonomic mice, and precision desk accessories.';
210
-
211
- return (
212
- <html lang="en" class="dark scroll-smooth">
213
- <head>
214
- <meta charSet="UTF-8" />
215
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
216
- <title>{title}</title>
217
- <meta name="description" content={description} />
218
- <link rel="stylesheet" href="/styles.css" />
219
- </head>
220
- <body class="bg-[#030712] text-slate-100 min-h-screen flex flex-col justify-between antialiased selection:bg-emerald-500/20 selection:text-emerald-300">
221
- <Navbar />
222
- <div class="flex-1">{children}</div>
223
- <Footer />
224
- </body>
225
- </html>
226
- );
227
- }
228
- `;
229
- files['src/app/page.tsx'] = `import { PRODUCTS } from '../data/products.js';
230
- import { ProductCard } from '../components/ProductCard.js';
231
-
232
- export const metadata = {
233
- title: 'AuraDesk Store — Precision Workspaces',
234
- description: 'Shop engineered ergonomic workspace accessories powered by FrootKit.',
235
- };
236
-
237
- export default function StoreHomePage() {
238
- return (
239
- <main class="max-w-6xl mx-auto px-6 py-12">
240
- {/* Store Hero */}
241
- <section class="rounded-3xl border border-slate-800 bg-gradient-to-br from-slate-900/60 via-slate-950 to-emerald-950/20 p-8 sm:p-14 mb-16 text-center sm:text-left relative overflow-hidden">
242
- <div class="max-w-2xl">
243
- <span class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs font-semibold text-emerald-400 mb-6">
244
- Season 2026 Collection
245
- </span>
246
- <h1 class="text-4xl sm:text-6xl font-extrabold text-white tracking-tight mb-4 leading-tight">
247
- Elevate Your <span class="bg-gradient-to-r from-emerald-400 to-teal-300 bg-clip-text text-transparent">Everyday Focus</span>
248
- </h1>
249
- <p class="text-slate-300 text-base sm:text-lg mb-8 leading-relaxed">
250
- Minimalist workspace hardware crafted for engineers, designers, and creators who value ergonomic precision.
251
- </p>
252
- <div class="flex flex-wrap gap-4 justify-center sm:justify-start">
253
- <a href="#products" class="px-6 py-3 rounded-xl bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/25">
254
- Browse Collection &darr;
255
- </a>
256
- <a href="/cart" class="px-6 py-3 rounded-xl bg-slate-900 border border-slate-800 text-slate-200 font-semibold hover:bg-slate-800 transition-all">
257
- View Cart (2 items)
258
- </a>
259
- </div>
260
- </div>
261
- </section>
262
-
263
- {/* Product Grid */}
264
- <section id="products">
265
- <div class="flex items-center justify-between mb-8">
266
- <div>
267
- <h2 class="text-2xl font-bold text-white tracking-tight">Featured Gear</h2>
268
- <p class="text-xs text-slate-400 mt-1">In-stock and ready to dispatch worldwide</p>
269
- </div>
270
- <a href="/api/products" class="text-xs font-mono text-emerald-400 hover:underline">
271
- Export JSON &rarr;
272
- </a>
273
- </div>
274
-
275
- <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
276
- {PRODUCTS.map((prod) => (
277
- <ProductCard key={prod.id} product={prod} />
278
- ))}
279
- </div>
280
- </section>
281
- </main>
282
- );
283
- }
284
- `;
285
- files['src/app/products/[id]/page.tsx'] = `import { PRODUCTS } from '../../../data/products.js';
286
-
287
- export async function generateStaticParams() {
288
- return PRODUCTS.map((p) => ({ id: p.id }));
289
- }
290
-
291
- export async function generateMetadata({ params }: { params: { id: string } }) {
292
- const product = PRODUCTS.find((p) => p.id === params.id);
293
- return {
294
- title: product ? \`\${product.name} — AuraDesk\` : 'Product Not Found',
295
- description: product?.description || '',
296
- };
297
- }
298
-
299
- export default function ProductDetailPage({ params }: { params: { id: string } }) {
300
- const product = PRODUCTS.find((p) => p.id === params.id);
301
-
302
- if (!product) {
303
- return (
304
- <main class="max-w-4xl mx-auto px-6 py-20 text-center">
305
- <h1 class="text-3xl font-bold text-white mb-4">Product Not Found</h1>
306
- <p class="text-slate-400 mb-6">The requested hardware item does not exist.</p>
307
- <a href="/" class="text-emerald-400 font-bold hover:underline">&larr; Back to Products</a>
308
- </main>
309
- );
310
- }
311
-
312
- return (
313
- <main class="max-w-6xl mx-auto px-6 py-12">
314
- <a href="/" class="inline-flex items-center gap-1.5 text-xs font-semibold text-emerald-400 hover:text-emerald-300 mb-8 transition-colors">
315
- &larr; Back to Collection
316
- </a>
317
-
318
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-start">
319
- {/* Gallery */}
320
- <div class="rounded-3xl border border-slate-800 bg-slate-900/40 overflow-hidden">
321
- <img src={product.image} alt={product.name} class="w-full aspect-4/3 object-cover" />
322
- </div>
323
-
324
- {/* Details & Buy Box */}
325
- <div class="space-y-6">
326
- <div>
327
- <span class="text-xs font-mono px-2.5 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
328
- {product.category}
329
- </span>
330
- <h1 class="text-3xl sm:text-4xl font-extrabold text-white mt-3 tracking-tight">
331
- {product.name}
332
- </h1>
333
- <div class="flex items-center gap-2 mt-2 text-sm text-slate-400">
334
- <span class="text-amber-400">★ {product.rating}</span>
335
- <span>&bull;</span>
336
- <span>{product.reviewsCount} customer reviews</span>
337
- </div>
338
- </div>
339
-
340
- <div class="text-3xl font-extrabold text-white">
341
- \${product.price.toFixed(2)}
342
- </div>
343
-
344
- <p class="text-slate-300 text-base leading-relaxed">
345
- {product.description}
346
- </p>
347
-
348
- <div class="pt-4 border-t border-slate-800">
349
- <h3 class="text-sm font-bold text-white mb-3">Key Specifications</h3>
350
- <ul class="space-y-2 text-sm text-slate-400">
351
- {product.features.map((feat) => (
352
- <li key={feat} class="flex items-center gap-2">
353
- <span class="text-emerald-400">✓</span> {feat}
354
- </li>
355
- ))}
356
- </ul>
357
- </div>
358
-
359
- <div class="pt-6 border-t border-slate-800 flex items-center gap-4">
360
- <a
361
- href="/cart"
362
- class="flex-1 text-center py-3.5 rounded-xl bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/20"
363
- >
364
- Add to Cart &bull; \${product.price.toFixed(2)}
365
- </a>
366
- </div>
367
- </div>
368
- </div>
369
- </main>
370
- );
371
- }
372
- `;
373
- files['src/app/cart/page.tsx'] = `import { PRODUCTS } from '../../data/products.js';
374
-
375
- export const metadata = {
376
- title: 'Shopping Cart — AuraDesk',
377
- description: 'Review your selected items and proceed to checkout.',
378
- };
379
-
380
- export default function CartPage() {
381
- const items = [
382
- { product: PRODUCTS[0]!, quantity: 1 },
383
- { product: PRODUCTS[1]!, quantity: 1 },
384
- ];
385
-
386
- const subtotal = items.reduce((sum, item) => sum + item.product.price * item.quantity, 0);
387
- const shipping = 0.0;
388
- const total = subtotal + shipping;
389
-
390
- return (
391
- <main class="max-w-4xl mx-auto px-6 py-12">
392
- <h1 class="text-3xl font-extrabold text-white mb-8 tracking-tight">Your Cart</h1>
393
-
394
- <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
395
- <div class="md:col-span-2 space-y-4">
396
- {items.map(({ product, quantity }) => (
397
- <div key={product.id} class="p-4 rounded-2xl border border-slate-800 bg-slate-900/40 flex items-center gap-4">
398
- <img src={product.image} alt={product.name} class="w-16 h-16 rounded-xl object-cover bg-slate-950" />
399
- <div class="flex-1 min-w-0">
400
- <h3 class="text-sm font-bold text-white truncate">{product.name}</h3>
401
- <div class="text-xs text-slate-400 mt-1">Qty: {quantity}</div>
402
- </div>
403
- <div class="text-right">
404
- <div class="text-sm font-bold text-white">\${(product.price * quantity).toFixed(2)}</div>
405
- </div>
406
- </div>
407
- ))}
408
- </div>
409
-
410
- <div class="p-6 rounded-2xl border border-slate-800 bg-slate-900/50 h-fit space-y-4">
411
- <h2 class="text-base font-bold text-white">Order Summary</h2>
412
- <div class="space-y-2 text-sm text-slate-300">
413
- <div class="flex justify-between"><span>Subtotal</span><span>\${subtotal.toFixed(2)}</span></div>
414
- <div class="flex justify-between"><span>Shipping</span><span class="text-emerald-400 font-bold">Free</span></div>
415
- <div class="pt-3 border-t border-slate-800 flex justify-between font-extrabold text-white text-base">
416
- <span>Total</span><span>\${total.toFixed(2)}</span>
417
- </div>
418
- </div>
419
- <form action="/api/checkout" method="POST">
420
- <button
421
- type="submit"
422
- 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/20"
423
- >
424
- Checkout (\${total.toFixed(2)})
425
- </button>
426
- </form>
427
- </div>
428
- </div>
429
- </main>
430
- );
431
- }
432
- `;
433
- files['src/app/api/products/route.ts'] = `import { PRODUCTS } from '../../../data/products.js';
434
-
435
- export async function GET(request: Request) {
436
- const url = new URL(request.url);
437
- const category = url.searchParams.get('category');
438
- const search = url.searchParams.get('q')?.toLowerCase();
439
-
440
- let results = [...PRODUCTS];
441
-
442
- if (category) {
443
- results = results.filter((p) => p.category.toLowerCase() === category.toLowerCase());
444
- }
445
-
446
- if (search) {
447
- results = results.filter(
448
- (p) =>
449
- p.name.toLowerCase().includes(search) ||
450
- p.description.toLowerCase().includes(search)
451
- );
452
- }
453
-
454
- return Response.json({
455
- total: results.length,
456
- products: results,
457
- });
458
- }
459
- `;
460
- files['src/app/api/checkout/route.ts'] = `export async function POST(request: Request) {
461
- const orderId = 'ORD-' + Math.random().toString(36).substring(2, 9).toUpperCase();
462
-
463
- return Response.json({
464
- success: true,
465
- orderId,
466
- message: 'Order created successfully',
467
- createdAt: new Date().toISOString(),
468
- });
469
- }
470
- `;
471
- return files;
472
- },
473
- };
474
- //# sourceMappingURL=ecommerce.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ecommerce.js","sourceRoot":"","sources":["../../src/templates/ecommerce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,CAAC,MAAM,iBAAiB,GAAuB;IACnD,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,qFAAqF;IAClG,QAAQ,EAAE,CAAC,WAAmB,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;QAExC,KAAK,CAAC,oBAAoB,CAAC,GAAG;;;;;;;;;;;;CAYjC,CAAC;QAEE,KAAK,CAAC,sBAAsB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDnC,CAAC;QAEE,KAAK,CAAC,2BAA2B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCxC,CAAC;QAEE,KAAK,CAAC,2BAA2B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCxC,CAAC;QAEE,KAAK,CAAC,gCAAgC,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiD7C,CAAC;QAEE,KAAK,CAAC,oBAAoB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCjC,CAAC;QAEE,KAAK,CAAC,kBAAkB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuD/B,CAAC;QAEE,KAAK,CAAC,gCAAgC,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuF7C,CAAC;QAEE,KAAK,CAAC,uBAAuB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2DpC,CAAC;QAEE,KAAK,CAAC,+BAA+B,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B5C,CAAC;QAEE,KAAK,CAAC,+BAA+B,CAAC,GAAG;;;;;;;;;;CAU5C,CAAC;QAEE,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { TemplateDefinition } from './types.js';
2
- export declare const emptyTemplate: TemplateDefinition;
3
- //# sourceMappingURL=empty.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"empty.d.ts","sourceRoot":"","sources":["../../src/templates/empty.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,aAAa,EAAE,kBAsF3B,CAAC"}
@@ -1,85 +0,0 @@
1
- import { getBaseFiles } from './common.js';
2
- export const emptyTemplate = {
3
- id: 'empty',
4
- name: 'Empty / Minimal',
5
- description: 'Clean, bare-bones project ready for custom development',
6
- generate: (projectName) => {
7
- const files = getBaseFiles(projectName);
8
- files['src/app/layout.tsx'] = `import type { ComponentChildren } from 'preact';
9
-
10
- export interface RootLayoutProps {
11
- children: ComponentChildren;
12
- metadata?: {
13
- title?: string;
14
- description?: string;
15
- };
16
- }
17
-
18
- export default function RootLayout({ children, metadata }: RootLayoutProps) {
19
- const title = metadata?.title || 'FrootKit App';
20
- const description = metadata?.description || 'Built with FrootKit.';
21
-
22
- return (
23
- <html lang="en" class="dark">
24
- <head>
25
- <meta charSet="UTF-8" />
26
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
27
- <title>{title}</title>
28
- <meta name="description" content={description} />
29
- <link rel="stylesheet" href="/styles.css" />
30
- </head>
31
- <body class="bg-[#030712] text-slate-100 min-h-screen antialiased">
32
- {children}
33
- </body>
34
- </html>
35
- );
36
- }
37
- `;
38
- files['src/app/page.tsx'] = `export const metadata = {
39
- title: '${projectName} — FrootKit',
40
- description: 'Clean starter built with FrootKit.',
41
- };
42
-
43
- export default function HomePage() {
44
- return (
45
- <main class="min-h-screen flex items-center justify-center p-6">
46
- <div class="text-center max-w-md">
47
- <h1 class="text-3xl sm:text-4xl font-extrabold text-white mb-3">
48
- ${projectName}
49
- </h1>
50
- <p class="text-slate-400 text-sm mb-6">
51
- Edit <code class="text-emerald-400 font-mono text-xs px-1.5 py-0.5 rounded bg-slate-900 border border-slate-800">src/app/page.tsx</code> to get started.
52
- </p>
53
- <div class="inline-flex gap-3 text-xs">
54
- <a
55
- href="https://frootjs.org"
56
- target="_blank"
57
- rel="noreferrer"
58
- class="px-4 py-2 rounded-lg bg-emerald-500 text-slate-950 font-bold hover:bg-emerald-400 transition-colors"
59
- >
60
- Documentation
61
- </a>
62
- <a
63
- href="/api/health"
64
- class="px-4 py-2 rounded-lg bg-slate-900 border border-slate-800 text-slate-300 font-mono hover:text-white transition-colors"
65
- >
66
- /api/health
67
- </a>
68
- </div>
69
- </div>
70
- </main>
71
- );
72
- }
73
- `;
74
- files['src/app/api/health/route.ts'] = `export async function GET() {
75
- return Response.json({
76
- status: 'ok',
77
- framework: 'frootkit',
78
- timestamp: new Date().toISOString(),
79
- });
80
- }
81
- `;
82
- return files;
83
- },
84
- };
85
- //# sourceMappingURL=empty.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"empty.js","sourceRoot":"","sources":["../../src/templates/empty.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,wDAAwD;IACrE,QAAQ,EAAE,CAAC,WAAmB,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;QAExC,KAAK,CAAC,oBAAoB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BjC,CAAC;QAEE,KAAK,CAAC,kBAAkB,CAAC,GAAG;YACpB,WAAW;;;;;;;;;YASX,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CAyBtB,CAAC;QAEE,KAAK,CAAC,6BAA6B,CAAC,GAAG;;;;;;;CAO1C,CAAC;QAEE,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { TemplateDefinition } from './types.js';
2
- export declare const starterTemplate: TemplateDefinition;
3
- //# sourceMappingURL=starter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"starter.d.ts","sourceRoot":"","sources":["../../src/templates/starter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,eAAO,MAAM,eAAe,EAAE,kBAqT7B,CAAC"}