Dimdam's
Dimdam’s Git

dimdams / dimdams-docs

Documentation de Dimdams

Public
00

feat(landing): enrichissement et refonte premium de la landing page

Benladamm · il y a 7 h9acf1e7c523a parent e6f5690Parcourir les fichiers à ce commit

6 fichiers modifiés · +1448 −149

Modifiésrc/app/globals.css+742−86
@@ -301,16 +301,17 @@ kbd {
301301 top: 0;
302302 left: 50%;
303303 transform: translateX(-50%);
304− width: 900px;
305− height: 400px;
306− background: radial-gradient(ellipse 60% 50% at 50% 0%, var(--accent-glow), transparent 70%);
304+ width: 1000px;
305+ height: 520px;
306+ background: radial-gradient(ellipse 70% 50% at 50% 0%, var(--accent-glow), transparent 70%);
307307 pointer-events: none;
308308 z-index: -1;
309309 }
310310
311+/* Hero Header */
311312 .hero {
312313 text-align: center;
313− margin-bottom: 56px;
314+ margin-bottom: 48px;
314315 display: flex;
315316 flex-direction: column;
316317 align-items: center;
@@ -319,14 +320,15 @@ kbd {
319320 display: inline-flex;
320321 align-items: center;
321322 gap: 8px;
322− padding: 5px 14px;
323+ padding: 6px 16px;
323324 border-radius: 999px;
324325 border: 1px solid var(--line-2);
325326 background: var(--surface-2);
326− font-size: 12px;
327+ font-size: 12.5px;
327328 font-weight: 600;
328329 color: var(--muted);
329− margin-bottom: 20px;
330+ margin-bottom: 22px;
331+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
330332 }
331333 .live-dot {
332334 width: 7px;
@@ -336,38 +338,401 @@ kbd {
336338 box-shadow: 0 0 10px #22c55e;
337339 }
338340 .hero h1 {
339− font-size: clamp(32px, 5vw, 50px);
341+ font-family: var(--font-outfit), system-ui, sans-serif;
342+ font-size: clamp(34px, 5.2vw, 54px);
340343 font-weight: 800;
341− margin: 0 0 16px;
342− letter-spacing: -0.025em;
344+ margin: 0 0 18px;
345+ letter-spacing: -0.03em;
343346 color: var(--strong);
347+ line-height: 1.15;
344348 }
345349 .hero p {
346− max-width: 680px;
350+ max-width: 720px;
347351 margin: 0 auto;
348352 color: var(--muted);
349353 font-size: 17px;
350− line-height: 1.6;
354+ line-height: 1.65;
351355 }
352356
353−.section-label {
357+/* Hero Search Bar */
358+.hero-search-container {
359+ max-width: 740px;
360+ width: 100%;
361+ margin: 36px auto 0;
362+}
363+.hero-search-bar {
364+ width: 100%;
354365 display: flex;
355366 align-items: center;
367+ justify-content: space-between;
368+ gap: 16px;
369+ padding: 14px 20px;
370+ border-radius: 16px;
371+ background: var(--surface);
372+ border: 1px solid var(--line-2);
373+ color: var(--text);
374+ cursor: pointer;
375+ transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
376+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255, 255, 255, 0.04);
377+}
378+.hero-search-bar:hover {
379+ border-color: rgba(224, 93, 118, 0.5);
380+ background: var(--surface-2);
381+ transform: translateY(-2px);
382+ box-shadow: 0 8px 32px rgba(107, 32, 48, 0.25), 0 0 0 1px rgba(224, 93, 118, 0.2);
383+}
384+.hero-search-left {
385+ display: flex;
386+ align-items: center;
387+ gap: 12px;
388+ min-width: 0;
389+ flex: 1;
390+}
391+.hero-search-icon {
392+ color: var(--faint);
393+ flex-shrink: 0;
394+}
395+.hero-search-bar:hover .hero-search-icon {
396+ color: var(--accent-light);
397+}
398+.hero-search-text {
399+ font-size: 15px;
400+ color: var(--muted);
401+ text-align: left;
402+ overflow: hidden;
403+ text-overflow: ellipsis;
404+ white-space: nowrap;
405+}
406+.hero-search-shortcuts {
407+ display: flex;
408+ align-items: center;
409+ gap: 6px;
410+ flex-shrink: 0;
411+}
412+.hero-search-shortcuts kbd {
413+ background: var(--surface-2);
414+ border: 1px solid var(--line-2);
415+ border-radius: 6px;
416+ padding: 3px 8px;
417+ font-size: 11.5px;
418+ font-family: var(--font-mono), monospace;
419+ color: var(--muted);
420+}
421+
422+.hero-popular-tags {
423+ display: flex;
424+ align-items: center;
425+ justify-content: center;
426+ gap: 8px;
427+ margin-top: 14px;
428+ flex-wrap: wrap;
429+}
430+.hero-popular-title {
431+ font-size: 11.5px;
432+ font-weight: 700;
433+ text-transform: uppercase;
434+ letter-spacing: 0.06em;
435+ color: var(--faint);
436+}
437+.hero-tags-list {
438+ display: flex;
439+ align-items: center;
440+ gap: 6px;
441+ flex-wrap: wrap;
442+}
443+.hero-tag-pill {
444+ background: var(--surface-2);
445+ border: 1px solid var(--line);
446+ border-radius: 999px;
447+ padding: 3px 11px;
448+ font-size: 12px;
449+ font-weight: 500;
450+ color: var(--muted);
451+ cursor: pointer;
452+ transition: all 0.15s ease;
453+}
454+.hero-tag-pill:hover {
455+ color: var(--accent-light);
456+ border-color: rgba(224, 93, 118, 0.35);
457+ background: rgba(107, 32, 48, 0.15);
458+}
459+
460+/* Terminal Showcase Section */
461+.terminal-section {
462+ max-width: 960px;
463+ margin: 0 auto 56px;
464+ width: 100%;
465+}
466+.terminal-showcase {
467+ background: #08080c;
468+ border: 1px solid var(--line-2);
469+ border-radius: 18px;
470+ overflow: hidden;
471+ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.04);
472+}
473+.terminal-header {
474+ background: #0d0d14;
475+ border-bottom: 1px solid var(--line);
476+ padding: 10px 18px;
477+ display: flex;
478+ align-items: center;
479+ justify-content: space-between;
480+ flex-wrap: wrap;
481+ gap: 12px;
482+}
483+.terminal-dots {
484+ display: flex;
485+ gap: 7px;
486+ align-items: center;
487+}
488+.dot {
489+ width: 10px;
490+ height: 10px;
491+ border-radius: 999px;
492+ display: inline-block;
493+}
494+.dot-red { background: #ef4444; }
495+.dot-yellow { background: #f59e0b; }
496+.dot-green { background: #22c55e; }
497+
498+.terminal-tabs {
499+ display: flex;
500+ align-items: center;
501+ gap: 4px;
502+ overflow-x: auto;
503+}
504+.terminal-tab {
505+ background: transparent;
506+ border: 1px solid transparent;
507+ border-radius: 8px;
508+ padding: 6px 12px;
509+ display: flex;
510+ align-items: center;
511+ gap: 8px;
512+ font-size: 13px;
513+ font-weight: 500;
514+ color: var(--muted);
515+ cursor: pointer;
516+ transition: all 0.15s ease;
517+}
518+.terminal-tab:hover {
519+ color: var(--strong);
520+ background: rgba(255, 255, 255, 0.04);
521+}
522+.terminal-tab.active {
523+ color: var(--strong);
524+ background: var(--surface-2);
525+ border-color: var(--line-2);
526+ font-weight: 600;
527+}
528+.tab-badge {
529+ font-size: 10.5px;
530+ font-family: var(--font-mono), monospace;
531+ color: var(--faint);
532+ background: rgba(255, 255, 255, 0.06);
533+ padding: 1px 6px;
534+ border-radius: 4px;
535+}
536+.terminal-tab.active .tab-badge {
537+ color: var(--accent-light);
538+ background: rgba(224, 93, 118, 0.12);
539+}
540+
541+.terminal-actions {
542+ display: flex;
543+ align-items: center;
544+}
545+.terminal-copy-btn {
546+ background: var(--surface-2);
547+ border: 1px solid var(--line);
548+ border-radius: 8px;
549+ padding: 5px 12px;
550+ display: flex;
551+ align-items: center;
552+ gap: 6px;
553+ font-size: 12px;
554+ font-weight: 500;
555+ color: var(--muted);
556+ cursor: pointer;
557+ transition: all 0.15s;
558+}
559+.terminal-copy-btn:hover {
560+ color: var(--strong);
561+ border-color: var(--line-2);
562+ background: rgba(255, 255, 255, 0.08);
563+}
564+.copied-text {
565+ color: #34d399;
566+ font-weight: 600;
567+}
568+
569+.terminal-body {
570+ padding: 22px 24px;
571+ overflow-x: auto;
572+ font-family: var(--font-mono), monospace;
573+ font-size: 13.5px;
574+ line-height: 1.65;
575+ background: #060609;
576+}
577+.terminal-pre {
578+ margin: 0;
579+ background: transparent !important;
580+ border: none !important;
581+ padding: 0 !important;
582+}
583+.terminal-line {
584+ display: flex;
585+ gap: 18px;
586+ align-items: baseline;
587+}
588+.line-num {
589+ color: rgba(255, 255, 255, 0.2);
590+ user-select: none;
591+ min-width: 20px;
592+ text-align: right;
593+ font-size: 12px;
594+}
595+.token-comment {
596+ color: #6b7280;
597+ font-style: italic;
598+}
599+.token-output {
600+ color: #34d399;
601+ font-weight: 500;
602+}
603+.token-command {
604+ color: #f3b4c1;
605+ font-weight: 600;
606+}
607+.token-plain {
608+ color: #d1d5db;
609+}
610+
611+.terminal-footer {
612+ background: #09090e;
613+ border-top: 1px solid var(--line);
614+ padding: 9px 20px;
615+ display: flex;
616+ align-items: center;
617+ justify-content: space-between;
618+ font-size: 12px;
619+ color: var(--faint);
620+ flex-wrap: wrap;
621+ gap: 10px;
622+}
623+.terminal-status-left {
624+ display: flex;
625+ align-items: center;
626+ gap: 8px;
627+}
628+.terminal-status-right {
629+ display: flex;
630+ align-items: center;
631+ gap: 8px;
632+}
633+.pulse-dot {
634+ width: 7px;
635+ height: 7px;
636+ border-radius: 999px;
637+ background: #22c55e;
638+ box-shadow: 0 0 8px #22c55e;
639+ display: inline-block;
640+ animation: pulse-ring 2s infinite ease-in-out;
641+}
642+@keyframes pulse-ring {
643+ 0%, 100% { opacity: 1; transform: scale(1); }
644+ 50% { opacity: 0.45; transform: scale(0.9); }
645+}
646+
647+/* Metrics Strip */
648+.metrics-strip {
649+ display: grid;
650+ grid-template-columns: repeat(4, 1fr);
651+ align-items: center;
652+ background: var(--surface);
653+ border: 1px solid var(--line);
654+ border-radius: 18px;
655+ padding: 24px 20px;
656+ margin-bottom: 64px;
657+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
658+}
659+.metric-item {
660+ display: flex;
661+ flex-direction: column;
662+ align-items: center;
663+ text-align: center;
664+ gap: 4px;
665+ padding: 0 12px;
666+}
667+.metric-val {
668+ font-family: var(--font-outfit), sans-serif;
669+ font-size: 32px;
670+ font-weight: 800;
671+ color: var(--strong);
672+ letter-spacing: -0.02em;
673+}
674+.metric-label {
675+ font-size: 13px;
676+ color: var(--muted);
677+ font-weight: 500;
678+ line-height: 1.4;
679+}
680+.metric-separator {
681+ display: none;
682+}
683+@media (max-width: 860px) {
684+ .metrics-strip {
685+ grid-template-columns: repeat(2, 1fr);
686+ gap: 24px;
687+ }
688+}
689+@media (max-width: 500px) {
690+ .metrics-strip {
691+ grid-template-columns: 1fr;
692+ gap: 20px;
693+ }
694+}
695+
696+/* Section Group Headers */
697+.section-heading-group {
698+ text-align: left;
699+ margin-bottom: 32px;
700+}
701+.section-label {
702+ display: inline-flex;
703+ align-items: center;
356704 gap: 8px;
357705 font-size: 12px;
358706 font-weight: 700;
359707 text-transform: uppercase;
360708 letter-spacing: 0.08em;
361− color: var(--faint);
362− margin-bottom: 18px;
709+ color: var(--accent-light);
710+ margin-bottom: 8px;
711+}
712+.section-title {
713+ font-family: var(--font-outfit), sans-serif;
714+ font-size: clamp(24px, 3.5vw, 32px);
715+ font-weight: 800;
716+ color: var(--strong);
717+ margin: 0 0 8px;
718+ letter-spacing: -0.02em;
719+}
720+.section-subtitle {
721+ color: var(--muted);
722+ font-size: 15px;
723+ margin: 0;
724+ max-width: 680px;
725+ line-height: 1.6;
363726 }
364727
365−/* Cards Section */
366−.cards-section { margin-bottom: 56px; }
728+/* 4 Core Cards Section */
729+.cards-section {
730+ margin-bottom: 64px;
731+}
367732 .cards {
368733 display: grid;
369734 grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
370− gap: 20px;
735+ gap: 22px;
371736 }
372737 .card {
373738 display: flex;
@@ -376,16 +741,14 @@ kbd {
376741 border-radius: 18px;
377742 border: 1px solid var(--line);
378743 background: var(--surface);
379− text-decoration: none;
380− color: var(--text);
381744 position: relative;
382745 transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
383− box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
746+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);
384747 }
385748 .card:hover {
386749 border-color: rgba(224, 93, 118, 0.4);
387− transform: translateY(-3px);
388− box-shadow: 0 12px 30px rgba(107, 32, 48, 0.2);
750+ transform: translateY(-4px);
751+ box-shadow: 0 16px 36px rgba(107, 32, 48, 0.22);
389752 }
390753 .card-header {
391754 display: flex;
@@ -394,8 +757,8 @@ kbd {
394757 margin-bottom: 16px;
395758 }
396759 .card-icon {
397− width: 44px;
398− height: 44px;
760+ width: 46px;
761+ height: 46px;
399762 border-radius: 12px;
400763 background: rgba(107, 32, 48, 0.18);
401764 border: 1px solid rgba(107, 32, 48, 0.35);
@@ -409,140 +772,433 @@ kbd {
409772 font-weight: 700;
410773 text-transform: uppercase;
411774 letter-spacing: 0.06em;
412− padding: 3px 9px;
775+ padding: 4px 10px;
413776 border-radius: 999px;
414777 border: 1px solid var(--line-2);
415778 background: var(--surface-2);
416779 color: var(--muted);
417780 }
418−.card h2 {
781+.card h3 {
782+ font-family: var(--font-outfit), sans-serif;
419783 margin: 0 0 8px;
420784 font-size: 21px;
421785 font-weight: 700;
422786 letter-spacing: -0.01em;
787+ color: var(--strong);
423788 }
424789 .card-desc {
425− margin: 0 0 18px;
790+ margin: 0 0 16px;
426791 color: var(--muted);
427792 font-size: 13.5px;
428793 line-height: 1.55;
429− flex: 1;
430794 }
431−.card-links {
795+
796+.card-highlights {
797+ margin: 0 0 16px;
798+ padding: 12px 14px;
799+ border-radius: 12px;
800+ background: var(--surface-2);
801+ border: 1px solid var(--line);
802+}
803+.card-highlights-title {
804+ font-size: 10.5px;
805+ font-weight: 700;
806+ text-transform: uppercase;
807+ letter-spacing: 0.06em;
808+ color: var(--faint);
809+ margin-bottom: 8px;
810+ display: block;
811+}
812+.card-highlights ul {
432813 list-style: none;
433− margin: 0 0 20px;
814+ margin: 0;
434815 padding: 0;
435816 display: flex;
436817 flex-direction: column;
437− gap: 6px;
818+ gap: 5px;
438819 }
439−.card-links li {
440− font-size: 13px;
820+.card-highlights li {
821+ font-size: 12.5px;
441822 color: var(--muted);
442823 display: flex;
443824 align-items: center;
444825 gap: 8px;
445826 }
446−.card-links li::before {
447− content: "";
827+.highlight-bullet {
448828 width: 5px;
449829 height: 5px;
450830 border-radius: 999px;
451− background: var(--faint);
831+ background: var(--accent-light);
452832 flex-shrink: 0;
453833 }
834+
835+.card-top-articles {
836+ margin-bottom: 20px;
837+ flex: 1;
838+}
839+.card-top-title {
840+ font-size: 10.5px;
841+ font-weight: 700;
842+ text-transform: uppercase;
843+ letter-spacing: 0.06em;
844+ color: var(--faint);
845+ margin-bottom: 8px;
846+ display: block;
847+}
848+.card-article-links {
849+ display: flex;
850+ flex-direction: column;
851+ gap: 4px;
852+}
853+.card-article-item {
854+ display: flex;
855+ align-items: center;
856+ justify-content: space-between;
857+ padding: 7px 10px;
858+ border-radius: 8px;
859+ background: transparent;
860+ border: 1px solid transparent;
861+ font-size: 13px;
862+ color: var(--text);
863+ text-decoration: none;
864+ transition: all 0.15s ease;
865+}
866+.card-article-item:hover {
867+ background: var(--surface-2);
868+ border-color: var(--line);
869+ color: var(--strong);
870+}
871+.article-arrow {
872+ color: var(--faint);
873+ transition: transform 0.15s, color 0.15s;
874+}
875+.card-article-item:hover .article-arrow {
876+ color: var(--accent-light);
877+ transform: translateX(2px);
878+}
879+
454880 .card-footer {
455881 display: flex;
456882 align-items: center;
457883 justify-content: space-between;
458− padding-top: 14px;
884+ padding-top: 16px;
459885 border-top: 1px solid var(--line);
460886 font-size: 13px;
461887 }
462−.page-count { color: var(--faint); font-weight: 500; font-size: 12px; }
888+.page-count {
889+ color: var(--faint);
890+ font-weight: 500;
891+ font-size: 12px;
892+}
463893 .card-cta {
464894 color: var(--accent-light);
465895 font-weight: 600;
466896 display: inline-flex;
467897 align-items: center;
468− gap: 5px;
898+ gap: 6px;
899+ text-decoration: none;
469900 transition: transform 0.15s;
470901 }
471−.card:hover .card-cta { transform: translateX(3px); }
472−
473−/* Quick Start Grid */
474−.quickstart-section { margin-bottom: 40px; }
475−.quickstart-grid {
476− display: grid;
477− grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
478− gap: 16px;
902+.card-cta:hover {
903+ transform: translateX(3px);
904+ color: var(--accent-soft);
479905 }
480−.quick-card {
906+
907+/* Stacks / Frameworks Grid */
908+.stacks-section {
909+ margin-bottom: 64px;
910+}
911+.stacks-grid {
912+ display: grid;
913+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
914+ gap: 18px;
915+}
916+.stack-card {
481917 display: flex;
482− align-items: center;
483− gap: 14px;
484− padding: 18px 20px;
485− border-radius: 14px;
486− border: 1px solid var(--line);
918+ flex-direction: column;
919+ padding: 22px;
920+ border-radius: 16px;
487921 background: var(--surface);
922+ border: 1px solid var(--line);
488923 text-decoration: none;
489924 color: var(--text);
490− transition: all 0.15s ease;
925+ transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
491926 }
492−.quick-card:hover {
927+.stack-card:hover {
928+ border-color: rgba(224, 93, 118, 0.35);
929+ background: var(--surface-2);
930+ transform: translateY(-3px);
931+ box-shadow: 0 10px 28px rgba(0, 0, 0, 0.25);
932+}
933+.stack-header {
934+ display: flex;
935+ align-items: center;
936+ justify-content: space-between;
937+ margin-bottom: 12px;
938+}
939+.stack-icon {
940+ width: 40px;
941+ height: 40px;
942+ border-radius: 10px;
943+ background: rgba(107, 32, 48, 0.15);
944+ border: 1px solid rgba(107, 32, 48, 0.3);
945+ color: var(--accent-light);
946+ display: flex;
947+ align-items: center;
948+ justify-content: center;
949+}
950+.stack-badge {
951+ font-size: 10.5px;
952+ font-weight: 700;
953+ text-transform: uppercase;
954+ letter-spacing: 0.05em;
955+ padding: 3px 9px;
956+ border-radius: 999px;
957+ background: var(--surface-2);
958+ border: 1px solid var(--line-2);
959+ color: var(--muted);
960+}
961+.stack-card h4 {
962+ font-family: var(--font-outfit), sans-serif;
963+ margin: 0 0 6px;
964+ font-size: 17px;
965+ font-weight: 700;
966+ color: var(--strong);
967+}
968+.stack-card p {
969+ margin: 0 0 16px;
970+ font-size: 13px;
971+ color: var(--muted);
972+ line-height: 1.5;
973+ flex: 1;
974+}
975+.stack-link {
976+ display: flex;
977+ align-items: center;
978+ gap: 6px;
979+ font-size: 13px;
980+ font-weight: 600;
981+ color: var(--accent-light);
982+ transition: transform 0.15s;
983+}
984+.stack-card:hover .stack-link {
985+ transform: translateX(3px);
986+}
987+
988+/* Architecture & Engagements Grid */
989+.architecture-section {
990+ margin-bottom: 64px;
991+}
992+.architecture-grid {
993+ display: grid;
994+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
995+ gap: 18px;
996+}
997+.architecture-card {
998+ padding: 24px;
999+ border-radius: 16px;
1000+ background: var(--surface);
1001+ border: 1px solid var(--line);
1002+ display: flex;
1003+ flex-direction: column;
1004+}
1005+.architecture-icon {
1006+ width: 44px;
1007+ height: 44px;
1008+ border-radius: 12px;
1009+ background: var(--surface-2);
1010+ border: 1px solid var(--line-2);
1011+ color: var(--accent-light);
1012+ display: flex;
1013+ align-items: center;
1014+ justify-content: center;
1015+ margin-bottom: 14px;
1016+}
1017+.architecture-card h4 {
1018+ font-family: var(--font-outfit), sans-serif;
1019+ margin: 0 0 8px;
1020+ font-size: 16px;
1021+ font-weight: 700;
1022+ color: var(--strong);
1023+}
1024+.architecture-card p {
1025+ margin: 0;
1026+ font-size: 13.5px;
1027+ color: var(--muted);
1028+ line-height: 1.55;
1029+}
1030+
1031+/* Ecosystem Connected Services */
1032+.ecosystem-section {
1033+ margin-bottom: 64px;
1034+}
1035+.ecosystem-grid {
1036+ display: grid;
1037+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
1038+ gap: 20px;
1039+}
1040+.ecosystem-card {
1041+ padding: 24px;
1042+ border-radius: 16px;
1043+ background: var(--surface);
1044+ border: 1px solid var(--line);
1045+ text-decoration: none;
1046+ color: var(--text);
1047+ display: flex;
1048+ flex-direction: column;
1049+ transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
1050+}
1051+.ecosystem-card:hover {
4931052 border-color: var(--line-2);
4941053 background: var(--surface-2);
4951054 transform: translateY(-2px);
1055+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
4961056 }
497−.quick-icon {
498− width: 38px;
499− height: 38px;
500− border-radius: 10px;
1057+.ecosystem-card-top {
1058+ display: flex;
1059+ align-items: center;
1060+ justify-content: space-between;
1061+ margin-bottom: 14px;
1062+}
1063+.ecosystem-icon {
1064+ width: 44px;
1065+ height: 44px;
1066+ border-radius: 12px;
5011067 background: var(--surface-2);
5021068 border: 1px solid var(--line-2);
5031069 color: var(--muted);
5041070 display: flex;
5051071 align-items: center;
5061072 justify-content: center;
507− flex-shrink: 0;
5081073 }
509−.quick-card:hover .quick-icon {
1074+.ecosystem-icon.status-green {
1075+ background: rgba(34, 197, 94, 0.12);
1076+ border-color: rgba(34, 197, 94, 0.25);
1077+ color: #22c55e;
1078+}
1079+.status-live-badge {
1080+ display: inline-flex;
1081+ align-items: center;
1082+ gap: 7px;
1083+ padding: 4px 11px;
1084+ border-radius: 999px;
1085+ background: rgba(34, 197, 94, 0.1);
1086+ border: 1px solid rgba(34, 197, 94, 0.25);
1087+ font-size: 11px;
1088+ font-weight: 600;
1089+ color: #4ade80;
1090+}
1091+.ecosystem-card h4 {
1092+ font-family: var(--font-outfit), sans-serif;
1093+ margin: 0 0 6px;
1094+ font-size: 17px;
1095+ font-weight: 700;
1096+ color: var(--strong);
1097+}
1098+.ecosystem-card p {
1099+ margin: 0 0 16px;
1100+ font-size: 13px;
1101+ color: var(--muted);
1102+ line-height: 1.5;
1103+ flex: 1;
1104+}
1105+.ecosystem-card-link {
1106+ display: flex;
1107+ align-items: center;
1108+ gap: 6px;
1109+ font-size: 12.5px;
1110+ font-family: var(--font-mono), monospace;
1111+ color: var(--faint);
1112+}
1113+.ecosystem-card:hover .ecosystem-card-link {
5101114 color: var(--accent-light);
511− border-color: rgba(224, 93, 118, 0.3);
5121115 }
513−.quick-content { flex: 1; min-width: 0; }
514−.quick-badge {
515− display: inline-block;
516− font-size: 10.5px;
1116+
1117+/* Support & Assistance Banner */
1118+.support-banner {
1119+ display: flex;
1120+ align-items: center;
1121+ justify-content: space-between;
1122+ padding: 36px 40px;
1123+ border-radius: 20px;
1124+ background: linear-gradient(135deg, rgba(107, 32, 48, 0.22) 0%, var(--surface) 60%);
1125+ border: 1px solid rgba(107, 32, 48, 0.4);
1126+ box-shadow: 0 12px 36px rgba(0, 0, 0, 0.3);
1127+ flex-wrap: wrap;
1128+ gap: 24px;
1129+}
1130+.support-banner-content {
1131+ flex: 1;
1132+ min-width: 280px;
1133+ max-width: 650px;
1134+}
1135+.support-badge {
1136+ display: inline-flex;
1137+ align-items: center;
1138+ gap: 8px;
1139+ font-size: 11px;
5171140 font-weight: 700;
5181141 text-transform: uppercase;
5191142 letter-spacing: 0.06em;
5201143 color: var(--accent-light);
521− margin-bottom: 2px;
1144+ margin-bottom: 10px;
5221145 }
523−.quick-card h3 {
1146+.support-banner-content h3 {
1147+ font-family: var(--font-outfit), sans-serif;
1148+ margin: 0 0 8px;
1149+ font-size: 22px;
1150+ font-weight: 700;
1151+ color: var(--strong);
1152+}
1153+.support-banner-content p {
5241154 margin: 0;
5251155 font-size: 14.5px;
1156+ color: var(--muted);
1157+ line-height: 1.6;
1158+}
1159+.support-banner-actions {
1160+ display: flex;
1161+ align-items: center;
1162+ gap: 12px;
1163+ flex-wrap: wrap;
1164+}
1165+.btn-support-primary {
1166+ display: inline-flex;
1167+ align-items: center;
1168+ gap: 8px;
1169+ padding: 12px 22px;
1170+ border-radius: 12px;
1171+ background: var(--accent);
1172+ color: #ffffff;
5261173 font-weight: 600;
1174+ font-size: 14px;
1175+ text-decoration: none;
1176+ transition: all 0.15s ease;
1177+ box-shadow: 0 4px 14px rgba(107, 32, 48, 0.4);
1178+}
1179+.btn-support-primary:hover {
1180+ background: var(--accent-hover);
1181+ transform: translateY(-1px);
1182+ color: #ffffff;
1183+}
1184+.btn-support-secondary {
1185+ display: inline-flex;
1186+ align-items: center;
1187+ gap: 8px;
1188+ padding: 12px 20px;
1189+ border-radius: 12px;
1190+ background: var(--surface-2);
1191+ border: 1px solid var(--line-2);
1192+ color: var(--text);
1193+ font-weight: 600;
1194+ font-size: 14px;
1195+ text-decoration: none;
1196+ transition: all 0.15s ease;
1197+}
1198+.btn-support-secondary:hover {
1199+ background: rgba(255, 255, 255, 0.08);
5271200 color: var(--strong);
5281201 }
529−.quick-card p {
530− margin: 2px 0 0;
531− font-size: 12.5px;
532− color: var(--faint);
533− overflow: hidden;
534− text-overflow: ellipsis;
535− white-space: nowrap;
536−}
537−.quick-arrow {
538− color: var(--faint);
539− flex-shrink: 0;
540− transition: transform 0.15s, color 0.15s;
541−}
542−.quick-card:hover .quick-arrow {
543− color: var(--strong);
544− transform: translateX(3px);
545−}
5461202
5471203 /* Documentation page */
5481204 .doc {
Modifiésrc/app/page.tsx+337−60
@@ -1,6 +1,8 @@
11 import Link from "next/link";
22 import { listPages } from "@/lib/content";
33 import { SECTIONS } from "@/lib/sections";
4+import { HeroSearch } from "@/components/HeroSearch";
5+import { TerminalShowcase } from "@/components/TerminalShowcase";
46 import {
57 IconServer,
68 IconTerminal,
@@ -9,6 +11,14 @@ import {
911 IconArrowRight,
1012 IconBookOpen,
1113 IconCode,
14+ IconShield,
15+ IconDatabase,
16+ IconLock,
17+ IconGlobe,
18+ IconExternalLink,
19+ IconZap,
20+ IconPackage,
21+ IconCpu,
1222 } from "@/components/Icons";
1323
1424 const SECTION_ICONS: Record<string, typeof IconServer> = {
@@ -25,34 +35,98 @@ const SECTION_BADGES: Record<string, string> = {
2535 status: "Haute Disponibilité",
2636 };
2737
28−const QUICK_STARTS = [
38+const SECTION_HIGHLIGHTS: Record<string, string[]> = {
39+ hebergement: [
40+ "Serveurs VPS NVMe & Accès root SSH",
41+ "Bases de données PostgreSQL & MariaDB",
42+ "Déploiements continus Git & Webhooks",
43+ "Sauvegardes automatiques & Snapshots",
44+ ],
45+ api: [
46+ "Jetons sécurisés préfixés dim_live_",
47+ "Gestion programmatique des services",
48+ "Pare-feu applicatif WAF & Règles réseau",
49+ "Métriques de charge & Journal d'audit",
50+ ],
51+ git: [
52+ "Dépôts privés illimités hébergés en France",
53+ "Pipelines CI/CD & Actions intégrées",
54+ "Registre de paquets (npm, Docker, PyPI)",
55+ "Hébergement statique Dimdam's Pages",
56+ ],
57+ status: [
58+ "Sondes réseau distribuées multi-protocoles",
59+ "Suivi de latence et temps de réponse",
60+ "Historique des incidents et alertes",
61+ "API publique Heartbeat en direct (JSON)",
62+ ],
63+};
64+
65+const STACK_CARDS = [
2966 {
30− title: "Déploiement Git continu",
31− desc: "Connecter vos dépôts pour déployer automatiquement à chaque push.",
67+ title: "Node.js & Next.js",
68+ badge: "SSR & Fullstack",
69+ desc: "Applications SSR, workers PM2 et déploiement continu à chaque git push.",
3270 href: "/hebergement/deploiement-git/",
33− section: "Hébergement",
34− icon: IconGitBranch,
71+ icon: IconZap,
3572 },
3673 {
37− title: "Authentification API",
38− desc: "Générer un jeton dim_live_ et configurer les permissions requises.",
39− href: "/api/",
40− section: "API & CLI",
74+ title: "Python & Bots",
75+ badge: "Workers & APIs",
76+ desc: "Bots Discord, scripts d'automatisation et micro-services FastAPI résilients.",
77+ href: "/hebergement/bots/",
4178 icon: IconCode,
4279 },
4380 {
44− title: "Accès SSH & Terminal VPS",
45− desc: "Se connecter directement en SSH sur le port 22 ou via le shell web.",
46− href: "/hebergement/vps/",
47− section: "Hébergement",
48− icon: IconTerminal,
81+ title: "Bases de données SQL",
82+ badge: "PostgreSQL & MariaDB",
83+ desc: "Instances managées avec accès direct, rétention et snapshots quotidiens.",
84+ href: "/hebergement/bases-de-donnees/",
85+ icon: IconDatabase,
4986 },
5087 {
51− title: "Heartbeat & API Statut",
52− desc: "Interroger les métriques de disponibilité et l'état des sondes en JSON.",
53− href: "/status/api/",
54− section: "Dimdam's Status",
55− icon: IconActivity,
88+ title: "Serveurs VPS Linux",
89+ badge: "Debian & Ubuntu",
90+ desc: "Accès root SSH sur le port 22, stockage NVMe haute performance et pare-feu.",
91+ href: "/hebergement/vps/",
92+ icon: IconCpu,
93+ },
94+ {
95+ title: "Forge Git & CI/CD",
96+ badge: "Actions & Pipelines",
97+ desc: "Automatisez vos tests, vos builds et vos paquets sur notre forge souveraine.",
98+ href: "/git/automatisation/",
99+ icon: IconGitBranch,
100+ },
101+ {
102+ title: "API REST & CLI",
103+ badge: "dimdams CLI",
104+ desc: "Pilotez l'infrastructure depuis vos scripts avec notre binaire officiel et l'API v1.",
105+ href: "/api/",
106+ icon: IconTerminal,
107+ },
108+];
109+
110+const ARCHITECTURE_PILLARS = [
111+ {
112+ title: "Protection Anti-DDoS & WAF",
113+ desc: "Filtrage volumétrique automatique, pare-feu applicatif WAF et gestion centralisée des certificats SSL/TLS Let's Encrypt.",
114+ icon: IconShield,
115+ },
116+ {
117+ title: "Sauvegardes & Snapshots",
118+ desc: "Sauvegardes automatiques quotidiennes, isolation des volumes et restauration instantanée depuis la console de gestion.",
119+ icon: IconDatabase,
120+ },
121+ {
122+ title: "Contrôle d'Accès & Clés",
123+ desc: "Authentification par clés SSH ed25519, tokens d'API avec permissions granulaires révocables et journal d'audit immuable.",
124+ icon: IconLock,
125+ },
126+ {
127+ title: "100% Souveraineté France",
128+ desc: "Infrastructure et données exclusivement hébergées en France métropolitaine, conformité RGPD stricte et zéro dépendance cloud tiers.",
129+ icon: IconGlobe,
56130 },
57131 ];
58132
@@ -63,49 +137,145 @@ export default function Home() {
63137 <section className="hero">
64138 <div className="hero-badge">
65139 <span className="live-dot" />
66− <span>Documentation technique officielle</span>
140+ <span>Documentation Officielle · Plateforme v2.4 Souveraine</span>
67141 </div>
68− <h1>Tout l&apos;écosystème Dimdam&apos;s documenté.</h1>
142+ <h1>Tout l&apos;écosystème Dimdam&apos;s, documenté en détail.</h1>
69143 <p>
70− Guides de configuration, tutoriels pas-à-pas pour vos conteneurs et VPS,
71− spécification exhaustive de l&apos;API REST et intégration de la forge logicielle.
144+ Guides d&apos;architecture, référence exhaustive de l&apos;API REST, gestion de vos
145+ conteneurs, bases de données et serveurs VPS souverains hébergés en France.
72146 </p>
147+
148+ {/* Global Search Bar */}
149+ <HeroSearch />
73150 </section>
74151
75− {/* Main 4 Products Grid */}
76− <section className="cards-section">
77− <div className="section-label">
78− <IconBookOpen width={16} height={16} />
79− <span>Produits & Services</span>
152+ {/* Developer Terminal Showcase */}
153+ <section className="terminal-section">
154+ <TerminalShowcase />
155+ </section>
156+
157+ {/* Metrics / Ecosystem Stats */}
158+ <section className="metrics-strip">
159+ <div className="metric-item">
160+ <span className="metric-val">4</span>
161+ <span className="metric-label">Pôles d&apos;ingénierie documentés</span>
80162 </div>
163+ <div className="metric-separator" />
164+ <div className="metric-item">
165+ <span className="metric-val">33+</span>
166+ <span className="metric-label">Guides techniques et références</span>
167+ </div>
168+ <div className="metric-separator" />
169+ <div className="metric-item">
170+ <span className="metric-val">100%</span>
171+ <span className="metric-label">Infrastructure hébergée en France</span>
172+ </div>
173+ <div className="metric-separator" />
174+ <div className="metric-item">
175+ <span className="metric-val">99.98%</span>
176+ <span className="metric-label">Disponibilité constatée et sondée</span>
177+ </div>
178+ </section>
179+
180+ {/* 4 Core Products Grid */}
181+ <section className="cards-section">
182+ <div className="section-heading-group">
183+ <div className="section-label">
184+ <IconBookOpen width={16} height={16} />
185+ <span>Piliers de l&apos;infrastructure</span>
186+ </div>
187+ <h2 className="section-title">Explorez par produit & service</h2>
188+ <p className="section-subtitle">
189+ Accédez aux manuels complets, configurations recommandées et spécifications de chaque composant.
190+ </p>
191+ </div>
192+
81193 <div className="cards">
82194 {SECTIONS.map((s) => {
83195 const pages = listPages(s.id).filter((p) => p.slug !== "index");
84196 const Icon = SECTION_ICONS[s.id] ?? IconBookOpen;
85197 const badge = SECTION_BADGES[s.id] ?? "Documentation";
198+ const highlights = SECTION_HIGHLIGHTS[s.id] ?? [];
86199
87200 return (
88− <Link key={s.id} href={`/${s.id}/`} className="card">
201+ <div key={s.id} className="card">
89202 <div className="card-header">
90203 <div className="card-icon">
91− <Icon width={22} height={22} />
204+ <Icon width={24} height={24} />
92205 </div>
93206 <span className="card-pill">{badge}</span>
94207 </div>
95− <h2>{s.title}</h2>
208+
209+ <h3>{s.title}</h3>
96210 <p className="card-desc">{s.description}</p>
97− <ul className="card-links">
98− {pages.slice(0, 4).map((p) => (
99− <li key={p.slug}>
100− <span>{p.title}</span>
101− </li>
102− ))}
103− </ul>
211+
212+ {/* Key Capabilities */}
213+ <div className="card-highlights">
214+ <span className="card-highlights-title">Fonctionnalités clés :</span>
215+ <ul>
216+ {highlights.map((h, idx) => (
217+ <li key={idx}>
218+ <span className="highlight-bullet" />
219+ <span>{h}</span>
220+ </li>
221+ ))}
222+ </ul>
223+ </div>
224+
225+ {/* Direct Links to top articles */}
226+ <div className="card-top-articles">
227+ <span className="card-top-title">Articles populaires :</span>
228+ <div className="card-article-links">
229+ {pages.slice(0, 3).map((p) => (
230+ <Link key={p.slug} href={p.href} className="card-article-item">
231+ <span>{p.title}</span>
232+ <IconArrowRight width={12} height={12} className="article-arrow" />
233+ </Link>
234+ ))}
235+ </div>
236+ </div>
237+
104238 <div className="card-footer">
105− <span className="page-count">{pages.length} articles</span>
106− <span className="card-cta">
107− Explorer <IconArrowRight width={14} height={14} />
108− </span>
239+ <span className="page-count">{pages.length} guides détaillés</span>
240+ <Link href={`/${s.id}/`} className="card-cta">
241+ Explorer la section <IconArrowRight width={14} height={14} />
242+ </Link>
243+ </div>
244+ </div>
245+ );
246+ })}
247+ </div>
248+ </section>
249+
250+ {/* Démarrage rapide par stack */}
251+ <section className="stacks-section">
252+ <div className="section-heading-group">
253+ <div className="section-label">
254+ <IconTerminal width={16} height={16} />
255+ <span>Déploiement & Cas d&apos;usage</span>
256+ </div>
257+ <h2 className="section-title">Démarrages rapides par technologie</h2>
258+ <p className="section-subtitle">
259+ Guides orientés code et déploiement pour initialiser vos projets en quelques minutes.
260+ </p>
261+ </div>
262+
263+ <div className="stacks-grid">
264+ {STACK_CARDS.map((item) => {
265+ const Icon = item.icon;
266+ return (
267+ <Link key={item.title} href={item.href} className="stack-card">
268+ <div className="stack-header">
269+ <div className="stack-icon">
270+ <Icon width={20} height={20} />
271+ </div>
272+ <span className="stack-badge">{item.badge}</span>
273+ </div>
274+ <h4>{item.title}</h4>
275+ <p>{item.desc}</p>
276+ <div className="stack-link">
277+ <span>Consulter le guide</span>
278+ <IconArrowRight width={14} height={14} />
109279 </div>
110280 </Link>
111281 );
@@ -113,31 +283,138 @@ export default function Home() {
113283 </div>
114284 </section>
115285
116− {/* Quick Start / Most Visited Guides */}
117− <section className="quickstart-section">
118− <div className="section-label">
119− <IconTerminal width={16} height={16} />
120− <span>Démarrage rapide & Guides essentiels</span>
286+ {/* Architecture, Sécurité & Souveraineté */}
287+ <section className="architecture-section">
288+ <div className="section-heading-group">
289+ <div className="section-label">
290+ <IconShield width={16} height={16} />
291+ <span>Architecture & Sécurité</span>
292+ </div>
293+ <h2 className="section-title">Engagements techniques & fiabilité</h2>
294+ <p className="section-subtitle">
295+ Une infrastructure souveraine conçue pour la protection des données et la haute disponibilité.
296+ </p>
121297 </div>
122− <div className="quickstart-grid">
123− {QUICK_STARTS.map((q) => {
124− const Icon = q.icon;
298+
299+ <div className="architecture-grid">
300+ {ARCHITECTURE_PILLARS.map((pillar) => {
301+ const Icon = pillar.icon;
125302 return (
126− <Link key={q.href} href={q.href} className="quick-card">
127− <div className="quick-icon">
128− <Icon width={18} height={18} />
303+ <div key={pillar.title} className="architecture-card">
304+ <div className="architecture-icon">
305+ <Icon width={22} height={22} />
129306 </div>
130− <div className="quick-content">
131− <span className="quick-badge">{q.section}</span>
132− <h3>{q.title}</h3>
133− <p>{q.desc}</p>
134− </div>
135− <IconArrowRight width={16} height={16} className="quick-arrow" />
136− </Link>
307+ <h4>{pillar.title}</h4>
308+ <p>{pillar.desc}</p>
309+ </div>
137310 );
138311 })}
139312 </div>
140313 </section>
314+
315+ {/* External Ecosystem Links */}
316+ <section className="ecosystem-section">
317+ <div className="section-heading-group">
318+ <div className="section-label">
319+ <IconGlobe width={16} height={16} />
320+ <span>Écosystème Dimdam&apos;s</span>
321+ </div>
322+ <h2 className="section-title">Plateformes & Outils connectés</h2>
323+ <p className="section-subtitle">
324+ Accédez directement à vos services, vos dépôts de code et aux sondes de surveillance.
325+ </p>
326+ </div>
327+
328+ <div className="ecosystem-grid">
329+ <a
330+ href="https://status.dimdams.com"
331+ target="_blank"
332+ rel="noopener noreferrer"
333+ className="ecosystem-card"
334+ >
335+ <div className="ecosystem-card-top">
336+ <div className="ecosystem-icon status-green">
337+ <IconActivity width={22} height={22} />
338+ </div>
339+ <div className="status-live-badge">
340+ <span className="pulse-dot" />
341+ <span>Tous systèmes opérationnels</span>
342+ </div>
343+ </div>
344+ <h4>Dimdam&apos;s Status</h4>
345+ <p>Supervisez en direct l&apos;état des serveurs, la latence moyenne et les incidents passés.</p>
346+ <div className="ecosystem-card-link">
347+ <span>status.dimdams.com</span>
348+ <IconExternalLink width={14} height={14} />
349+ </div>
350+ </a>
351+
352+ <a
353+ href="https://git.dimdams.com"
354+ target="_blank"
355+ rel="noopener noreferrer"
356+ className="ecosystem-card"
357+ >
358+ <div className="ecosystem-card-top">
359+ <div className="ecosystem-icon">
360+ <IconGitBranch width={22} height={22} />
361+ </div>
362+ <span className="card-pill">Forge Git</span>
363+ </div>
364+ <h4>Dimdam&apos;s Git</h4>
365+ <p>Hébergez vos dépôts en France, configurez vos pipelines CI/CD et gérez vos paquets.</p>
366+ <div className="ecosystem-card-link">
367+ <span>git.dimdams.com</span>
368+ <IconExternalLink width={14} height={14} />
369+ </div>
370+ </a>
371+
372+ <a
373+ href="https://dimdams.com"
374+ target="_blank"
375+ rel="noopener noreferrer"
376+ className="ecosystem-card"
377+ >
378+ <div className="ecosystem-card-top">
379+ <div className="ecosystem-icon">
380+ <IconServer width={22} height={22} />
381+ </div>
382+ <span className="card-pill">Console Client</span>
383+ </div>
384+ <h4>Tableau de bord Dimdam&apos;s</h4>
385+ <p>Commandez vos instances, gérez vos clés d&apos;API, vos domaines et vos quotas de facturation.</p>
386+ <div className="ecosystem-card-link">
387+ <span>dimdams.com</span>
388+ <IconExternalLink width={14} height={14} />
389+ </div>
390+ </a>
391+ </div>
392+ </section>
393+
394+ {/* Support & Assistance Banner */}
395+ <section className="support-banner">
396+ <div className="support-banner-content">
397+ <div className="support-badge">
398+ <IconPackage width={16} height={16} />
399+ <span>Support & Accompagnement</span>
400+ </div>
401+ <h3>Besoin d&apos;un accompagnement sur votre infrastructure ?</h3>
402+ <p>
403+ Notre équipe technique vous assiste pour vos migrations de code, configurations réseau sur mesure
404+ ou dimensionnements de serveurs VPS dédiés.
405+ </p>
406+ </div>
407+ <div className="support-banner-actions">
408+ <a href="https://dimdams.com/support" className="btn-support-primary">
409+ Contacter le support
410+ <IconArrowRight width={16} height={16} />
411+ </a>
412+ <a href="https://status.dimdams.com" className="btn-support-secondary">
413+ <IconActivity width={16} height={16} />
414+ État des services
415+ </a>
416+ </div>
417+ </section>
141418 </main>
142419 );
143420 }
Ajoutésrc/components/HeroSearch.tsx+55−0
@@ -0,0 +1,55 @@
1+"use client";
2+
3+import { IconSearch } from "./Icons";
4+
5+const POPULAR_SEARCHES = [
6+ { label: "CLI dimdams", query: "cli" },
7+ { label: "Déploiement Git", query: "deploiement git" },
8+ { label: "Tokens & Clés API", query: "authentification" },
9+ { label: "Bases PostgreSQL", query: "bases de donnees" },
10+ { label: "Accès SSH VPS", query: "vps" },
11+ { label: "Dimdam's Pages", query: "pages" },
12+ { label: "API Statut JSON", query: "status api" },
13+];
14+
15+export function HeroSearch() {
16+ const openSearch = (query?: string) => {
17+ window.dispatchEvent(new CustomEvent("dimdams:open-search", { detail: { query } }));
18+ };
19+
20+ return (
21+ <div className="hero-search-container">
22+ <button
23+ type="button"
24+ className="hero-search-bar"
25+ onClick={() => openSearch()}
26+ aria-label="Ouvrir la recherche globale dans la documentation"
27+ >
28+ <div className="hero-search-left">
29+ <IconSearch width={20} height={20} className="hero-search-icon" />
30+ <span className="hero-search-text">Rechercher un guide, un endpoint API, une commande CLI, SSH...</span>
31+ </div>
32+ <div className="hero-search-shortcuts">
33+ <kbd>Ctrl K</kbd>
34+ <kbd>/</kbd>
35+ </div>
36+ </button>
37+
38+ <div className="hero-popular-tags">
39+ <span className="hero-popular-title">Populaire :</span>
40+ <div className="hero-tags-list">
41+ {POPULAR_SEARCHES.map((item) => (
42+ <button
43+ key={item.label}
44+ type="button"
45+ className="hero-tag-pill"
46+ onClick={() => openSearch(item.query)}
47+ >
48+ {item.label}
49+ </button>
50+ ))}
51+ </div>
52+ </div>
53+ </div>
54+ );
55+}
Modifiésrc/components/Icons.tsx+110−0
@@ -83,3 +83,113 @@ export function IconCode(props: SVGProps<SVGSVGElement>) {
8383 </svg>
8484 );
8585 }
86+
87+export function IconSearch(props: SVGProps<SVGSVGElement>) {
88+ return (
89+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
90+ <circle cx="11" cy="11" r="8" />
91+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
92+ </svg>
93+ );
94+}
95+
96+export function IconDatabase(props: SVGProps<SVGSVGElement>) {
97+ return (
98+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
99+ <ellipse cx="12" cy="5" rx="9" ry="3" />
100+ <path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
101+ <path d="M3 12c0 1.66 4 3 9 3s9-1.34 9-3" />
102+ </svg>
103+ );
104+}
105+
106+export function IconCpu(props: SVGProps<SVGSVGElement>) {
107+ return (
108+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
109+ <rect width="16" height="16" x="4" y="4" rx="2" />
110+ <rect width="6" height="6" x="9" y="9" rx="1" />
111+ <path d="M9 1v3" />
112+ <path d="M15 1v3" />
113+ <path d="M9 20v3" />
114+ <path d="M15 20v3" />
115+ <path d="M20 9h3" />
116+ <path d="M20 14h3" />
117+ <path d="M1 9h3" />
118+ <path d="M1 14h3" />
119+ </svg>
120+ );
121+}
122+
123+export function IconLock(props: SVGProps<SVGSVGElement>) {
124+ return (
125+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
126+ <rect width="18" height="11" x="3" y="11" rx="2" ry="2" />
127+ <path d="M7 11V7a5 5 0 0 1 10 0v4" />
128+ </svg>
129+ );
130+}
131+
132+export function IconLayers(props: SVGProps<SVGSVGElement>) {
133+ return (
134+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
135+ <polygon points="12 2 2 7 12 12 22 7 12 2" />
136+ <polyline points="2 17 12 22 22 17" />
137+ <polyline points="2 12 12 17 22 12" />
138+ </svg>
139+ );
140+}
141+
142+export function IconGlobe(props: SVGProps<SVGSVGElement>) {
143+ return (
144+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
145+ <circle cx="12" cy="12" r="10" />
146+ <line x1="2" y1="12" x2="22" y2="12" />
147+ <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
148+ </svg>
149+ );
150+}
151+
152+export function IconCheck(props: SVGProps<SVGSVGElement>) {
153+ return (
154+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
155+ <polyline points="20 6 9 17 4 12" />
156+ </svg>
157+ );
158+}
159+
160+export function IconCopy(props: SVGProps<SVGSVGElement>) {
161+ return (
162+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
163+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
164+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
165+ </svg>
166+ );
167+}
168+
169+export function IconRefresh(props: SVGProps<SVGSVGElement>) {
170+ return (
171+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
172+ <path d="M21.5 2v6h-6" />
173+ <path d="M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67" />
174+ </svg>
175+ );
176+}
177+
178+export function IconZap(props: SVGProps<SVGSVGElement>) {
179+ return (
180+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
181+ <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
182+ </svg>
183+ );
184+}
185+
186+export function IconPackage(props: SVGProps<SVGSVGElement>) {
187+ return (
188+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
189+ <line x1="16.5" y1="9.4" x2="7.5" y2="4.21" />
190+ <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
191+ <polyline points="3.27 6.96 12 12.01 20.73 6.96" />
192+ <line x1="12" y1="22.08" x2="12" y2="12" />
193+ </svg>
194+ );
195+}
Modifiésrc/components/Search.tsx+16−3
@@ -51,8 +51,12 @@ export function Search() {
5151 const [cursor, setCursor] = useState(0);
5252 const input = useRef<HTMLInputElement>(null);
5353
54− const show = useCallback(() => {
54+ const show = useCallback((initialQuery?: string) => {
5555 setOpen(true);
56+ if (typeof initialQuery === "string") {
57+ setQuery(initialQuery);
58+ setCursor(0);
59+ }
5660 if (!index) {
5761 fetch("/search-index.json")
5862 .then((r) => r.json())
@@ -69,8 +73,17 @@ export function Search() {
6973 show();
7074 }
7175 };
76+ const onCustomOpen = (e: Event) => {
77+ const customEvent = e as CustomEvent<{ query?: string }>;
78+ show(customEvent.detail?.query);
79+ };
80+
81+ window.addEventListener("dimdams:open-search", onCustomOpen);
7282 document.addEventListener("keydown", onKey);
73− return () => document.removeEventListener("keydown", onKey);
83+ return () => {
84+ window.removeEventListener("dimdams:open-search", onCustomOpen);
85+ document.removeEventListener("keydown", onKey);
86+ };
7487 }, [show]);
7588
7689 useEffect(() => {
@@ -106,7 +119,7 @@ export function Search() {
106119
107120 return (
108121 <>
109− <button type="button" className="search-button" onClick={show} aria-label="Rechercher dans la documentation">
122+ <button type="button" className="search-button" onClick={() => show()} aria-label="Rechercher dans la documentation">
110123 <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
111124 <circle cx="11" cy="11" r="7" />
112125 <path d="m20 20-3.5-3.5" />
Ajoutésrc/components/TerminalShowcase.tsx+188−0
@@ -0,0 +1,188 @@
1+"use client";
2+
3+import { useState } from "react";
4+import { IconCheck, IconCopy, IconTerminal, IconCode, IconGitBranch, IconServer } from "./Icons";
5+
6+interface TabSnippet {
7+ id: string;
8+ title: string;
9+ icon: typeof IconTerminal;
10+ code: string;
11+ badge: string;
12+ language: string;
13+}
14+
15+const TABS: TabSnippet[] = [
16+ {
17+ id: "cli",
18+ title: "dimdams CLI",
19+ icon: IconTerminal,
20+ badge: "v1.4.0",
21+ language: "bash",
22+ code: `# 1. Connexion sécurisée avec votre jeton d'API
23+dimdams auth login --token dim_live_a8f9c2d14e...
24+
25+# 2. Déploiement continu vers vos serveurs en France
26+dimdams deploy --service app-prod --env production
27+
28+# ✓ Build complété en 3.8s · Conteneur en ligne sur https://mon-app.dimdams.com`,
29+ },
30+ {
31+ id: "api",
32+ title: "REST API",
33+ icon: IconCode,
34+ badge: "v1 JSON",
35+ language: "bash",
36+ code: `curl -X POST https://api.dimdams.com/v1/services \\
37+ -H "Authorization: Bearer dim_live_a8f9c2d14e..." \\
38+ -H "Content-Type: application/json" \\
39+ -d '{
40+ "name": "backend-api",
41+ "template": "nodejs-22",
42+ "replicas": 2,
43+ "port": 3000
44+ }'`,
45+ },
46+ {
47+ id: "git",
48+ title: "Forge Git",
49+ icon: IconGitBranch,
50+ badge: "CI/CD",
51+ language: "bash",
52+ code: `# Lier votre dépôt local à la forge Dimdam's
53+git remote add dimdams git@git.dimdams.com:org/projet.git
54+
55+# Déclencher le pipeline de compilation automatique
56+git push dimdams main
57+
58+# Pipeline CI: test ✓ | build ✓ | deploiement srv-003 ✓`,
59+ },
60+ {
61+ id: "ssh",
62+ title: "SSH Direct",
63+ icon: IconServer,
64+ badge: "Port 22",
65+ language: "bash",
66+ code: `# Accès root sans intermédiaire avec clé ed25519
67+ssh -i ~/.ssh/id_ed25519 root@vps-01.dimdams.com
68+
69+Linux vps-01 6.8.0-dimdams-nvme #1 SMP PREEMPT_DYNAMIC
70+root@vps-01:~# ufw status
71+Status: active (Pare-feu WAF & Anti-DDoS actif)`,
72+ },
73+];
74+
75+export function TerminalShowcase() {
76+ const [activeTab, setActiveTab] = useState<string>("cli");
77+ const [copied, setCopied] = useState<boolean>(false);
78+
79+ const currentSnippet = TABS.find((t) => t.id === activeTab) ?? TABS[0];
80+
81+ const handleCopy = () => {
82+ navigator.clipboard.writeText(currentSnippet.code);
83+ setCopied(true);
84+ setTimeout(() => setCopied(false), 2000);
85+ };
86+
87+ return (
88+ <div className="terminal-showcase">
89+ {/* Terminal Window Header */}
90+ <div className="terminal-header">
91+ <div className="terminal-dots" aria-hidden="true">
92+ <span className="dot dot-red" />
93+ <span className="dot dot-yellow" />
94+ <span className="dot dot-green" />
95+ </div>
96+
97+ {/* Tab switchers */}
98+ <div className="terminal-tabs" role="tablist">
99+ {TABS.map((tab) => {
100+ const Icon = tab.icon;
101+ const isActive = tab.id === activeTab;
102+ return (
103+ <button
104+ key={tab.id}
105+ type="button"
106+ role="tab"
107+ aria-selected={isActive}
108+ className={`terminal-tab ${isActive ? "active" : ""}`}
109+ onClick={() => setActiveTab(tab.id)}
110+ >
111+ <Icon width={14} height={14} />
112+ <span>{tab.title}</span>
113+ <span className="tab-badge">{tab.badge}</span>
114+ </button>
115+ );
116+ })}
117+ </div>
118+
119+ {/* Copy button & status indicator */}
120+ <div className="terminal-actions">
121+ <button
122+ type="button"
123+ className="terminal-copy-btn"
124+ onClick={handleCopy}
125+ aria-label="Copier l'extrait de code"
126+ >
127+ {copied ? (
128+ <>
129+ <IconCheck width={14} height={14} className="text-emerald-400" />
130+ <span className="copied-text">Copié !</span>
131+ </>
132+ ) : (
133+ <>
134+ <IconCopy width={14} height={14} />
135+ <span>Copier</span>
136+ </>
137+ )}
138+ </button>
139+ </div>
140+ </div>
141+
142+ {/* Terminal Code Body */}
143+ <div className="terminal-body">
144+ <pre className="terminal-pre">
145+ <code>
146+ {currentSnippet.code.split("\n").map((line, idx) => {
147+ const isComment = line.trim().startsWith("#");
148+ const isOutput = line.trim().startsWith("✓") || line.trim().startsWith("Linux") || line.trim().startsWith("root@");
149+ const isCommand = !isComment && !isOutput && (line.trim().startsWith("dimdams") || line.trim().startsWith("curl") || line.trim().startsWith("git") || line.trim().startsWith("ssh"));
150+
151+ return (
152+ <div key={idx} className="terminal-line">
153+ <span className="line-num">{idx + 1}</span>
154+ <span
155+ className={
156+ isComment
157+ ? "token-comment"
158+ : isOutput
159+ ? "token-output"
160+ : isCommand
161+ ? "token-command"
162+ : "token-plain"
163+ }
164+ >
165+ {line}
166+ </span>
167+ </div>
168+ );
169+ })}
170+ </code>
171+ </pre>
172+ </div>
173+
174+ {/* Terminal Status Footer */}
175+ <div className="terminal-footer">
176+ <div className="terminal-status-left">
177+ <span className="pulse-dot" />
178+ <span>Nœuds d&apos;infrastructure & sondes en ligne</span>
179+ </div>
180+ <div className="terminal-status-right">
181+ <span>Latence réseau moyenne : <strong>1.4 ms</strong></span>
182+ <span>·</span>
183+ <span>Hébergement 100% France</span>
184+ </div>
185+ </div>
186+ </div>
187+ );
188+}