@@ -370,16 +370,43 @@ const app = {
370370 let categoriesHtml = '' ;
371371 Object . keys ( commandsByCategory ) . sort ( ) . forEach ( category => {
372372 const commands = commandsByCategory [ category ] . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
373+ const categoryId = category . replace ( / \s + / g, '_' ) . toLowerCase ( ) ;
374+ const enabledCommandsInCategory = commands . filter ( cmd => this . isCommandEnabled ( cmd . name ) ) . length ;
375+ const totalCommandsInCategory = commands . length ;
373376
374377 categoriesHtml += `
375- <div class="mb-6">
376- <h3 class="text-lg font-bold text-white mb-3 flex items-center">
377- <svg class="w-5 h-5 mr-2 text-blue-400" fill="currentColor" viewBox="0 0 20 20">
378- <path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path>
379- </svg>
380- ${ category }
381- </h3>
382- <div class="grid gap-2">
378+ <div class="mb-6 category-section" data-category="${ category } ">
379+ <div class="category-header bg-slate-700/40 border border-slate-600/40 rounded-xl p-4 cursor-pointer hover:bg-slate-600/40 transition-colors" data-target="category-${ categoryId } ">
380+ <div class="flex items-center justify-between">
381+ <div class="flex items-center">
382+ <svg class="category-chevron w-5 h-5 mr-3 text-slate-400 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
383+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
384+ </svg>
385+ <svg class="w-5 h-5 mr-2 text-blue-400" fill="currentColor" viewBox="0 0 20 20">
386+ <path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path>
387+ </svg>
388+ <h3 class="text-lg font-bold text-white">${ category } </h3>
389+ <span class="ml-3 px-2 py-1 bg-slate-600/40 text-slate-300 rounded-lg text-xs font-medium category-count">
390+ ${ enabledCommandsInCategory } /${ totalCommandsInCategory }
391+ </span>
392+ </div>
393+ <div class="flex items-center space-x-2">
394+ <button class="category-disable-btn px-3 py-1.5 bg-red-600/20 hover:bg-red-600/30 text-red-400 rounded-lg transition-colors text-xs font-medium border border-red-500/30 hover:border-red-500/50" data-category="${ category } " title="Désactiver toute la catégorie">
395+ <svg class="w-3 h-3 mr-1 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24">
396+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L18.364 5.636M5.636 18.364l12.728-12.728"></path>
397+ </svg>
398+ Désactiver tout
399+ </button>
400+ <button class="category-enable-btn px-3 py-1.5 bg-green-600/20 hover:bg-green-600/30 text-green-400 rounded-lg transition-colors text-xs font-medium border border-green-500/30 hover:border-green-500/50" data-category="${ category } " title="Activer toute la catégorie">
401+ <svg class="w-3 h-3 mr-1 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24">
402+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
403+ </svg>
404+ Activer tout
405+ </button>
406+ </div>
407+ </div>
408+ </div>
409+ <div id="category-${ categoryId } " class="category-content mt-3 grid gap-2">
383410 ${ commands . map ( cmd => {
384411 const isEnabled = this . isCommandEnabled ( cmd . name ) ;
385412 const typeColor = cmd . type === 'native' ? 'bg-blue-600/20 text-blue-300 border-blue-500/30' : 'bg-purple-600/20 text-purple-300 border-purple-500/30' ;
@@ -488,6 +515,19 @@ const app = {
488515 enabledCountSpan . textContent = allCommands . size - this . disabledCommands . size ;
489516 } ;
490517
518+ // Fonction pour mettre à jour le compteur d'une catégorie
519+ const updateCategoryCount = ( categoryElement ) => {
520+ const category = categoryElement . dataset . category ;
521+ const commandItems = categoryElement . querySelectorAll ( '.command-item' ) ;
522+ const enabledItems = Array . from ( commandItems ) . filter ( item => {
523+ const toggle = item . querySelector ( '.command-toggle' ) ;
524+ return toggle . classList . contains ( 'enabled' ) ;
525+ } ) ;
526+
527+ const countElement = categoryElement . querySelector ( '.category-count' ) ;
528+ countElement . textContent = `${ enabledItems . length } /${ commandItems . length } ` ;
529+ } ;
530+
491531 const closeModal = ( ) => {
492532 modal . remove ( ) ;
493533 } ;
@@ -528,6 +568,9 @@ const app = {
528568 textSpan . className = 'text-xs text-red-400 font-medium' ;
529569 }
530570
571+ // Mettre à jour le compteur de la catégorie
572+ const categoryElement = toggle . closest ( '.category-section' ) ;
573+ updateCategoryCount ( categoryElement ) ;
531574 updateEnabledCount ( ) ;
532575
533576 this . showNotification ( {
@@ -571,6 +614,11 @@ const app = {
571614 textSpan . className = 'text-xs text-green-400 font-medium' ;
572615 } ) ;
573616
617+ // Mettre à jour tous les compteurs de catégories
618+ modal . querySelectorAll ( '.category-section' ) . forEach ( categoryElement => {
619+ updateCategoryCount ( categoryElement ) ;
620+ } ) ;
621+
574622 updateEnabledCount ( ) ;
575623
576624 this . showNotification ( {
@@ -582,6 +630,120 @@ const app = {
582630 }
583631 } ) ;
584632
633+ // Gestionnaires pour l'ouverture/fermeture des catégories
634+ modal . querySelectorAll ( '.category-header' ) . forEach ( header => {
635+ header . addEventListener ( 'click' , ( e ) => {
636+ // Ne pas fermer si on clique sur les boutons d'action
637+ if ( e . target . closest ( '.category-disable-btn' ) || e . target . closest ( '.category-enable-btn' ) ) {
638+ return ;
639+ }
640+
641+ const targetId = header . dataset . target ;
642+ const content = document . getElementById ( targetId ) ;
643+ const chevron = header . querySelector ( '.category-chevron' ) ;
644+
645+ if ( content . style . display === 'none' || content . style . display === '' ) {
646+ // Ouvrir
647+ content . style . display = 'grid' ;
648+ chevron . style . transform = 'rotate(90deg)' ;
649+ } else {
650+ // Fermer
651+ content . style . display = 'none' ;
652+ chevron . style . transform = 'rotate(0deg)' ;
653+ }
654+ } ) ;
655+ } ) ;
656+
657+ // Gestionnaire pour désactiver toute une catégorie
658+ modal . querySelectorAll ( '.category-disable-btn' ) . forEach ( btn => {
659+ btn . addEventListener ( 'click' , ( e ) => {
660+ e . stopPropagation ( ) ;
661+ const category = btn . dataset . category ;
662+ const categoryElement = btn . closest ( '.category-section' ) ;
663+
664+ if ( confirm ( `Êtes-vous sûr de vouloir désactiver toutes les commandes de la catégorie "${ category } " ?` ) ) {
665+ const commandToggles = categoryElement . querySelectorAll ( '.command-toggle' ) ;
666+
667+ commandToggles . forEach ( toggle => {
668+ const commandName = toggle . dataset . command ;
669+ this . toggleCommandEnabled ( commandName , false ) ;
670+ toggle . classList . remove ( 'enabled' ) ;
671+
672+ // Mettre à jour l'affichage
673+ const commandItem = toggle . closest ( '.command-item' ) ;
674+ const statusContainer = commandItem . querySelector ( '.flex.items-center.space-x-3.flex-shrink-0 .flex.items-center.space-x-2' ) ;
675+ const iconSpan = statusContainer . children [ 0 ] ;
676+ const textSpan = statusContainer . children [ 1 ] ;
677+
678+ iconSpan . textContent = '✗' ;
679+ iconSpan . className = 'text-lg text-red-400' ;
680+ textSpan . textContent = 'DÉSACTIVÉE' ;
681+ textSpan . className = 'text-xs text-red-400 font-medium' ;
682+ } ) ;
683+
684+ updateCategoryCount ( categoryElement ) ;
685+ updateEnabledCount ( ) ;
686+
687+ this . showNotification ( {
688+ type : 'info' ,
689+ title : 'Catégorie désactivée' ,
690+ message : `Toutes les commandes de "${ category } " ont été désactivées.` ,
691+ duration : 2000
692+ } ) ;
693+ }
694+ } ) ;
695+ } ) ;
696+
697+ // Gestionnaire pour activer toute une catégorie
698+ modal . querySelectorAll ( '.category-enable-btn' ) . forEach ( btn => {
699+ btn . addEventListener ( 'click' , ( e ) => {
700+ e . stopPropagation ( ) ;
701+ const category = btn . dataset . category ;
702+ const categoryElement = btn . closest ( '.category-section' ) ;
703+ const commandToggles = categoryElement . querySelectorAll ( '.command-toggle' ) ;
704+
705+ commandToggles . forEach ( toggle => {
706+ const commandName = toggle . dataset . command ;
707+ this . toggleCommandEnabled ( commandName , true ) ;
708+ toggle . classList . add ( 'enabled' ) ;
709+
710+ // Mettre à jour l'affichage
711+ const commandItem = toggle . closest ( '.command-item' ) ;
712+ const statusContainer = commandItem . querySelector ( '.flex.items-center.space-x-3.flex-shrink-0 .flex.items-center.space-x-2' ) ;
713+ const iconSpan = statusContainer . children [ 0 ] ;
714+ const textSpan = statusContainer . children [ 1 ] ;
715+
716+ iconSpan . textContent = '✓' ;
717+ iconSpan . className = 'text-lg text-green-400' ;
718+ textSpan . textContent = 'ACTIVÉE' ;
719+ textSpan . className = 'text-xs text-green-400 font-medium' ;
720+ } ) ;
721+
722+ updateCategoryCount ( categoryElement ) ;
723+ updateEnabledCount ( ) ;
724+
725+ this . showNotification ( {
726+ type : 'success' ,
727+ title : 'Catégorie activée' ,
728+ message : `Toutes les commandes de "${ category } " ont été activées.` ,
729+ duration : 2000
730+ } ) ;
731+ } ) ;
732+ } ) ;
733+
734+ // Mettre à jour les compteurs de catégories et configurer l'état d'ouverture/fermeture
735+ modal . querySelectorAll ( '.category-section' ) . forEach ( ( categoryElement , index ) => {
736+ updateCategoryCount ( categoryElement ) ;
737+
738+ const categoryId = categoryElement . querySelector ( '.category-header' ) . dataset . target ;
739+ const content = document . getElementById ( categoryId ) ;
740+ const chevron = categoryElement . querySelector ( '.category-chevron' ) ;
741+
742+ // Fermer toutes les catégories par défaut
743+ content . style . display = 'none' ;
744+ chevron . style . transform = 'rotate(0deg)' ;
745+ } ) ;
746+
585747 closeBtn . addEventListener ( 'click' , closeModal ) ;
586748 closeBtnBottom . addEventListener ( 'click' , closeModal ) ;
587749
0 commit comments