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.
@@ -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
- ## Documentation
303
+ L'application sera disponible sur [http://localhost:3000](http://localhost:3000)
293
304
 
294
- Visit [https://vako.js.org](https://vako.js.org) for more information.
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
- <h1><%= title %></h1>
330
- <p>${translations.welcome || 'Welcome to your Vako application!'}</p>
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>&copy; ${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>&copy; ${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'] = `body {
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: 20px;
359
- background-color: #f5f5f5;
602
+ padding: 0;
603
+ box-sizing: border-box;
360
604
  }
361
605
 
362
- h1 {
363
- color: #333;
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>&copy; ${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'] = `console.log('Vako loaded');
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
- // Create auth routes and middleware
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', { title: '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
- // Implement login logic here
742
- res.redirect('/');
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
- // Implement logout logic here
747
- res.redirect('/');
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>&copy; ${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>&copy; ${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
 
@@ -316,21 +316,28 @@ class SetupWizard {
316
316
  }
317
317
  ];
318
318
 
319
- const { language } = await inquirer.prompt([{
320
- type: 'list',
321
- name: 'language',
322
- message: '🌍 Select the language for your site:',
323
- choices: languageChoices.map(choice => ({
324
- name: choice.name,
325
- value: choice.value
326
- })),
327
- pageSize: 10
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
- this.config.language = language;
331
-
332
- const selectedChoice = languageChoices.find(c => c.value === language);
333
- console.log(chalk.gray(`\n✓ Selected: ${selectedChoice.description}\n`));
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
@@ -21,7 +21,7 @@ const program = new Command();
21
21
  program
22
22
  .name('vako')
23
23
  .description('Vako Framework CLI')
24
- .version('1.3.17');
24
+ .version('1.3.19');
25
25
 
26
26
  // ============= DEV COMMAND =============
27
27
  program
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vako",
3
- "version": "1.3.17",
3
+ "version": "1.3.19",
4
4
  "description": "🚀 Ultra-modern Node.js framework with hot reload, plugins, authentication, TypeScript support, and Next.js integration",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",