vako 1.3.17 → 1.3.19
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/bin/commands/setup-executor.js +928 -19
- package/bin/commands/setup.js +21 -14
- package/bin/vako.js +1 -1
- package/package.json +1 -1
|
@@ -282,16 +282,73 @@ app.listen();
|
|
|
282
282
|
|
|
283
283
|
${description || 'A modern web application built with Vako'}
|
|
284
284
|
|
|
285
|
-
## Getting Started
|
|
285
|
+
## 🚀 Getting Started
|
|
286
|
+
|
|
287
|
+
### Installation
|
|
286
288
|
|
|
287
289
|
\`\`\`bash
|
|
288
290
|
npm install
|
|
291
|
+
\`\`\`
|
|
292
|
+
|
|
293
|
+
### Development
|
|
294
|
+
|
|
295
|
+
Démarrer le serveur de développement avec hot reload :
|
|
296
|
+
|
|
297
|
+
\`\`\`bash
|
|
289
298
|
npm run dev
|
|
299
|
+
# ou
|
|
300
|
+
vako dev
|
|
290
301
|
\`\`\`
|
|
291
302
|
|
|
292
|
-
|
|
303
|
+
L'application sera disponible sur [http://localhost:3000](http://localhost:3000)
|
|
293
304
|
|
|
294
|
-
|
|
305
|
+
### Production
|
|
306
|
+
|
|
307
|
+
\`\`\`bash
|
|
308
|
+
npm run build
|
|
309
|
+
npm start
|
|
310
|
+
\`\`\`
|
|
311
|
+
|
|
312
|
+
## 📁 Project Structure
|
|
313
|
+
|
|
314
|
+
\`\`\`
|
|
315
|
+
${projectName}/
|
|
316
|
+
├── views/ # Templates EJS
|
|
317
|
+
│ ├── index.ejs # Page d'accueil
|
|
318
|
+
│ └── about.ejs # Page à propos
|
|
319
|
+
├── routes/ # Routes Express
|
|
320
|
+
│ └── index.js # Routes principales
|
|
321
|
+
├── public/ # Fichiers statiques
|
|
322
|
+
│ ├── css/ # Styles CSS
|
|
323
|
+
│ └── js/ # JavaScript client
|
|
324
|
+
├── locales/ # Fichiers de traduction
|
|
325
|
+
├── config/ # Configuration
|
|
326
|
+
├── middleware/ # Middleware personnalisé
|
|
327
|
+
└── app.js # Point d'entrée
|
|
328
|
+
\`\`\`
|
|
329
|
+
|
|
330
|
+
## 🎯 Features
|
|
331
|
+
|
|
332
|
+
- ✅ Hot Reload Development Server
|
|
333
|
+
- ✅ Plugin System
|
|
334
|
+
- ✅ Authentication Ready
|
|
335
|
+
- ✅ Modern Architecture
|
|
336
|
+
- ✅ EJS Templates
|
|
337
|
+
- ✅ RESTful API Routes
|
|
338
|
+
|
|
339
|
+
## 📚 Documentation
|
|
340
|
+
|
|
341
|
+
- [Vako Documentation](https://vako.js.org)
|
|
342
|
+
- [Express.js Guide](https://expressjs.com)
|
|
343
|
+
- [EJS Templates](https://ejs.co)
|
|
344
|
+
|
|
345
|
+
## 🤝 Contributing
|
|
346
|
+
|
|
347
|
+
Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une issue ou une pull request.
|
|
348
|
+
|
|
349
|
+
## 📝 License
|
|
350
|
+
|
|
351
|
+
${license || 'MIT'}
|
|
295
352
|
`;
|
|
296
353
|
|
|
297
354
|
// .gitignore
|
|
@@ -307,14 +364,103 @@ coverage/
|
|
|
307
364
|
files['routes/index.js'] = `const { Router } = require('express');
|
|
308
365
|
const router = Router();
|
|
309
366
|
|
|
367
|
+
// Page d'accueil
|
|
310
368
|
router.get('/', (req, res) => {
|
|
311
369
|
res.render('index', {
|
|
312
|
-
title: 'Welcome to ${projectName}'
|
|
370
|
+
title: '${translations.title || 'Welcome to'} ${projectName}',
|
|
371
|
+
message: '${translations.welcome || 'Welcome to your Vako application!'}',
|
|
372
|
+
features: [
|
|
373
|
+
'Hot Reload Development Server',
|
|
374
|
+
'Plugin System',
|
|
375
|
+
'Authentication Ready',
|
|
376
|
+
'Modern Architecture'
|
|
377
|
+
]
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// Page à propos
|
|
382
|
+
router.get('/about', (req, res) => {
|
|
383
|
+
res.render('about', {
|
|
384
|
+
title: 'About - ${projectName}',
|
|
385
|
+
description: '${description || translations.description || 'A modern web application built with Vako'}'
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// API exemple
|
|
390
|
+
router.get('/api/status', (req, res) => {
|
|
391
|
+
res.json({
|
|
392
|
+
status: 'ok',
|
|
393
|
+
message: 'Vako API is running',
|
|
394
|
+
timestamp: new Date().toISOString()
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
module.exports = router;
|
|
399
|
+
`;
|
|
400
|
+
|
|
401
|
+
// routes/auth.js (créé seulement si auth est activé, mais on le crée toujours pour éviter les erreurs)
|
|
402
|
+
if (this.config.auth && this.config.auth.enabled) {
|
|
403
|
+
files['routes/auth.js'] = `const { Router } = require('express');
|
|
404
|
+
const router = Router();
|
|
405
|
+
|
|
406
|
+
// Page de connexion
|
|
407
|
+
router.get('/login', (req, res) => {
|
|
408
|
+
res.render('auth/login', {
|
|
409
|
+
title: 'Login - ${projectName}',
|
|
410
|
+
error: req.query.error || null
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Traitement de la connexion
|
|
415
|
+
router.post('/login', async (req, res) => {
|
|
416
|
+
const { username, password } = req.body;
|
|
417
|
+
|
|
418
|
+
// TODO: Implémenter la logique d'authentification
|
|
419
|
+
// Exemple basique (à remplacer par une vraie authentification)
|
|
420
|
+
if (username && password) {
|
|
421
|
+
// Ici vous devriez vérifier les credentials dans la base de données
|
|
422
|
+
req.session.userId = username; // Exemple simple
|
|
423
|
+
return res.redirect('/');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
res.redirect('/auth/login?error=invalid_credentials');
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// Page d'inscription
|
|
430
|
+
router.get('/register', (req, res) => {
|
|
431
|
+
res.render('auth/register', {
|
|
432
|
+
title: 'Register - ${projectName}',
|
|
433
|
+
error: req.query.error || null
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// Traitement de l'inscription
|
|
438
|
+
router.post('/register', async (req, res) => {
|
|
439
|
+
const { username, email, password } = req.body;
|
|
440
|
+
|
|
441
|
+
// TODO: Implémenter la logique d'inscription
|
|
442
|
+
// Exemple basique (à remplacer par une vraie logique)
|
|
443
|
+
if (username && email && password) {
|
|
444
|
+
// Ici vous devriez créer l'utilisateur dans la base de données
|
|
445
|
+
return res.redirect('/auth/login?success=registered');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
res.redirect('/auth/register?error=missing_fields');
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Déconnexion
|
|
452
|
+
router.get('/logout', (req, res) => {
|
|
453
|
+
req.session.destroy((err) => {
|
|
454
|
+
if (err) {
|
|
455
|
+
console.error('Error destroying session:', err);
|
|
456
|
+
}
|
|
457
|
+
res.redirect('/');
|
|
313
458
|
});
|
|
314
459
|
});
|
|
315
460
|
|
|
316
461
|
module.exports = router;
|
|
317
462
|
`;
|
|
463
|
+
}
|
|
318
464
|
|
|
319
465
|
// views/index.ejs
|
|
320
466
|
const langAttr = language === 'multi' ? 'fr' : language;
|
|
@@ -323,11 +469,110 @@ module.exports = router;
|
|
|
323
469
|
<head>
|
|
324
470
|
<meta charset="UTF-8">
|
|
325
471
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
472
|
+
<meta name="description" content="${description || translations.description || 'A modern web application built with Vako'}">
|
|
326
473
|
<title><%= title %></title>
|
|
474
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
327
475
|
</head>
|
|
328
476
|
<body>
|
|
329
|
-
<
|
|
330
|
-
|
|
477
|
+
<header>
|
|
478
|
+
<nav>
|
|
479
|
+
<div class="container">
|
|
480
|
+
<h1 class="logo">${projectName}</h1>
|
|
481
|
+
<ul class="nav-menu">
|
|
482
|
+
<li><a href="/" class="active">Home</a></li>
|
|
483
|
+
<li><a href="/about">About</a></li>
|
|
484
|
+
<li><a href="/api/status">API Status</a></li>
|
|
485
|
+
</ul>
|
|
486
|
+
</div>
|
|
487
|
+
</nav>
|
|
488
|
+
</header>
|
|
489
|
+
|
|
490
|
+
<main>
|
|
491
|
+
<section class="hero">
|
|
492
|
+
<div class="container">
|
|
493
|
+
<h1><%= title %></h1>
|
|
494
|
+
<p class="lead"><%= message %></p>
|
|
495
|
+
<div class="cta-buttons">
|
|
496
|
+
<a href="/about" class="btn btn-primary">Learn More</a>
|
|
497
|
+
<a href="/api/status" class="btn btn-secondary">API Status</a>
|
|
498
|
+
</div>
|
|
499
|
+
</div>
|
|
500
|
+
</section>
|
|
501
|
+
|
|
502
|
+
<section class="features">
|
|
503
|
+
<div class="container">
|
|
504
|
+
<h2>Features</h2>
|
|
505
|
+
<div class="features-grid">
|
|
506
|
+
<% features.forEach(function(feature) { %>
|
|
507
|
+
<div class="feature-card">
|
|
508
|
+
<div class="feature-icon">✨</div>
|
|
509
|
+
<h3><%= feature %></h3>
|
|
510
|
+
</div>
|
|
511
|
+
<% }); %>
|
|
512
|
+
</div>
|
|
513
|
+
</div>
|
|
514
|
+
</section>
|
|
515
|
+
</main>
|
|
516
|
+
|
|
517
|
+
<footer>
|
|
518
|
+
<div class="container">
|
|
519
|
+
<p>© ${new Date().getFullYear()} ${projectName}. Built with <a href="https://vako.js.org" target="_blank">Vako</a>.</p>
|
|
520
|
+
</div>
|
|
521
|
+
</footer>
|
|
522
|
+
|
|
523
|
+
<script src="/js/main.js"></script>
|
|
524
|
+
</body>
|
|
525
|
+
</html>
|
|
526
|
+
`;
|
|
527
|
+
|
|
528
|
+
// views/about.ejs
|
|
529
|
+
files['views/about.ejs'] = `<!DOCTYPE html>
|
|
530
|
+
<html lang="${langAttr}">
|
|
531
|
+
<head>
|
|
532
|
+
<meta charset="UTF-8">
|
|
533
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
534
|
+
<title><%= title %></title>
|
|
535
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
536
|
+
</head>
|
|
537
|
+
<body>
|
|
538
|
+
<header>
|
|
539
|
+
<nav>
|
|
540
|
+
<div class="container">
|
|
541
|
+
<h1 class="logo">${projectName}</h1>
|
|
542
|
+
<ul class="nav-menu">
|
|
543
|
+
<li><a href="/">Home</a></li>
|
|
544
|
+
<li><a href="/about" class="active">About</a></li>
|
|
545
|
+
<li><a href="/api/status">API Status</a></li>
|
|
546
|
+
</ul>
|
|
547
|
+
</div>
|
|
548
|
+
</nav>
|
|
549
|
+
</header>
|
|
550
|
+
|
|
551
|
+
<main>
|
|
552
|
+
<section class="content">
|
|
553
|
+
<div class="container">
|
|
554
|
+
<h1><%= title %></h1>
|
|
555
|
+
<p><%= description %></p>
|
|
556
|
+
<div class="info-box">
|
|
557
|
+
<h3>Technology Stack</h3>
|
|
558
|
+
<ul>
|
|
559
|
+
<li>Vako Framework</li>
|
|
560
|
+
<li>Express.js</li>
|
|
561
|
+
<li>EJS Templates</li>
|
|
562
|
+
<li>Node.js</li>
|
|
563
|
+
</ul>
|
|
564
|
+
</div>
|
|
565
|
+
</div>
|
|
566
|
+
</section>
|
|
567
|
+
</main>
|
|
568
|
+
|
|
569
|
+
<footer>
|
|
570
|
+
<div class="container">
|
|
571
|
+
<p>© ${new Date().getFullYear()} ${projectName}. Built with <a href="https://vako.js.org" target="_blank">Vako</a>.</p>
|
|
572
|
+
</div>
|
|
573
|
+
</footer>
|
|
574
|
+
|
|
575
|
+
<script src="/js/main.js"></script>
|
|
331
576
|
</body>
|
|
332
577
|
</html>
|
|
333
578
|
`;
|
|
@@ -352,20 +597,429 @@ module.exports = router;
|
|
|
352
597
|
}
|
|
353
598
|
|
|
354
599
|
// public/css/style.css
|
|
355
|
-
files['public/css/style.css'] =
|
|
356
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
600
|
+
files['public/css/style.css'] = `* {
|
|
357
601
|
margin: 0;
|
|
358
|
-
padding:
|
|
359
|
-
|
|
602
|
+
padding: 0;
|
|
603
|
+
box-sizing: border-box;
|
|
360
604
|
}
|
|
361
605
|
|
|
362
|
-
|
|
363
|
-
color: #
|
|
606
|
+
:root {
|
|
607
|
+
--primary-color: #007bff;
|
|
608
|
+
--secondary-color: #6c757d;
|
|
609
|
+
--success-color: #28a745;
|
|
610
|
+
--danger-color: #dc3545;
|
|
611
|
+
--warning-color: #ffc107;
|
|
612
|
+
--info-color: #17a2b8;
|
|
613
|
+
--light-color: #f8f9fa;
|
|
614
|
+
--dark-color: #343a40;
|
|
615
|
+
--white: #ffffff;
|
|
616
|
+
--gray: #6c757d;
|
|
617
|
+
--border-radius: 8px;
|
|
618
|
+
--shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
619
|
+
--transition: all 0.3s ease;
|
|
364
620
|
}
|
|
621
|
+
|
|
622
|
+
body {
|
|
623
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
624
|
+
line-height: 1.6;
|
|
625
|
+
color: var(--dark-color);
|
|
626
|
+
background-color: var(--light-color);
|
|
627
|
+
min-height: 100vh;
|
|
628
|
+
display: flex;
|
|
629
|
+
flex-direction: column;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.container {
|
|
633
|
+
max-width: 1200px;
|
|
634
|
+
margin: 0 auto;
|
|
635
|
+
padding: 0 20px;
|
|
636
|
+
width: 100%;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* Header & Navigation */
|
|
640
|
+
header {
|
|
641
|
+
background: var(--white);
|
|
642
|
+
box-shadow: var(--shadow);
|
|
643
|
+
position: sticky;
|
|
644
|
+
top: 0;
|
|
645
|
+
z-index: 1000;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
nav {
|
|
649
|
+
padding: 1rem 0;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
nav .container {
|
|
653
|
+
display: flex;
|
|
654
|
+
justify-content: space-between;
|
|
655
|
+
align-items: center;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.logo {
|
|
659
|
+
font-size: 1.5rem;
|
|
660
|
+
font-weight: bold;
|
|
661
|
+
color: var(--primary-color);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.nav-menu {
|
|
665
|
+
display: flex;
|
|
666
|
+
list-style: none;
|
|
667
|
+
gap: 2rem;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.nav-menu a {
|
|
671
|
+
text-decoration: none;
|
|
672
|
+
color: var(--dark-color);
|
|
673
|
+
font-weight: 500;
|
|
674
|
+
transition: var(--transition);
|
|
675
|
+
padding: 0.5rem 1rem;
|
|
676
|
+
border-radius: var(--border-radius);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.nav-menu a:hover,
|
|
680
|
+
.nav-menu a.active {
|
|
681
|
+
color: var(--primary-color);
|
|
682
|
+
background-color: var(--light-color);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/* Main Content */
|
|
686
|
+
main {
|
|
687
|
+
flex: 1;
|
|
688
|
+
padding: 2rem 0;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/* Hero Section */
|
|
692
|
+
.hero {
|
|
693
|
+
background: linear-gradient(135deg, var(--primary-color) 0%, #0056b3 100%);
|
|
694
|
+
color: var(--white);
|
|
695
|
+
padding: 4rem 0;
|
|
696
|
+
text-align: center;
|
|
697
|
+
margin-bottom: 3rem;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.hero h1 {
|
|
701
|
+
font-size: 3rem;
|
|
702
|
+
margin-bottom: 1rem;
|
|
703
|
+
color: var(--white);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.lead {
|
|
707
|
+
font-size: 1.25rem;
|
|
708
|
+
margin-bottom: 2rem;
|
|
709
|
+
opacity: 0.9;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.cta-buttons {
|
|
713
|
+
display: flex;
|
|
714
|
+
gap: 1rem;
|
|
715
|
+
justify-content: center;
|
|
716
|
+
flex-wrap: wrap;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* Buttons */
|
|
720
|
+
.btn {
|
|
721
|
+
display: inline-block;
|
|
722
|
+
padding: 0.75rem 1.5rem;
|
|
723
|
+
border-radius: var(--border-radius);
|
|
724
|
+
text-decoration: none;
|
|
725
|
+
font-weight: 600;
|
|
726
|
+
transition: var(--transition);
|
|
727
|
+
border: 2px solid transparent;
|
|
728
|
+
cursor: pointer;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.btn-primary {
|
|
732
|
+
background-color: var(--white);
|
|
733
|
+
color: var(--primary-color);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.btn-primary:hover {
|
|
737
|
+
background-color: var(--light-color);
|
|
738
|
+
transform: translateY(-2px);
|
|
739
|
+
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.btn-secondary {
|
|
743
|
+
background-color: transparent;
|
|
744
|
+
color: var(--white);
|
|
745
|
+
border-color: var(--white);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.btn-secondary:hover {
|
|
749
|
+
background-color: var(--white);
|
|
750
|
+
color: var(--primary-color);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/* Features Section */
|
|
754
|
+
.features {
|
|
755
|
+
padding: 3rem 0;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.features h2 {
|
|
759
|
+
text-align: center;
|
|
760
|
+
font-size: 2.5rem;
|
|
761
|
+
margin-bottom: 3rem;
|
|
762
|
+
color: var(--dark-color);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.features-grid {
|
|
766
|
+
display: grid;
|
|
767
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
768
|
+
gap: 2rem;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.feature-card {
|
|
772
|
+
background: var(--white);
|
|
773
|
+
padding: 2rem;
|
|
774
|
+
border-radius: var(--border-radius);
|
|
775
|
+
box-shadow: var(--shadow);
|
|
776
|
+
text-align: center;
|
|
777
|
+
transition: var(--transition);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.feature-card:hover {
|
|
781
|
+
transform: translateY(-5px);
|
|
782
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
.feature-icon {
|
|
786
|
+
font-size: 3rem;
|
|
787
|
+
margin-bottom: 1rem;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.feature-card h3 {
|
|
791
|
+
color: var(--dark-color);
|
|
792
|
+
margin-top: 1rem;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/* Content Section */
|
|
796
|
+
.content {
|
|
797
|
+
max-width: 800px;
|
|
798
|
+
margin: 0 auto;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.content h1 {
|
|
802
|
+
font-size: 2.5rem;
|
|
803
|
+
margin-bottom: 1.5rem;
|
|
804
|
+
color: var(--dark-color);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.content p {
|
|
808
|
+
font-size: 1.1rem;
|
|
809
|
+
margin-bottom: 2rem;
|
|
810
|
+
color: var(--gray);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.info-box {
|
|
814
|
+
background: var(--white);
|
|
815
|
+
padding: 2rem;
|
|
816
|
+
border-radius: var(--border-radius);
|
|
817
|
+
box-shadow: var(--shadow);
|
|
818
|
+
margin-top: 2rem;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.info-box h3 {
|
|
822
|
+
margin-bottom: 1rem;
|
|
823
|
+
color: var(--primary-color);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.info-box ul {
|
|
827
|
+
list-style: none;
|
|
828
|
+
padding-left: 0;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.info-box li {
|
|
832
|
+
padding: 0.5rem 0;
|
|
833
|
+
border-bottom: 1px solid var(--light-color);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.info-box li:last-child {
|
|
837
|
+
border-bottom: none;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.info-box li:before {
|
|
841
|
+
content: "✓ ";
|
|
842
|
+
color: var(--success-color);
|
|
843
|
+
font-weight: bold;
|
|
844
|
+
margin-right: 0.5rem;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/* Footer */
|
|
848
|
+
footer {
|
|
849
|
+
background: var(--dark-color);
|
|
850
|
+
color: var(--white);
|
|
851
|
+
padding: 2rem 0;
|
|
852
|
+
margin-top: auto;
|
|
853
|
+
text-align: center;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
footer a {
|
|
857
|
+
color: var(--primary-color);
|
|
858
|
+
text-decoration: none;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
footer a:hover {
|
|
862
|
+
text-decoration: underline;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/* Responsive */
|
|
866
|
+
@media (max-width: 768px) {
|
|
867
|
+
.nav-menu {
|
|
868
|
+
flex-direction: column;
|
|
869
|
+
gap: 0.5rem;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.hero h1 {
|
|
873
|
+
font-size: 2rem;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.features-grid {
|
|
877
|
+
grid-template-columns: 1fr;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.cta-buttons {
|
|
881
|
+
flex-direction: column;
|
|
882
|
+
align-items: center;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.btn {
|
|
886
|
+
width: 100%;
|
|
887
|
+
max-width: 300px;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
`;
|
|
891
|
+
|
|
892
|
+
// views/error.ejs
|
|
893
|
+
files['views/error.ejs'] = `<!DOCTYPE html>
|
|
894
|
+
<html lang="${langAttr}">
|
|
895
|
+
<head>
|
|
896
|
+
<meta charset="UTF-8">
|
|
897
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
898
|
+
<title><%= title %></title>
|
|
899
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
900
|
+
<style>
|
|
901
|
+
.error-container {
|
|
902
|
+
text-align: center;
|
|
903
|
+
padding: 4rem 2rem;
|
|
904
|
+
max-width: 600px;
|
|
905
|
+
margin: 0 auto;
|
|
906
|
+
}
|
|
907
|
+
.error-code {
|
|
908
|
+
font-size: 6rem;
|
|
909
|
+
font-weight: bold;
|
|
910
|
+
color: var(--danger-color);
|
|
911
|
+
margin-bottom: 1rem;
|
|
912
|
+
}
|
|
913
|
+
.error-message {
|
|
914
|
+
font-size: 1.5rem;
|
|
915
|
+
margin-bottom: 2rem;
|
|
916
|
+
color: var(--gray);
|
|
917
|
+
}
|
|
918
|
+
</style>
|
|
919
|
+
</head>
|
|
920
|
+
<body>
|
|
921
|
+
<header>
|
|
922
|
+
<nav>
|
|
923
|
+
<div class="container">
|
|
924
|
+
<h1 class="logo">${projectName}</h1>
|
|
925
|
+
<ul class="nav-menu">
|
|
926
|
+
<li><a href="/">Home</a></li>
|
|
927
|
+
<li><a href="/about">About</a></li>
|
|
928
|
+
</ul>
|
|
929
|
+
</div>
|
|
930
|
+
</nav>
|
|
931
|
+
</header>
|
|
932
|
+
|
|
933
|
+
<main>
|
|
934
|
+
<div class="error-container">
|
|
935
|
+
<div class="error-code"><%= error.status || 500 %></div>
|
|
936
|
+
<h1><%= title %></h1>
|
|
937
|
+
<p class="error-message"><%= message %></p>
|
|
938
|
+
<% if (error.stack && process.env.NODE_ENV === 'development') { %>
|
|
939
|
+
<pre style="text-align: left; background: #f5f5f5; padding: 1rem; border-radius: 8px; overflow-x: auto;"><%= error.stack %></pre>
|
|
940
|
+
<% } %>
|
|
941
|
+
<div class="cta-buttons" style="margin-top: 2rem;">
|
|
942
|
+
<a href="/" class="btn btn-primary">Go Home</a>
|
|
943
|
+
</div>
|
|
944
|
+
</div>
|
|
945
|
+
</main>
|
|
946
|
+
|
|
947
|
+
<footer>
|
|
948
|
+
<div class="container">
|
|
949
|
+
<p>© ${new Date().getFullYear()} ${projectName}. Built with <a href="https://vako.js.org" target="_blank">Vako</a>.</p>
|
|
950
|
+
</div>
|
|
951
|
+
</footer>
|
|
952
|
+
</body>
|
|
953
|
+
</html>
|
|
365
954
|
`;
|
|
366
955
|
|
|
367
956
|
// public/js/main.js
|
|
368
|
-
files['public/js/main.js'] =
|
|
957
|
+
files['public/js/main.js'] = `// Vako Application JavaScript
|
|
958
|
+
console.log('🚀 Vako application loaded');
|
|
959
|
+
|
|
960
|
+
// Smooth scroll for anchor links
|
|
961
|
+
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
962
|
+
anchor.addEventListener('click', function (e) {
|
|
963
|
+
e.preventDefault();
|
|
964
|
+
const target = document.querySelector(this.getAttribute('href'));
|
|
965
|
+
if (target) {
|
|
966
|
+
target.scrollIntoView({
|
|
967
|
+
behavior: 'smooth',
|
|
968
|
+
block: 'start'
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
// API Status Check
|
|
975
|
+
async function checkApiStatus() {
|
|
976
|
+
try {
|
|
977
|
+
const response = await fetch('/api/status');
|
|
978
|
+
const data = await response.json();
|
|
979
|
+
console.log('API Status:', data);
|
|
980
|
+
return data;
|
|
981
|
+
} catch (error) {
|
|
982
|
+
console.error('API Status check failed:', error);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// Initialize on page load
|
|
987
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
988
|
+
console.log('DOM loaded');
|
|
989
|
+
|
|
990
|
+
// Check API status if on home page
|
|
991
|
+
if (window.location.pathname === '/') {
|
|
992
|
+
checkApiStatus();
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// Add animation to feature cards
|
|
996
|
+
const featureCards = document.querySelectorAll('.feature-card');
|
|
997
|
+
featureCards.forEach((card, index) => {
|
|
998
|
+
card.style.animationDelay = \`\${index * 0.1}s\`;
|
|
999
|
+
card.classList.add('fade-in');
|
|
1000
|
+
});
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
// Add fade-in animation
|
|
1004
|
+
const style = document.createElement('style');
|
|
1005
|
+
style.textContent = \`
|
|
1006
|
+
@keyframes fadeIn {
|
|
1007
|
+
from {
|
|
1008
|
+
opacity: 0;
|
|
1009
|
+
transform: translateY(20px);
|
|
1010
|
+
}
|
|
1011
|
+
to {
|
|
1012
|
+
opacity: 1;
|
|
1013
|
+
transform: translateY(0);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
.fade-in {
|
|
1018
|
+
animation: fadeIn 0.6s ease-out forwards;
|
|
1019
|
+
opacity: 0;
|
|
1020
|
+
}
|
|
1021
|
+
\`;
|
|
1022
|
+
document.head.appendChild(style);
|
|
369
1023
|
`;
|
|
370
1024
|
|
|
371
1025
|
return files;
|
|
@@ -729,22 +1383,75 @@ coverage/
|
|
|
729
1383
|
|
|
730
1384
|
async setupAuthentication() {
|
|
731
1385
|
if (this.config.auth.enabled) {
|
|
732
|
-
//
|
|
1386
|
+
// S'assurer que le dossier routes existe
|
|
1387
|
+
const routesDir = path.join(this.projectPath, 'routes');
|
|
1388
|
+
if (!fs.existsSync(routesDir)) {
|
|
1389
|
+
fs.mkdirSync(routesDir, { recursive: true });
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// S'assurer que le dossier views/auth existe pour les templates
|
|
1393
|
+
const authViewsDir = path.join(this.projectPath, 'views', 'auth');
|
|
1394
|
+
if (!fs.existsSync(authViewsDir)) {
|
|
1395
|
+
fs.mkdirSync(authViewsDir, { recursive: true });
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// Create auth routes
|
|
733
1399
|
const authRoute = `const { Router } = require('express');
|
|
734
1400
|
const router = Router();
|
|
735
1401
|
|
|
1402
|
+
// Page de connexion
|
|
736
1403
|
router.get('/login', (req, res) => {
|
|
737
|
-
res.render('auth/login', {
|
|
1404
|
+
res.render('auth/login', {
|
|
1405
|
+
title: 'Login - ${this.config.projectName}',
|
|
1406
|
+
error: req.query.error || null
|
|
1407
|
+
});
|
|
738
1408
|
});
|
|
739
1409
|
|
|
1410
|
+
// Traitement de la connexion
|
|
740
1411
|
router.post('/login', async (req, res) => {
|
|
741
|
-
|
|
742
|
-
|
|
1412
|
+
const { username, password } = req.body;
|
|
1413
|
+
|
|
1414
|
+
// TODO: Implémenter la logique d'authentification
|
|
1415
|
+
// Exemple basique (à remplacer par une vraie authentification)
|
|
1416
|
+
if (username && password) {
|
|
1417
|
+
// Ici vous devriez vérifier les credentials dans la base de données
|
|
1418
|
+
req.session.userId = username; // Exemple simple
|
|
1419
|
+
return res.redirect('/');
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
res.redirect('/login?error=invalid_credentials');
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
// Page d'inscription
|
|
1426
|
+
router.get('/register', (req, res) => {
|
|
1427
|
+
res.render('auth/register', {
|
|
1428
|
+
title: 'Register - ${this.config.projectName}',
|
|
1429
|
+
error: req.query.error || null
|
|
1430
|
+
});
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
// Traitement de l'inscription
|
|
1434
|
+
router.post('/register', async (req, res) => {
|
|
1435
|
+
const { username, email, password } = req.body;
|
|
1436
|
+
|
|
1437
|
+
// TODO: Implémenter la logique d'inscription
|
|
1438
|
+
// Exemple basique (à remplacer par une vraie logique)
|
|
1439
|
+
if (username && email && password) {
|
|
1440
|
+
// Ici vous devriez créer l'utilisateur dans la base de données
|
|
1441
|
+
return res.redirect('/login?success=registered');
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
res.redirect('/register?error=missing_fields');
|
|
743
1445
|
});
|
|
744
1446
|
|
|
1447
|
+
// Déconnexion
|
|
745
1448
|
router.get('/logout', (req, res) => {
|
|
746
|
-
|
|
747
|
-
|
|
1449
|
+
req.session.destroy((err) => {
|
|
1450
|
+
if (err) {
|
|
1451
|
+
console.error('Error destroying session:', err);
|
|
1452
|
+
}
|
|
1453
|
+
res.redirect('/');
|
|
1454
|
+
});
|
|
748
1455
|
});
|
|
749
1456
|
|
|
750
1457
|
module.exports = router;
|
|
@@ -752,6 +1459,208 @@ module.exports = router;
|
|
|
752
1459
|
|
|
753
1460
|
const authPath = path.join(this.projectPath, 'routes/auth.js');
|
|
754
1461
|
fs.writeFileSync(authPath, authRoute, 'utf8');
|
|
1462
|
+
|
|
1463
|
+
// Créer les vues d'authentification
|
|
1464
|
+
const loginView = `<!DOCTYPE html>
|
|
1465
|
+
<html lang="${this.config.language === 'multi' ? 'fr' : this.config.language || 'fr'}">
|
|
1466
|
+
<head>
|
|
1467
|
+
<meta charset="UTF-8">
|
|
1468
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1469
|
+
<title><%= title %></title>
|
|
1470
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
1471
|
+
<style>
|
|
1472
|
+
.auth-container {
|
|
1473
|
+
max-width: 400px;
|
|
1474
|
+
margin: 4rem auto;
|
|
1475
|
+
padding: 2rem;
|
|
1476
|
+
background: var(--white);
|
|
1477
|
+
border-radius: var(--border-radius);
|
|
1478
|
+
box-shadow: var(--shadow);
|
|
1479
|
+
}
|
|
1480
|
+
.auth-container h1 {
|
|
1481
|
+
text-align: center;
|
|
1482
|
+
margin-bottom: 2rem;
|
|
1483
|
+
color: var(--primary-color);
|
|
1484
|
+
}
|
|
1485
|
+
.form-group {
|
|
1486
|
+
margin-bottom: 1.5rem;
|
|
1487
|
+
}
|
|
1488
|
+
.form-group label {
|
|
1489
|
+
display: block;
|
|
1490
|
+
margin-bottom: 0.5rem;
|
|
1491
|
+
color: var(--dark-color);
|
|
1492
|
+
font-weight: 500;
|
|
1493
|
+
}
|
|
1494
|
+
.form-group input {
|
|
1495
|
+
width: 100%;
|
|
1496
|
+
padding: 0.75rem;
|
|
1497
|
+
border: 1px solid #ddd;
|
|
1498
|
+
border-radius: var(--border-radius);
|
|
1499
|
+
font-size: 1rem;
|
|
1500
|
+
}
|
|
1501
|
+
.form-group input:focus {
|
|
1502
|
+
outline: none;
|
|
1503
|
+
border-color: var(--primary-color);
|
|
1504
|
+
}
|
|
1505
|
+
.error-message {
|
|
1506
|
+
background: var(--danger-color);
|
|
1507
|
+
color: var(--white);
|
|
1508
|
+
padding: 0.75rem;
|
|
1509
|
+
border-radius: var(--border-radius);
|
|
1510
|
+
margin-bottom: 1rem;
|
|
1511
|
+
text-align: center;
|
|
1512
|
+
}
|
|
1513
|
+
</style>
|
|
1514
|
+
</head>
|
|
1515
|
+
<body>
|
|
1516
|
+
<header>
|
|
1517
|
+
<nav>
|
|
1518
|
+
<div class="container">
|
|
1519
|
+
<h1 class="logo">${this.config.projectName}</h1>
|
|
1520
|
+
<ul class="nav-menu">
|
|
1521
|
+
<li><a href="/">Home</a></li>
|
|
1522
|
+
<li><a href="/login" class="active">Login</a></li>
|
|
1523
|
+
<li><a href="/register">Register</a></li>
|
|
1524
|
+
</ul>
|
|
1525
|
+
</div>
|
|
1526
|
+
</nav>
|
|
1527
|
+
</header>
|
|
1528
|
+
|
|
1529
|
+
<main>
|
|
1530
|
+
<div class="auth-container">
|
|
1531
|
+
<h1>Login</h1>
|
|
1532
|
+
<% if (error) { %>
|
|
1533
|
+
<div class="error-message">Invalid credentials. Please try again.</div>
|
|
1534
|
+
<% } %>
|
|
1535
|
+
<form method="POST" action="/login">
|
|
1536
|
+
<div class="form-group">
|
|
1537
|
+
<label for="username">Username</label>
|
|
1538
|
+
<input type="text" id="username" name="username" required>
|
|
1539
|
+
</div>
|
|
1540
|
+
<div class="form-group">
|
|
1541
|
+
<label for="password">Password</label>
|
|
1542
|
+
<input type="password" id="password" name="password" required>
|
|
1543
|
+
</div>
|
|
1544
|
+
<button type="submit" class="btn btn-primary" style="width: 100%;">Login</button>
|
|
1545
|
+
</form>
|
|
1546
|
+
<p style="text-align: center; margin-top: 1rem;">
|
|
1547
|
+
Don't have an account? <a href="/register">Register here</a>
|
|
1548
|
+
</p>
|
|
1549
|
+
</div>
|
|
1550
|
+
</main>
|
|
1551
|
+
|
|
1552
|
+
<footer>
|
|
1553
|
+
<div class="container">
|
|
1554
|
+
<p>© ${new Date().getFullYear()} ${this.config.projectName}. Built with <a href="https://vako.js.org" target="_blank">Vako</a>.</p>
|
|
1555
|
+
</div>
|
|
1556
|
+
</footer>
|
|
1557
|
+
</body>
|
|
1558
|
+
</html>
|
|
1559
|
+
`;
|
|
1560
|
+
|
|
1561
|
+
const registerView = `<!DOCTYPE html>
|
|
1562
|
+
<html lang="${this.config.language === 'multi' ? 'fr' : this.config.language || 'fr'}">
|
|
1563
|
+
<head>
|
|
1564
|
+
<meta charset="UTF-8">
|
|
1565
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1566
|
+
<title><%= title %></title>
|
|
1567
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
1568
|
+
<style>
|
|
1569
|
+
.auth-container {
|
|
1570
|
+
max-width: 400px;
|
|
1571
|
+
margin: 4rem auto;
|
|
1572
|
+
padding: 2rem;
|
|
1573
|
+
background: var(--white);
|
|
1574
|
+
border-radius: var(--border-radius);
|
|
1575
|
+
box-shadow: var(--shadow);
|
|
1576
|
+
}
|
|
1577
|
+
.auth-container h1 {
|
|
1578
|
+
text-align: center;
|
|
1579
|
+
margin-bottom: 2rem;
|
|
1580
|
+
color: var(--primary-color);
|
|
1581
|
+
}
|
|
1582
|
+
.form-group {
|
|
1583
|
+
margin-bottom: 1.5rem;
|
|
1584
|
+
}
|
|
1585
|
+
.form-group label {
|
|
1586
|
+
display: block;
|
|
1587
|
+
margin-bottom: 0.5rem;
|
|
1588
|
+
color: var(--dark-color);
|
|
1589
|
+
font-weight: 500;
|
|
1590
|
+
}
|
|
1591
|
+
.form-group input {
|
|
1592
|
+
width: 100%;
|
|
1593
|
+
padding: 0.75rem;
|
|
1594
|
+
border: 1px solid #ddd;
|
|
1595
|
+
border-radius: var(--border-radius);
|
|
1596
|
+
font-size: 1rem;
|
|
1597
|
+
}
|
|
1598
|
+
.form-group input:focus {
|
|
1599
|
+
outline: none;
|
|
1600
|
+
border-color: var(--primary-color);
|
|
1601
|
+
}
|
|
1602
|
+
.error-message {
|
|
1603
|
+
background: var(--danger-color);
|
|
1604
|
+
color: var(--white);
|
|
1605
|
+
padding: 0.75rem;
|
|
1606
|
+
border-radius: var(--border-radius);
|
|
1607
|
+
margin-bottom: 1rem;
|
|
1608
|
+
text-align: center;
|
|
1609
|
+
}
|
|
1610
|
+
</style>
|
|
1611
|
+
</head>
|
|
1612
|
+
<body>
|
|
1613
|
+
<header>
|
|
1614
|
+
<nav>
|
|
1615
|
+
<div class="container">
|
|
1616
|
+
<h1 class="logo">${this.config.projectName}</h1>
|
|
1617
|
+
<ul class="nav-menu">
|
|
1618
|
+
<li><a href="/">Home</a></li>
|
|
1619
|
+
<li><a href="/login">Login</a></li>
|
|
1620
|
+
<li><a href="/register" class="active">Register</a></li>
|
|
1621
|
+
</ul>
|
|
1622
|
+
</div>
|
|
1623
|
+
</nav>
|
|
1624
|
+
</header>
|
|
1625
|
+
|
|
1626
|
+
<main>
|
|
1627
|
+
<div class="auth-container">
|
|
1628
|
+
<h1>Register</h1>
|
|
1629
|
+
<% if (error) { %>
|
|
1630
|
+
<div class="error-message">Please fill all fields.</div>
|
|
1631
|
+
<% } %>
|
|
1632
|
+
<form method="POST" action="/register">
|
|
1633
|
+
<div class="form-group">
|
|
1634
|
+
<label for="username">Username</label>
|
|
1635
|
+
<input type="text" id="username" name="username" required>
|
|
1636
|
+
</div>
|
|
1637
|
+
<div class="form-group">
|
|
1638
|
+
<label for="email">Email</label>
|
|
1639
|
+
<input type="email" id="email" name="email" required>
|
|
1640
|
+
</div>
|
|
1641
|
+
<div class="form-group">
|
|
1642
|
+
<label for="password">Password</label>
|
|
1643
|
+
<input type="password" id="password" name="password" required>
|
|
1644
|
+
</div>
|
|
1645
|
+
<button type="submit" class="btn btn-primary" style="width: 100%;">Register</button>
|
|
1646
|
+
</form>
|
|
1647
|
+
<p style="text-align: center; margin-top: 1rem;">
|
|
1648
|
+
Already have an account? <a href="/login">Login here</a>
|
|
1649
|
+
</p>
|
|
1650
|
+
</div>
|
|
1651
|
+
</main>
|
|
1652
|
+
|
|
1653
|
+
<footer>
|
|
1654
|
+
<div class="container">
|
|
1655
|
+
<p>© ${new Date().getFullYear()} ${this.config.projectName}. Built with <a href="https://vako.js.org" target="_blank">Vako</a>.</p>
|
|
1656
|
+
</div>
|
|
1657
|
+
</footer>
|
|
1658
|
+
</body>
|
|
1659
|
+
</html>
|
|
1660
|
+
`;
|
|
1661
|
+
|
|
1662
|
+
fs.writeFileSync(path.join(authViewsDir, 'login.ejs'), loginView, 'utf8');
|
|
1663
|
+
fs.writeFileSync(path.join(authViewsDir, 'register.ejs'), registerView, 'utf8');
|
|
755
1664
|
}
|
|
756
1665
|
}
|
|
757
1666
|
|
package/bin/commands/setup.js
CHANGED
|
@@ -316,21 +316,28 @@ class SetupWizard {
|
|
|
316
316
|
}
|
|
317
317
|
];
|
|
318
318
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
319
|
+
try {
|
|
320
|
+
const { language } = await inquirer.prompt([{
|
|
321
|
+
type: 'list',
|
|
322
|
+
name: 'language',
|
|
323
|
+
message: '🌍 Select the language for your site:',
|
|
324
|
+
choices: languageChoices.map(choice => ({
|
|
325
|
+
name: choice.name,
|
|
326
|
+
value: choice.value
|
|
327
|
+
})),
|
|
328
|
+
pageSize: 10
|
|
329
|
+
}]);
|
|
329
330
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
331
|
+
this.config.language = language || 'fr'; // Par défaut français
|
|
332
|
+
|
|
333
|
+
const selectedChoice = languageChoices.find(c => c.value === language);
|
|
334
|
+
if (selectedChoice) {
|
|
335
|
+
console.log(chalk.gray(`\n✓ Selected: ${selectedChoice.description}\n`));
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error(chalk.red('Error selecting language:'), error.message);
|
|
339
|
+
this.config.language = 'fr'; // Par défaut français en cas d'erreur
|
|
340
|
+
}
|
|
334
341
|
}
|
|
335
342
|
|
|
336
343
|
/**
|
package/bin/vako.js
CHANGED
package/package.json
CHANGED