create-flexireact 1.0.0 → 1.1.0

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 (2) hide show
  1. package/index.js +571 -233
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -74,11 +74,7 @@ ${c.green} ╰─────────────────────
74
74
  const TEMPLATES = {
75
75
  default: {
76
76
  name: 'Default',
77
- description: 'Basic FlexiReact app with TypeScript and Tailwind',
78
- },
79
- 'flexi-ui': {
80
- name: 'FlexiUI',
81
- description: 'FlexiReact with FlexiUI component library',
77
+ description: 'Premium template with modern UI, animations & dark mode',
82
78
  },
83
79
  minimal: {
84
80
  name: 'Minimal',
@@ -106,10 +102,6 @@ function info(msg) {
106
102
  console.log(` ${c.cyan}ℹ${c.reset} ${msg}`);
107
103
  }
108
104
 
109
- function step(num, total, msg) {
110
- console.log(` ${c.dim}[${num}/${total}]${c.reset} ${msg}`);
111
- }
112
-
113
105
  // Spinner
114
106
  class Spinner {
115
107
  constructor(message) {
@@ -184,26 +176,6 @@ async function select(question, options) {
184
176
  });
185
177
  }
186
178
 
187
- // Copy directory recursively
188
- function copyDir(src, dest) {
189
- if (!fs.existsSync(dest)) {
190
- fs.mkdirSync(dest, { recursive: true });
191
- }
192
-
193
- const entries = fs.readdirSync(src, { withFileTypes: true });
194
-
195
- for (const entry of entries) {
196
- const srcPath = path.join(src, entry.name);
197
- const destPath = path.join(dest, entry.name);
198
-
199
- if (entry.isDirectory()) {
200
- copyDir(srcPath, destPath);
201
- } else {
202
- fs.copyFileSync(srcPath, destPath);
203
- }
204
- }
205
- }
206
-
207
179
  // Check if directory is empty
208
180
  function isDirEmpty(dir) {
209
181
  if (!fs.existsSync(dir)) return true;
@@ -211,7 +183,7 @@ function isDirEmpty(dir) {
211
183
  }
212
184
 
213
185
  // ============================================================================
214
- // Template Files (Inline for npm package)
186
+ // Template Files
215
187
  // ============================================================================
216
188
 
217
189
  const TEMPLATE_FILES = {
@@ -224,21 +196,24 @@ const TEMPLATE_FILES = {
224
196
  dev: "npm run css && flexireact dev",
225
197
  build: "npm run css && flexireact build",
226
198
  start: "flexireact start",
227
- css: "npx tailwindcss -i ./app/styles/input.css -o ./public/styles.css --minify"
199
+ css: "npx tailwindcss -i ./app/styles/globals.css -o ./public/styles.css --minify"
228
200
  },
229
201
  dependencies: {
230
- react: "^18.2.0",
202
+ "react": "^18.2.0",
231
203
  "react-dom": "^18.2.0",
232
204
  "@flexireact/core": "^1.0.0",
233
- ...(template === 'flexi-ui' && { "@flexireact/flexi-ui": "^1.0.0" })
205
+ "framer-motion": "^11.0.0",
206
+ "lucide-react": "^0.400.0",
207
+ "clsx": "^2.1.0",
208
+ "tailwind-merge": "^2.2.0"
234
209
  },
235
210
  devDependencies: {
236
211
  "@types/react": "^18.2.0",
237
212
  "@types/react-dom": "^18.2.0",
238
- typescript: "^5.3.0",
239
- tailwindcss: "^3.4.0",
240
- postcss: "^8.4.32",
241
- autoprefixer: "^10.4.16"
213
+ "typescript": "^5.3.0",
214
+ "tailwindcss": "^3.4.0",
215
+ "postcss": "^8.4.32",
216
+ "autoprefixer": "^10.4.16"
242
217
  }
243
218
  }, null, 2),
244
219
 
@@ -265,8 +240,7 @@ const TEMPLATE_FILES = {
265
240
  exclude: ["node_modules", ".flexi"]
266
241
  }, null, 2),
267
242
 
268
- 'tailwind.config.js': (name, template) => `/** @type {import('tailwindcss').Config} */
269
- ${template === 'flexi-ui' ? "const { flexiUIPlugin } = require('@flexireact/flexi-ui/tailwind');\n" : ''}
243
+ 'tailwind.config.js': () => `/** @type {import('tailwindcss').Config} */
270
244
  module.exports = {
271
245
  darkMode: 'class',
272
246
  content: [
@@ -274,16 +248,71 @@ module.exports = {
274
248
  './pages/**/*.{js,ts,jsx,tsx}',
275
249
  './components/**/*.{js,ts,jsx,tsx}',
276
250
  './layouts/**/*.{js,ts,jsx,tsx}',
277
- ${template === 'flexi-ui' ? "'./node_modules/@flexireact/flexi-ui/dist/**/*.js'," : ''}
278
251
  ],
279
252
  theme: {
280
253
  extend: {
281
254
  fontFamily: {
282
255
  sans: ['Inter', 'system-ui', 'sans-serif'],
283
256
  },
257
+ colors: {
258
+ border: 'hsl(240 3.7% 15.9%)',
259
+ input: 'hsl(240 3.7% 15.9%)',
260
+ ring: 'hsl(142.1 76.2% 36.3%)',
261
+ background: 'hsl(240 10% 3.9%)',
262
+ foreground: 'hsl(0 0% 98%)',
263
+ primary: {
264
+ DEFAULT: 'hsl(142.1 76.2% 36.3%)',
265
+ foreground: 'hsl(144.9 80.4% 10%)',
266
+ },
267
+ secondary: {
268
+ DEFAULT: 'hsl(240 3.7% 15.9%)',
269
+ foreground: 'hsl(0 0% 98%)',
270
+ },
271
+ muted: {
272
+ DEFAULT: 'hsl(240 3.7% 15.9%)',
273
+ foreground: 'hsl(240 5% 64.9%)',
274
+ },
275
+ accent: {
276
+ DEFAULT: 'hsl(240 3.7% 15.9%)',
277
+ foreground: 'hsl(0 0% 98%)',
278
+ },
279
+ card: {
280
+ DEFAULT: 'hsl(240 10% 3.9%)',
281
+ foreground: 'hsl(0 0% 98%)',
282
+ },
283
+ },
284
+ borderRadius: {
285
+ lg: '0.75rem',
286
+ md: '0.5rem',
287
+ sm: '0.25rem',
288
+ },
289
+ animation: {
290
+ 'fade-in': 'fadeIn 0.5s ease-out',
291
+ 'fade-up': 'fadeUp 0.5s ease-out',
292
+ 'scale-in': 'scaleIn 0.3s ease-out',
293
+ 'glow': 'glow 2s ease-in-out infinite alternate',
294
+ },
295
+ keyframes: {
296
+ fadeIn: {
297
+ '0%': { opacity: '0' },
298
+ '100%': { opacity: '1' },
299
+ },
300
+ fadeUp: {
301
+ '0%': { opacity: '0', transform: 'translateY(20px)' },
302
+ '100%': { opacity: '1', transform: 'translateY(0)' },
303
+ },
304
+ scaleIn: {
305
+ '0%': { opacity: '0', transform: 'scale(0.95)' },
306
+ '100%': { opacity: '1', transform: 'scale(1)' },
307
+ },
308
+ glow: {
309
+ '0%': { boxShadow: '0 0 20px rgba(16, 185, 129, 0.2)' },
310
+ '100%': { boxShadow: '0 0 40px rgba(16, 185, 129, 0.4)' },
311
+ },
312
+ },
284
313
  },
285
314
  },
286
- plugins: [${template === 'flexi-ui' ? 'flexiUIPlugin' : ''}],
315
+ plugins: [],
287
316
  };
288
317
  `,
289
318
 
@@ -295,155 +324,398 @@ module.exports = {
295
324
  };
296
325
  `,
297
326
 
298
- 'flexireact.config.js': (name, template) => `/** @type {import('flexireact').Config} */
327
+ 'flexireact.config.js': () => `/** @type {import('@flexireact/core').Config} */
299
328
  export default {
300
- // Styles to include
301
329
  styles: [
302
330
  '/styles.css',
303
- 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'
331
+ 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap'
304
332
  ],
305
-
306
- // Server options
333
+ favicon: '/favicon.svg',
307
334
  server: {
308
335
  port: 3000
309
336
  },
310
-
311
- // Islands (partial hydration)
312
337
  islands: {
313
338
  enabled: true
314
339
  }
315
340
  };
316
341
  `,
317
342
 
318
- 'pages/index.tsx': (name, template) => template === 'flexi-ui' ? `import React from 'react';
343
+ // ============================================================================
344
+ // Components
345
+ // ============================================================================
319
346
 
320
- export default function HomePage() {
347
+ 'components/ui/button.tsx': () => `import React from 'react';
348
+ import { cn } from '../../lib/utils';
349
+
350
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
351
+ variant?: 'default' | 'outline' | 'ghost';
352
+ size?: 'default' | 'sm' | 'lg';
353
+ children: React.ReactNode;
354
+ }
355
+
356
+ export function Button({
357
+ className,
358
+ variant = 'default',
359
+ size = 'default',
360
+ children,
361
+ ...props
362
+ }: ButtonProps) {
321
363
  return (
322
- <div className="py-20">
323
- <div className="container mx-auto px-4 text-center">
324
- <span className="inline-block px-4 py-1.5 text-sm font-medium rounded-full mb-6" style={{ backgroundColor: 'rgba(0,255,156,0.1)', color: '#00FF9C', border: '1px solid rgba(0,255,156,0.3)' }}>
325
- ✨ Welcome to FlexiReact
326
- </span>
327
-
328
- <h1 className="text-4xl md:text-6xl font-bold mb-6">
329
- Build amazing apps with{' '}
330
- <span style={{ color: '#00FF9C' }}>FlexiReact</span>
331
- </h1>
332
-
333
- <p className="text-lg opacity-70 mb-8 max-w-2xl mx-auto">
334
- The modern React framework with TypeScript, Tailwind CSS, SSR, and Islands architecture.
335
- </p>
364
+ <button
365
+ className={cn(
366
+ 'inline-flex items-center justify-center rounded-lg font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
367
+ {
368
+ 'bg-primary text-primary-foreground hover:bg-primary/90 shadow-lg shadow-primary/25': variant === 'default',
369
+ 'border border-border bg-transparent hover:bg-secondary hover:text-foreground': variant === 'outline',
370
+ 'hover:bg-secondary hover:text-foreground': variant === 'ghost',
371
+ },
372
+ {
373
+ 'h-10 px-4 py-2 text-sm': size === 'default',
374
+ 'h-9 px-3 text-sm': size === 'sm',
375
+ 'h-12 px-8 text-base': size === 'lg',
376
+ },
377
+ className
378
+ )}
379
+ {...props}
380
+ >
381
+ {children}
382
+ </button>
383
+ );
384
+ }
385
+ `,
336
386
 
337
- <div className="flex gap-4 justify-center">
338
- <a href="/docs" className="px-6 py-3 font-medium rounded-xl text-black" style={{ backgroundColor: '#00FF9C' }}>
339
- Get Started →
340
- </a>
341
- <a href="https://github.com/flexireact/flexireact" className="px-6 py-3 font-medium rounded-xl border border-[var(--flexi-border)] hover:bg-[var(--flexi-bg-muted)] transition-colors">
342
- GitHub
343
- </a>
344
- </div>
345
- </div>
387
+ 'components/ui/card.tsx': () => `import React from 'react';
388
+ import { cn } from '../../lib/utils';
389
+
390
+ interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
391
+ children: React.ReactNode;
392
+ }
393
+
394
+ export function Card({ className, children, ...props }: CardProps) {
395
+ return (
396
+ <div
397
+ className={cn(
398
+ 'rounded-xl border border-border bg-card text-card-foreground shadow-sm transition-all duration-300 hover:border-primary/50 hover:shadow-lg hover:shadow-primary/5',
399
+ className
400
+ )}
401
+ {...props}
402
+ >
403
+ {children}
346
404
  </div>
347
405
  );
348
406
  }
349
- ` : `import React from 'react';
350
407
 
351
- export default function HomePage() {
408
+ export function CardHeader({ className, children, ...props }: CardProps) {
352
409
  return (
353
- <div className="py-20 px-4">
354
- <div className="max-w-4xl mx-auto text-center">
355
- {/* Badge */}
356
- <span className="inline-block px-4 py-2 text-sm font-medium rounded-full mb-8 bg-emerald-500/10 text-emerald-400 border border-emerald-500/30">
357
- ⚡ The Modern React Framework
358
- </span>
359
-
360
- {/* Title */}
361
- <h1 className="text-5xl md:text-7xl font-extrabold mb-6 text-white">
362
- Build amazing apps with{' '}
363
- <span className="text-transparent bg-clip-text bg-gradient-to-r from-emerald-400 to-cyan-400">
364
- FlexiReact
365
- </span>
366
- </h1>
410
+ <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props}>
411
+ {children}
412
+ </div>
413
+ );
414
+ }
415
+
416
+ export function CardTitle({ className, children, ...props }: CardProps) {
417
+ return (
418
+ <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props}>
419
+ {children}
420
+ </h3>
421
+ );
422
+ }
423
+
424
+ export function CardDescription({ className, children, ...props }: CardProps) {
425
+ return (
426
+ <p className={cn('text-sm text-muted-foreground', className)} {...props}>
427
+ {children}
428
+ </p>
429
+ );
430
+ }
431
+
432
+ export function CardContent({ className, children, ...props }: CardProps) {
433
+ return (
434
+ <div className={cn('p-6 pt-0', className)} {...props}>
435
+ {children}
436
+ </div>
437
+ );
438
+ }
439
+ `,
440
+
441
+ 'components/ui/badge.tsx': () => `import React from 'react';
442
+ import { cn } from '../../lib/utils';
443
+
444
+ interface BadgeProps extends React.HTMLAttributes<HTMLDivElement> {
445
+ variant?: 'default' | 'secondary' | 'outline';
446
+ children: React.ReactNode;
447
+ }
448
+
449
+ export function Badge({ className, variant = 'default', children, ...props }: BadgeProps) {
450
+ return (
451
+ <div
452
+ className={cn(
453
+ 'inline-flex items-center rounded-full px-3 py-1 text-xs font-medium transition-colors',
454
+ {
455
+ 'bg-primary/10 text-primary border border-primary/20': variant === 'default',
456
+ 'bg-secondary text-secondary-foreground': variant === 'secondary',
457
+ 'border border-border text-foreground': variant === 'outline',
458
+ },
459
+ className
460
+ )}
461
+ {...props}
462
+ >
463
+ {children}
464
+ </div>
465
+ );
466
+ }
467
+ `,
468
+
469
+ 'components/Navbar.tsx': () => `import React from 'react';
470
+ import { Button } from './ui/button';
471
+
472
+ export function Navbar() {
473
+ return (
474
+ <header className="sticky top-0 z-50 w-full border-b border-border/40 bg-background/80 backdrop-blur-xl">
475
+ <nav className="container mx-auto flex h-16 max-w-6xl items-center justify-between px-4">
476
+ <a href="/" className="flex items-center gap-2 transition-opacity hover:opacity-80">
477
+ <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-primary to-emerald-400">
478
+ <svg className="h-4 w-4 text-primary-foreground" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
479
+ <path strokeLinecap="round" strokeLinejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
480
+ </svg>
481
+ </div>
482
+ <span className="text-lg font-bold">FlexiReact</span>
483
+ </a>
367
484
 
368
- {/* Subtitle */}
369
- <p className="text-xl text-slate-400 mb-10 max-w-2xl mx-auto leading-relaxed">
370
- A blazing-fast React framework with TypeScript, Tailwind CSS, SSR, SSG,
371
- Islands architecture, and file-based routing.
372
- </p>
485
+ <div className="flex items-center gap-2">
486
+ <Button variant="ghost" size="sm" asChild>
487
+ <a href="https://github.com/flexireact/flexireact">Docs</a>
488
+ </Button>
489
+ <Button variant="ghost" size="sm" asChild>
490
+ <a href="https://github.com/flexireact/flexireact" className="flex items-center gap-2">
491
+ <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
492
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
493
+ </svg>
494
+ GitHub
495
+ </a>
496
+ </Button>
497
+ </div>
498
+ </nav>
499
+ </header>
500
+ );
501
+ }
502
+ `,
373
503
 
374
- {/* Buttons */}
375
- <div className="flex flex-wrap gap-4 justify-center mb-16">
376
- <a
377
- href="https://github.com/flexireact/flexireact"
378
- className="px-8 py-4 bg-emerald-500 text-black font-semibold rounded-xl hover:bg-emerald-400 transition-all shadow-lg shadow-emerald-500/25"
379
- >
380
- Get Started
381
- </a>
382
- <a
383
- href="https://github.com/flexireact/flexireact"
384
- className="px-8 py-4 bg-slate-800 text-white font-semibold rounded-xl border border-slate-700 hover:bg-slate-700 transition-all"
385
- >
386
- GitHub
387
- </a>
504
+ 'components/Hero.tsx': () => `import React from 'react';
505
+ import { Button } from './ui/button';
506
+ import { Badge } from './ui/badge';
507
+
508
+ export function Hero() {
509
+ return (
510
+ <section className="relative overflow-hidden">
511
+ {/* Gradient Background */}
512
+ <div className="absolute inset-0 -z-10">
513
+ <div className="absolute left-1/2 top-0 -translate-x-1/2 -translate-y-1/2">
514
+ <div className="h-[600px] w-[600px] rounded-full bg-gradient-to-r from-primary/20 via-emerald-500/10 to-cyan-500/20 blur-3xl" />
515
+ </div>
516
+ <div className="absolute right-0 top-1/2 -translate-y-1/2">
517
+ <div className="h-[400px] w-[400px] rounded-full bg-gradient-to-l from-primary/10 to-transparent blur-3xl" />
388
518
  </div>
519
+ </div>
389
520
 
390
- {/* Features */}
391
- <div className="grid md:grid-cols-3 gap-6 text-left">
392
- <div className="p-6 rounded-2xl bg-slate-800/50 border border-slate-700">
393
- <div className="text-3xl mb-3">⚡</div>
394
- <h3 className="text-lg font-semibold text-white mb-2">Lightning Fast</h3>
395
- <p className="text-slate-400 text-sm">Powered by esbuild for instant builds and sub-second HMR.</p>
396
- </div>
397
- <div className="p-6 rounded-2xl bg-slate-800/50 border border-slate-700">
398
- <div className="text-3xl mb-3">🏝️</div>
399
- <h3 className="text-lg font-semibold text-white mb-2">Islands Architecture</h3>
400
- <p className="text-slate-400 text-sm">Partial hydration for minimal JavaScript and maximum performance.</p>
521
+ <div className="container mx-auto max-w-6xl px-4 py-24 sm:py-32 lg:py-40">
522
+ <div className="flex flex-col items-center text-center">
523
+ {/* Badge */}
524
+ <Badge className="mb-6 animate-fade-in">
525
+ <span className="mr-1">⚡</span> The Modern React Framework
526
+ </Badge>
527
+
528
+ {/* Title */}
529
+ <h1 className="mb-6 max-w-4xl animate-fade-up text-4xl font-extrabold tracking-tight sm:text-5xl md:text-6xl lg:text-7xl">
530
+ Build{' '}
531
+ <span className="bg-gradient-to-r from-primary via-emerald-400 to-cyan-400 bg-clip-text text-transparent">
532
+ blazing fast
533
+ </span>{' '}
534
+ web apps
535
+ </h1>
536
+
537
+ {/* Subtitle */}
538
+ <p className="mb-10 max-w-2xl animate-fade-up text-lg text-muted-foreground sm:text-xl" style={{ animationDelay: '0.1s' }}>
539
+ A modern React framework with TypeScript, Tailwind CSS, SSR, SSG,
540
+ Islands architecture, and file-based routing. Ship faster.
541
+ </p>
542
+
543
+ {/* CTA Buttons */}
544
+ <div className="flex flex-wrap items-center justify-center gap-4 animate-fade-up" style={{ animationDelay: '0.2s' }}>
545
+ <Button size="lg" className="gap-2">
546
+ Start Building
547
+ <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
548
+ <path strokeLinecap="round" strokeLinejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />
549
+ </svg>
550
+ </Button>
551
+ <Button variant="outline" size="lg" asChild>
552
+ <a href="https://github.com/flexireact/flexireact" className="gap-2">
553
+ <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
554
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
555
+ </svg>
556
+ GitHub
557
+ </a>
558
+ </Button>
401
559
  </div>
402
- <div className="p-6 rounded-2xl bg-slate-800/50 border border-slate-700">
403
- <div className="text-3xl mb-3">📁</div>
404
- <h3 className="text-lg font-semibold text-white mb-2">File-based Routing</h3>
405
- <p className="text-slate-400 text-sm">Create a file in pages/, get a route automatically.</p>
560
+
561
+ {/* Code Preview */}
562
+ <div className="mt-16 w-full max-w-2xl animate-fade-up rounded-xl border border-border bg-card/50 p-4 backdrop-blur-sm" style={{ animationDelay: '0.3s' }}>
563
+ <div className="flex items-center gap-2 border-b border-border pb-3">
564
+ <div className="h-3 w-3 rounded-full bg-red-500/80" />
565
+ <div className="h-3 w-3 rounded-full bg-yellow-500/80" />
566
+ <div className="h-3 w-3 rounded-full bg-green-500/80" />
567
+ <span className="ml-2 text-xs text-muted-foreground">terminal</span>
568
+ </div>
569
+ <pre className="mt-4 overflow-x-auto text-left text-sm">
570
+ <code className="text-muted-foreground">
571
+ <span className="text-muted-foreground/60">$</span>{' '}
572
+ <span className="text-primary">npx</span> create-flexireact@latest my-app{'\n'}
573
+ <span className="text-muted-foreground/60">$</span>{' '}
574
+ <span className="text-primary">cd</span> my-app{'\n'}
575
+ <span className="text-muted-foreground/60">$</span>{' '}
576
+ <span className="text-primary">npm</span> run dev{'\n'}
577
+ {'\n'}
578
+ <span className="text-emerald-400">✓</span> Ready in <span className="text-primary">38ms</span>
579
+ </code>
580
+ </pre>
406
581
  </div>
407
582
  </div>
408
583
  </div>
409
- </div>
584
+ </section>
410
585
  );
411
586
  }
412
587
  `,
413
588
 
414
- 'layouts/root.tsx': (name, template) => template === 'flexi-ui' ? `import React from 'react';
589
+ 'components/Features.tsx': () => `import React from 'react';
590
+ import { Card, CardHeader, CardTitle, CardDescription } from './ui/card';
591
+
592
+ const features = [
593
+ {
594
+ icon: (
595
+ <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
596
+ <path strokeLinecap="round" strokeLinejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
597
+ </svg>
598
+ ),
599
+ title: 'Lightning Fast',
600
+ description: 'Powered by esbuild for instant builds and sub-second hot module replacement.',
601
+ },
602
+ {
603
+ icon: (
604
+ <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
605
+ <path strokeLinecap="round" strokeLinejoin="round" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
606
+ </svg>
607
+ ),
608
+ title: 'File-based Routing',
609
+ description: 'Create a file in pages/, get a route automatically. Simple and intuitive.',
610
+ },
611
+ {
612
+ icon: (
613
+ <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
614
+ <path strokeLinecap="round" strokeLinejoin="round" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
615
+ </svg>
616
+ ),
617
+ title: 'Islands Architecture',
618
+ description: 'Partial hydration for minimal JavaScript. Only hydrate what needs interactivity.',
619
+ },
620
+ {
621
+ icon: (
622
+ <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
623
+ <path strokeLinecap="round" strokeLinejoin="round" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
624
+ </svg>
625
+ ),
626
+ title: 'SSR & SSG',
627
+ description: 'Server-side rendering and static generation out of the box. SEO friendly.',
628
+ },
629
+ ];
415
630
 
416
- interface LayoutProps {
417
- children: React.ReactNode;
631
+ export function Features() {
632
+ return (
633
+ <section className="container mx-auto max-w-6xl px-4 py-24">
634
+ <div className="mb-12 text-center">
635
+ <h2 className="mb-4 text-3xl font-bold tracking-tight sm:text-4xl">
636
+ Everything you need
637
+ </h2>
638
+ <p className="mx-auto max-w-2xl text-muted-foreground">
639
+ A complete toolkit for building modern web applications with React.
640
+ </p>
641
+ </div>
642
+
643
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
644
+ {features.map((feature, index) => (
645
+ <Card key={index} className="group cursor-default">
646
+ <CardHeader>
647
+ <div className="mb-3 inline-flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10 text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground">
648
+ {feature.icon}
649
+ </div>
650
+ <CardTitle>{feature.title}</CardTitle>
651
+ <CardDescription>{feature.description}</CardDescription>
652
+ </CardHeader>
653
+ </Card>
654
+ ))}
655
+ </div>
656
+ </section>
657
+ );
418
658
  }
659
+ `,
419
660
 
420
- export default function RootLayout({ children }: LayoutProps) {
661
+ 'components/Footer.tsx': () => `import React from 'react';
662
+
663
+ export function Footer() {
421
664
  return (
422
- <div className="min-h-screen flex flex-col" style={{ backgroundColor: 'var(--flexi-bg)', color: 'var(--flexi-fg)' }}>
423
- <header className="sticky top-0 z-50 w-full border-b border-[var(--flexi-border)] backdrop-blur-sm" style={{ backgroundColor: 'rgba(2, 6, 23, 0.8)' }}>
424
- <nav className="container mx-auto px-4 h-16 flex items-center justify-between">
425
- <a href="/" className="flex items-center gap-2">
426
- <div className="w-8 h-8 rounded-xl flex items-center justify-center" style={{ background: 'linear-gradient(135deg, #00FF9C, #00CC7D)' }}>
427
- <span className="text-black font-bold text-sm">F</span>
428
- </div>
429
- <span className="font-bold text-xl">FlexiReact</span>
430
- </a>
431
- <div className="flex items-center gap-4">
432
- <a href="/" className="text-sm opacity-70 hover:opacity-100">Home</a>
433
- <a href="/about" className="text-sm opacity-70 hover:opacity-100">About</a>
665
+ <footer className="border-t border-border">
666
+ <div className="container mx-auto max-w-6xl px-4 py-8">
667
+ <div className="flex flex-col items-center justify-between gap-4 sm:flex-row">
668
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
669
+ <span>Built with</span>
670
+ <span className="text-red-500">❤️</span>
671
+ <span>using</span>
672
+ <a href="https://github.com/flexireact/flexireact" className="font-medium text-foreground hover:text-primary transition-colors">
673
+ FlexiReact
674
+ </a>
434
675
  </div>
435
- </nav>
436
- </header>
437
- <main className="flex-1">
438
- {children}
439
- </main>
440
- <footer className="border-t border-[var(--flexi-border)] py-8 text-center text-sm opacity-70">
441
- Built with FlexiReact
442
- </footer>
443
- </div>
676
+ <div className="flex items-center gap-4 text-sm text-muted-foreground">
677
+ <a href="https://github.com/flexireact/flexireact" className="hover:text-foreground transition-colors">
678
+ GitHub
679
+ </a>
680
+ <a href="https://github.com/flexireact/flexireact" className="hover:text-foreground transition-colors">
681
+ Documentation
682
+ </a>
683
+ </div>
684
+ </div>
685
+ </div>
686
+ </footer>
444
687
  );
445
688
  }
446
- ` : `import React from 'react';
689
+ `,
690
+
691
+ 'components/index.ts': () => `export { Navbar } from './Navbar';
692
+ export { Hero } from './Hero';
693
+ export { Features } from './Features';
694
+ export { Footer } from './Footer';
695
+ export { Button } from './ui/button';
696
+ export { Card, CardHeader, CardTitle, CardDescription, CardContent } from './ui/card';
697
+ export { Badge } from './ui/badge';
698
+ `,
699
+
700
+ // ============================================================================
701
+ // Lib
702
+ // ============================================================================
703
+
704
+ 'lib/utils.ts': () => `import { clsx, type ClassValue } from 'clsx';
705
+ import { twMerge } from 'tailwind-merge';
706
+
707
+ export function cn(...inputs: ClassValue[]) {
708
+ return twMerge(clsx(inputs));
709
+ }
710
+ `,
711
+
712
+ // ============================================================================
713
+ // Pages & Layouts
714
+ // ============================================================================
715
+
716
+ 'layouts/root.tsx': () => `import React from 'react';
717
+ import { Navbar } from '../components/Navbar';
718
+ import { Footer } from '../components/Footer';
447
719
 
448
720
  interface LayoutProps {
449
721
  children: React.ReactNode;
@@ -451,58 +723,145 @@ interface LayoutProps {
451
723
 
452
724
  export default function RootLayout({ children }: LayoutProps) {
453
725
  return (
454
- <div className="min-h-screen bg-slate-900 text-white">
455
- <header className="sticky top-0 z-50 border-b border-slate-700 bg-slate-900/80 backdrop-blur-sm">
456
- <nav className="container mx-auto px-4 h-16 flex items-center justify-between">
457
- <a href="/" className="flex items-center gap-2 font-bold text-xl">
458
- <span className="text-emerald-400">⚡</span> FlexiReact
459
- </a>
460
- <div className="flex items-center gap-6">
461
- <a href="/" className="text-sm text-slate-400 hover:text-white">Home</a>
462
- <a href="/about" className="text-sm text-slate-400 hover:text-white">About</a>
463
- <a href="https://github.com/flexireact/flexireact" className="text-sm px-4 py-2 bg-emerald-500 text-black rounded-lg font-medium hover:bg-emerald-400">
464
- GitHub
465
- </a>
466
- </div>
467
- </nav>
468
- </header>
469
- <main className="flex-1">
470
- {children}
471
- </main>
472
- <footer className="border-t border-slate-700 py-8 text-center text-sm text-slate-500">
473
- Built with ❤️ using FlexiReact
474
- </footer>
726
+ <div className="relative min-h-screen bg-background text-foreground antialiased">
727
+ <Navbar />
728
+ <main>{children}</main>
729
+ <Footer />
475
730
  </div>
476
731
  );
477
732
  }
478
733
  `,
479
734
 
480
- 'app/styles/input.css': () => `@tailwind base;
735
+ 'pages/index.tsx': () => `import React from 'react';
736
+ import { Hero } from '../components/Hero';
737
+ import { Features } from '../components/Features';
738
+
739
+ export default function HomePage() {
740
+ return (
741
+ <>
742
+ <Hero />
743
+ <Features />
744
+ </>
745
+ );
746
+ }
747
+ `,
748
+
749
+ // ============================================================================
750
+ // Styles
751
+ // ============================================================================
752
+
753
+ 'app/styles/globals.css': () => `@tailwind base;
481
754
  @tailwind components;
482
755
  @tailwind utilities;
483
756
 
484
757
  @layer base {
485
758
  :root {
486
- --flexi-bg: #0f172a;
487
- --flexi-fg: #f8fafc;
488
- --flexi-bg-subtle: #1e293b;
489
- --flexi-bg-muted: #334155;
490
- --flexi-border: #475569;
491
- --flexi-fg-muted: #94a3b8;
492
- --flexi-primary: #10b981;
759
+ --background: 240 10% 3.9%;
760
+ --foreground: 0 0% 98%;
761
+ --card: 240 10% 3.9%;
762
+ --card-foreground: 0 0% 98%;
763
+ --popover: 240 10% 3.9%;
764
+ --popover-foreground: 0 0% 98%;
765
+ --primary: 142.1 76.2% 36.3%;
766
+ --primary-foreground: 144.9 80.4% 10%;
767
+ --secondary: 240 3.7% 15.9%;
768
+ --secondary-foreground: 0 0% 98%;
769
+ --muted: 240 3.7% 15.9%;
770
+ --muted-foreground: 240 5% 64.9%;
771
+ --accent: 240 3.7% 15.9%;
772
+ --accent-foreground: 0 0% 98%;
773
+ --destructive: 0 62.8% 30.6%;
774
+ --destructive-foreground: 0 0% 98%;
775
+ --border: 240 3.7% 15.9%;
776
+ --input: 240 3.7% 15.9%;
777
+ --ring: 142.1 76.2% 36.3%;
778
+ --radius: 0.75rem;
493
779
  }
494
-
780
+
781
+ * {
782
+ border-color: hsl(var(--border));
783
+ }
784
+
495
785
  html {
496
786
  scroll-behavior: smooth;
497
787
  }
498
-
788
+
499
789
  body {
500
- font-family: 'Inter', system-ui, sans-serif;
501
- background-color: #0f172a;
502
- color: #f8fafc;
790
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
791
+ background-color: hsl(var(--background));
792
+ color: hsl(var(--foreground));
503
793
  min-height: 100vh;
794
+ -webkit-font-smoothing: antialiased;
795
+ -moz-osx-font-smoothing: grayscale;
796
+ }
797
+ }
798
+
799
+ @layer utilities {
800
+ .text-balance {
801
+ text-wrap: balance;
504
802
  }
505
803
  }
804
+ `,
805
+
806
+ // ============================================================================
807
+ // Public Assets
808
+ // ============================================================================
809
+
810
+ 'public/.gitkeep': () => '',
811
+
812
+ 'public/favicon.svg': () => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
813
+ <defs>
814
+ <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
815
+ <stop offset="0%" style="stop-color:#10b981"/>
816
+ <stop offset="100%" style="stop-color:#06b6d4"/>
817
+ </linearGradient>
818
+ </defs>
819
+ <rect width="100" height="100" rx="20" fill="#0a0a0a"/>
820
+ <path d="M50 20L30 55h15v25l20-35H50V20z" fill="url(#grad)"/>
821
+ </svg>`,
822
+ };
823
+
824
+ // Minimal template files
825
+ const MINIMAL_FILES = {
826
+ 'package.json': (name) => JSON.stringify({
827
+ name: name,
828
+ version: "1.0.0",
829
+ private: true,
830
+ type: "module",
831
+ scripts: {
832
+ dev: "flexireact dev",
833
+ build: "flexireact build",
834
+ start: "flexireact start"
835
+ },
836
+ dependencies: {
837
+ "react": "^18.2.0",
838
+ "react-dom": "^18.2.0",
839
+ "@flexireact/core": "^1.0.0"
840
+ },
841
+ devDependencies: {
842
+ "@types/react": "^18.2.0",
843
+ "@types/react-dom": "^18.2.0",
844
+ "typescript": "^5.3.0"
845
+ }
846
+ }, null, 2),
847
+
848
+ 'tsconfig.json': TEMPLATE_FILES['tsconfig.json'],
849
+
850
+ 'flexireact.config.js': () => `export default {
851
+ server: { port: 3000 }
852
+ };
853
+ `,
854
+
855
+ 'pages/index.tsx': () => `import React from 'react';
856
+
857
+ export default function HomePage() {
858
+ return (
859
+ <div style={{ padding: '2rem', fontFamily: 'system-ui' }}>
860
+ <h1>Welcome to FlexiReact</h1>
861
+ <p>Edit pages/index.tsx to get started.</p>
862
+ </div>
863
+ );
864
+ }
506
865
  `,
507
866
 
508
867
  'public/.gitkeep': () => '',
@@ -533,50 +892,55 @@ async function main() {
533
892
 
534
893
  // Check if directory exists
535
894
  if (fs.existsSync(projectPath) && !isDirEmpty(projectPath)) {
536
- error(`Directory "${projectName}" already exists and is not empty`);
895
+ error(`Directory ${projectName} already exists and is not empty`);
537
896
  process.exit(1);
538
897
  }
539
898
 
540
- console.log('');
541
-
542
899
  // Select template
900
+ console.log('');
543
901
  const templateOptions = Object.entries(TEMPLATES).map(([key, value]) => ({
544
902
  key,
545
903
  ...value,
546
904
  }));
547
905
 
548
906
  const selectedTemplate = await select('Select a template:', templateOptions);
549
- const template = selectedTemplate.key;
907
+ const templateKey = selectedTemplate.key;
550
908
 
551
909
  console.log('');
552
- console.log(` ${c.dim}Creating project in${c.reset} ${c.cyan}${projectPath}${c.reset}`);
910
+ log(`Creating project in ${c.cyan}${projectPath}${c.reset}`);
553
911
  console.log('');
554
912
 
555
913
  // Create project directory
556
914
  const spinner1 = new Spinner('Creating project structure...');
557
915
  spinner1.start();
558
-
916
+
559
917
  try {
560
918
  fs.mkdirSync(projectPath, { recursive: true });
561
- fs.mkdirSync(path.join(projectPath, 'pages'), { recursive: true });
562
- fs.mkdirSync(path.join(projectPath, 'layouts'), { recursive: true });
563
- fs.mkdirSync(path.join(projectPath, 'app', 'styles'), { recursive: true });
564
- fs.mkdirSync(path.join(projectPath, 'public'), { recursive: true });
565
- fs.mkdirSync(path.join(projectPath, 'components'), { recursive: true });
919
+
920
+ // Create subdirectories
921
+ const dirs = templateKey === 'minimal'
922
+ ? ['pages', 'public']
923
+ : ['pages', 'public', 'components', 'components/ui', 'layouts', 'app/styles', 'lib'];
924
+
925
+ for (const dir of dirs) {
926
+ fs.mkdirSync(path.join(projectPath, dir), { recursive: true });
927
+ }
566
928
 
567
929
  spinner1.stop(true);
568
930
  } catch (err) {
569
931
  spinner1.stop(false);
570
- error(`Failed to create directory: ${err.message}`);
932
+ error(`Failed to create project structure: ${err.message}`);
571
933
  process.exit(1);
572
934
  }
573
935
 
574
936
  // Write template files
575
937
  const spinner2 = new Spinner('Writing template files...');
576
938
  spinner2.start();
577
-
939
+
578
940
  try {
579
- for (const [filePath, generator] of Object.entries(TEMPLATE_FILES)) {
941
+ const files = templateKey === 'minimal' ? MINIMAL_FILES : TEMPLATE_FILES;
942
+
943
+ for (const [filePath, contentFn] of Object.entries(files)) {
580
944
  const fullPath = path.join(projectPath, filePath);
581
945
  const dir = path.dirname(fullPath);
582
946
 
@@ -584,51 +948,25 @@ async function main() {
584
948
  fs.mkdirSync(dir, { recursive: true });
585
949
  }
586
950
 
587
- const content = generator(projectName, template);
951
+ const content = contentFn(projectName, templateKey);
588
952
  fs.writeFileSync(fullPath, content);
589
953
  }
590
954
 
591
955
  spinner2.stop(true);
592
956
  } catch (err) {
593
957
  spinner2.stop(false);
594
- error(`Failed to write files: ${err.message}`);
958
+ error(`Failed to write template files: ${err.message}`);
595
959
  process.exit(1);
596
960
  }
597
961
 
598
- // Create .gitignore
962
+ // Create README
599
963
  const spinner3 = new Spinner('Creating configuration files...');
600
964
  spinner3.start();
601
-
965
+
602
966
  try {
603
- fs.writeFileSync(path.join(projectPath, '.gitignore'), `# Dependencies
604
- node_modules/
605
-
606
- # Build
607
- .flexi/
608
- dist/
609
- build/
610
-
611
- # Environment
612
- .env
613
- .env.local
614
- .env.*.local
967
+ const readmeContent = `# ${projectName}
615
968
 
616
- # IDE
617
- .vscode/
618
- .idea/
619
-
620
- # OS
621
- .DS_Store
622
- Thumbs.db
623
-
624
- # Logs
625
- *.log
626
- npm-debug.log*
627
- `);
628
-
629
- fs.writeFileSync(path.join(projectPath, 'README.md'), `# ${projectName}
630
-
631
- A FlexiReact application.
969
+ A modern web application built with [FlexiReact](https://github.com/flexireact/flexireact).
632
970
 
633
971
  ## Getting Started
634
972
 
@@ -642,9 +980,9 @@ Open [http://localhost:3000](http://localhost:3000) in your browser.
642
980
  ## Learn More
643
981
 
644
982
  - [FlexiReact Documentation](https://github.com/flexireact/flexireact)
645
- - [FlexiUI Components](https://github.com/flexireact/flexi-ui)
646
- `);
983
+ `;
647
984
 
985
+ fs.writeFileSync(path.join(projectPath, 'README.md'), readmeContent);
648
986
  spinner3.stop(true);
649
987
  } catch (err) {
650
988
  spinner3.stop(false);
@@ -652,7 +990,7 @@ Open [http://localhost:3000](http://localhost:3000) in your browser.
652
990
  process.exit(1);
653
991
  }
654
992
 
655
- // Done!
993
+ // Success message
656
994
  console.log(SUCCESS_BANNER(projectName));
657
995
  }
658
996
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-flexireact",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Create FlexiReact apps with one command - The Modern React Framework",
5
5
  "author": "FlexiReact Team",
6
6
  "license": "MIT",