fix(marketing): restaurer visibilité 12 fonctions dans 'Comment ça marche'

L'abstraction en 4 catégories (commit 8a7650f) cachait les 13 modes
derrière des regroupements ; l'utilisateur ne VOYAIT plus les 6 boutons
features originaux et percevait que des fonctions avaient disparu.

Refonte v2 :
- Bottom tab bar : 6 boutons FEATURES originaux 1-6 (Trans/Diari/Lang/Exp/Users/Part) — visibles, cliquables
- Right panel : grid 3×4 = 12 boutons FEATURES 1-12 (IA mode 0 reste accessible via Brain card)
- Mobile pills : 12 features scrollables horizontalement
- Auto-cycle : 1→12 skip 0, 1100ms each (~13s cycle complet)
- Manual click : isManual 4500ms reset puis reprend auto
- SUPPRESSION : CATEGORIES array + activeCategory state + handleCategorySelect + sub-mode dots indicator
- AJOUT : featureGridLabel() pour labels compacts (Recording/Recherche IA/Résumés/Intégrations/Audit trail/Conformité)

Préservé : phone shell statique, palette brand stricte b1/b2/b3, IA Mistral
card inchangée, 13 templates de modes (0-12) intacts, eyebrow brand-navy noir,
WCAG aria-labels + aria-pressed, prefers-reduced-motion guard.

Test adapté : assert featureGridLabel + 12 fonctions + labels grid.
This commit is contained in:
Allison
2026-04-29 13:17:09 -04:00
parent 8a7650f9fa
commit a14bcb9a1a
2 changed files with 78 additions and 140 deletions

View File

@@ -480,8 +480,8 @@
{# Stats row #} {# Stats row #}
<div class="flex flex-wrap items-center justify-center gap-x-8 gap-y-3 text-brand-navy"> <div class="flex flex-wrap items-center justify-center gap-x-8 gap-y-3 text-brand-navy">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="text-2xl font-black grad-text">4</span> <span class="text-2xl font-black grad-text">12</span>
<span class="text-xs font-medium text-brand-navy/60 uppercase tracking-wider">catégories · 6 modules</span> <span class="text-xs font-medium text-brand-navy/60 uppercase tracking-wider">fonctions · modules</span>
</div> </div>
<div class="w-px h-6 bg-brand-navy/15 hidden sm:block" aria-hidden="true"></div> <div class="w-px h-6 bg-brand-navy/15 hidden sm:block" aria-hidden="true"></div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -1200,34 +1200,27 @@
</div> </div>
{# BOTTOM : 4 catégories tabs (Capture / IA / Distribution / Gouvernance) + sub-mode dots + Auto pill — hauteur fixe 90px #} {# BOTTOM : 6 boutons feature originaux (Trans / Diari / Lang / Exp / Users / Part) + Auto pill — hauteur fixe 90px #}
<div class="relative flex flex-col items-center justify-center gap-1 z-10 flex-shrink-0" <div class="relative flex flex-col items-center justify-center gap-1.5 z-10 flex-shrink-0"
style="height: 90px; border-top: 1px solid rgba(255,255,255,0.06); background: linear-gradient(180deg, transparent, rgba(0,0,0,0.32));"> style="height: 90px; border-top: 1px solid rgba(255,255,255,0.06); background: linear-gradient(180deg, transparent, rgba(0,0,0,0.32));">
{# Sub-mode dots indicator (shows position within active category) #}
<div class="flex items-center gap-1" style="height:6px;" aria-hidden="true">
<template x-for="(sm, di) in CATEGORIES[activeCategory].submodes" :key="di">
<span class="block rounded-full"
:style="`width:${sm === selectedFeature ? '10px' : '4px'};height:4px;background:${sm === selectedFeature ? CATEGORIES[activeCategory].color : 'rgba(255,255,255,0.20)'};transition:width 0.2s, background 0.2s;`"></span>
</template>
</div>
{# 4 catégories tabs #} {# 6 boutons features originaux (FEATURES indexes 1-6) — visible bottom tab bar #}
<div class="flex items-end gap-1"> <div class="flex items-end gap-1.5 justify-center">
<template x-for="(cat, ci) in CATEGORIES" :key="ci"> <template x-for="i in [1,2,3,4,5,6]" :key="i">
<button type="button" @click="handleCategorySelect(ci)" <button type="button" @click="handleManualSelect(i)"
class="dictia-feat-btn dictia-cat-btn outline-none cursor-pointer focus-visible:ring-2 focus-visible:ring-white/40 flex flex-col items-center justify-end relative" class="dictia-feat-btn outline-none cursor-pointer focus-visible:ring-2 focus-visible:ring-white/40 flex flex-col items-center justify-end relative"
style="width:54px;height:42px;border:none;padding:4px 0 6px;background:transparent;" style="width:34px;height:42px;border:none;padding:4px 0 6px;background:transparent;"
:aria-pressed="activeCategory === ci ? 'true' : 'false'" :aria-pressed="selectedFeature === i ? 'true' : 'false'"
:aria-label="`Catégorie : ${cat.title}`"> :aria-label="`Fonction : ${FEATURES[i].title}`">
<span :style="`color: ${activeCategory === ci ? cat.color : 'rgba(255,255,255,0.30)'}; transition: color 0.2s, transform 0.15s, filter 0.2s; filter: ${activeCategory === ci ? 'drop-shadow(0 0 6px ' + cat.color + 'CC)' : 'none'}; transform: scale(${activeCategory === ci ? 1.15 : 1}); display: inline-block;`"> <span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.40)'}; transition: color 0.2s, transform 0.15s, filter 0.2s; filter: ${selectedFeature === i ? 'drop-shadow(0 0 6px ' + FEATURES[i].color + 'CC)' : 'none'}; transform: scale(${selectedFeature === i ? 1.15 : 1}); display: inline-block;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px;" aria-hidden="true" x-html="cat.iconPath"></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;" aria-hidden="true" x-html="featureIconPath(i)"></svg>
</span> </span>
<span class="text-[9px] font-mono font-bold mt-0.5 leading-none uppercase tracking-wider" <span class="text-[9px] font-mono font-bold mt-0.5 leading-none uppercase tracking-wider"
:style="`color: ${activeCategory === ci ? cat.color : 'rgba(255,255,255,0.40)'};`" :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.55)'};`"
x-text="cat.short"></span> x-text="featureShortLabel(i)"></span>
{# Tab indicator bottom border 2px #} {# Tab indicator bottom border 2px #}
<span x-show="activeCategory === ci" class="absolute" aria-hidden="true" <span x-show="selectedFeature === i" class="absolute" aria-hidden="true"
:style="`bottom: 0; left: 6px; right: 6px; height: 2px; background: ${cat.color}; border-radius: 1px; box-shadow: 0 0 8px ${cat.color};`"></span> :style="`bottom: 0; left: 4px; right: 4px; height: 2px; background: ${FEATURES[i].color}; border-radius: 1px; box-shadow: 0 0 8px ${FEATURES[i].color};`"></span>
</button> </button>
</template> </template>
</div> </div>
@@ -1286,35 +1279,41 @@
</div> </div>
</div> </div>
{# Mobile : pills catégories horizontales scrollables #} {# Mobile : pills features horizontales scrollables (12 fonctions, indexes 1-12) #}
<div class="lg:hidden w-full overflow-x-auto dictia-hide-scrollbar" style="scrollbar-width:none;"> <div class="lg:hidden w-full overflow-x-auto dictia-hide-scrollbar" style="scrollbar-width:none;">
<div class="flex gap-2 px-1 pb-1" style="width:max-content;"> <div class="flex gap-2 px-1 pb-1" style="width:max-content;">
<template x-for="(cat, ci) in CATEGORIES" :key="ci"> <template x-for="i in [1,2,3,4,5,6,7,8,9,10,11,12]" :key="i">
<button type="button" @click="handleCategorySelect(ci)" <button type="button" @click="handleManualSelect(i)"
class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-full shrink-0 transition-all focus-visible:ring-2 focus-visible:ring-brand-b1" class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-full shrink-0 transition-all focus-visible:ring-2 focus-visible:ring-brand-b1"
:style="`border: 1px solid ${activeCategory === ci ? cat.color + '70' : 'rgba(0,0,0,0.10)'}; background-color: ${activeCategory === ci ? cat.color + '18' : 'rgba(0,0,0,0.04)'}; outline: none;`"> :style="`border: 1px solid ${selectedFeature === i ? FEATURES[i].color + '70' : 'rgba(0,0,0,0.10)'}; background-color: ${selectedFeature === i ? FEATURES[i].color + '18' : 'rgba(0,0,0,0.04)'}; outline: none;`"
<span :style="`color: ${activeCategory === ci ? cat.color : 'rgba(0,0,0,0.40)'}; transition: color 0.2s;`"> :aria-pressed="selectedFeature === i ? 'true' : 'false'"
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:12px;height:12px;" aria-hidden="true" x-html="cat.iconPath"></svg> :aria-label="`Fonction : ${FEATURES[i].title}`">
<span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(0,0,0,0.40)'}; transition: color 0.2s;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:12px;height:12px;" aria-hidden="true" x-html="featureIconPath(i)"></svg>
</span> </span>
<span class="text-[11px] font-bold whitespace-nowrap" <span class="text-[11px] font-bold whitespace-nowrap"
:style="`color: ${activeCategory === ci ? cat.color : 'rgba(0,0,0,0.50)'};`" :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(0,0,0,0.50)'};`"
x-text="cat.title"></span> x-text="FEATURES[i].title"></span>
</button> </button>
</template> </template>
</div> </div>
</div> </div>
</div> </div>
{# ─────────── ZONE RIGHT : IA Mistral premium card + grid 6 features ─────────── #} {# ─────────── ZONE RIGHT : IA Mistral premium card + grid 12 features ─────────── #}
<div class="flex flex-col gap-3 w-full lg:w-[320px] flex-shrink-0 relative z-10"> <div class="flex flex-col gap-3 w-full lg:w-[320px] flex-shrink-0 relative z-10">
{# Eyebrow + title — alignés sur le système typo #} {# Eyebrow + title — alignés sur le système typo #}
<div class="mb-1 flex items-center gap-2"> <div class="mb-1 flex items-center justify-between gap-2">
<span class="block w-1 h-6 rounded-full" style="background:linear-gradient(180deg,#06b6d4,#c026d3);" aria-hidden="true"></span> <div class="flex items-center gap-2">
<div> <span class="block w-1 h-6 rounded-full" style="background:linear-gradient(180deg,#06b6d4,#c026d3);" aria-hidden="true"></span>
<p class="text-xs font-mono font-bold uppercase tracking-widest text-brand-b3">4 catégories · 12 sous-modes</p> <div>
<p class="font-bold text-lg leading-snug text-brand-navy">Le moteur IA local</p> <p class="text-xs font-mono font-bold uppercase tracking-widest text-brand-b3">Fonctions clés</p>
<p class="font-bold text-lg leading-snug text-brand-navy">Le moteur IA local</p>
</div>
</div> </div>
<span class="text-[10px] font-mono font-bold px-2 py-0.5 rounded-full text-brand-b3 whitespace-nowrap"
style="background-color:rgba(192,38,211,0.10);border:1px solid rgba(192,38,211,0.25);">12 fonctions</span>
</div> </div>
{# IA Mistral 7B premium card — couleurs brand-b3 (fuchsia officiel) #} {# IA Mistral 7B premium card — couleurs brand-b3 (fuchsia officiel) #}
@@ -1410,32 +1409,20 @@
</div> </div>
</div> </div>
{# Category grid 2×2 — 4 catégories avec sous-modes affichés dessous (architecture lisible) #} {# Feature grid 3×4 — 12 fonctions (FEATURES indexes 1-12, IA mode 0 accessible via Brain card ci-dessus) #}
<div class="grid grid-cols-2 gap-2"> <div class="grid grid-cols-3 gap-2">
<template x-for="(cat, ci) in CATEGORIES" :key="ci"> <template x-for="i in [1,2,3,4,5,6,7,8,9,10,11,12]" :key="i">
<button type="button" @click="handleCategorySelect(ci)" <button type="button" @click="handleManualSelect(i)"
class="flex flex-col items-start gap-2 rounded-xl py-3 px-3 outline-none transition-all focus-visible:ring-2 focus-visible:ring-white/40 text-left" class="flex flex-col items-center gap-1.5 rounded-xl py-2.5 px-2 outline-none transition-all focus-visible:ring-2 focus-visible:ring-white/40 text-center"
:style="`border: 1px solid ${activeCategory === ci ? cat.color + '70' : 'rgba(255,255,255,0.10)'}; background-color: ${activeCategory === ci ? 'rgba(8,12,24,0.95)' : 'rgba(8,12,24,0.85)'}; box-shadow: ${activeCategory === ci ? '0 0 16px ' + cat.color + '40, inset 0 0 16px ' + cat.color + '20' : 'none'}; cursor: pointer;`" :style="`border: 1px solid ${selectedFeature === i ? FEATURES[i].color + '70' : 'rgba(255,255,255,0.10)'}; background-color: ${selectedFeature === i ? 'rgba(8,12,24,0.95)' : 'rgba(8,12,24,0.85)'}; box-shadow: ${selectedFeature === i ? '0 0 16px ' + FEATURES[i].color + '40, inset 0 0 16px ' + FEATURES[i].color + '20' : 'none'}; cursor: pointer; min-height:64px;`"
:aria-pressed="activeCategory === ci ? 'true' : 'false'" :aria-pressed="selectedFeature === i ? 'true' : 'false'"
:aria-label="`Catégorie : ${cat.title}`"> :aria-label="`Fonction : ${FEATURES[i].title}`">
<div class="flex items-center gap-2 w-full"> <span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.55)'}; filter: ${selectedFeature === i ? 'drop-shadow(0 0 6px ' + FEATURES[i].color + 'BB)' : 'none'}; transition: all 0.2s; transform: scale(${selectedFeature === i ? 1.15 : 1}); display:inline-block;`">
<span :style="`color: ${activeCategory === ci ? cat.color : 'rgba(255,255,255,0.55)'}; filter: ${activeCategory === ci ? 'drop-shadow(0 0 6px ' + cat.color + 'BB)' : 'none'}; transition: all 0.2s; display:inline-block;`"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px;" aria-hidden="true" x-html="featureIconPath(i)"></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px;" aria-hidden="true" x-html="cat.iconPath"></svg> </span>
</span> <span class="text-[10px] font-bold leading-tight w-full truncate"
<span class="text-[11px] font-bold leading-tight flex-1" :style="`color: ${selectedFeature === i ? 'rgba(255,255,255,0.98)' : 'rgba(255,255,255,0.85)'};`"
:style="`color: ${activeCategory === ci ? 'rgba(255,255,255,0.98)' : 'rgba(255,255,255,0.85)'};`" x-text="featureGridLabel(i)"></span>
x-text="cat.title"></span>
</div>
<p class="text-[10px] font-mono leading-snug w-full"
:style="`color: ${activeCategory === ci ? cat.color + 'EE' : 'rgba(255,255,255,0.55)'};`"
x-text="cat.subtitle"></p>
{# Mini sous-modes dots dans la card #}
<div class="flex items-center gap-0.5 mt-auto" aria-hidden="true">
<template x-for="(sm, si) in cat.submodes" :key="si">
<span class="block rounded-full"
:style="`width:${activeCategory === ci && sm === selectedFeature ? '8px' : '3px'};height:3px;background:${activeCategory === ci ? (sm === selectedFeature ? cat.color : cat.color + '55') : 'rgba(255,255,255,0.15)'};transition:all 0.2s;`"></span>
</template>
</div>
</button> </button>
</template> </template>
</div> </div>
@@ -1445,11 +1432,11 @@
</div> </div>
{# Alpine logic — dictiaDashboard + 4 catégories × 12 sous-modes (refonte stratégique 2026-04-29) #} {# Alpine logic — dictiaDashboard : 12 fonctions visibles (1-12) + IA accessible via Brain card (refonte 2026-04-29) #}
<script> <script>
function dictiaDashboard() { function dictiaDashboard() {
return { return {
/* FEATURES indexes (0-12) — même structure que v1 (0=IA, 1-6=existants), nouveaux 7-12 ajoutés */ /* FEATURES indexes (0-12) — IA mode 0 accessible via Brain card; 1-6 = originaux, 7-12 = nouveaux */
FEATURES: [ FEATURES: [
{ idx: 0, title: 'IA intégrée', subtitle: "Résumé, actions, Q&R", color: '#c026d3', badge: 'Mistral 7B' }, /* brand-b3 */ { idx: 0, title: 'IA intégrée', subtitle: "Résumé, actions, Q&R", color: '#c026d3', badge: 'Mistral 7B' }, /* brand-b3 */
{ idx: 1, title: 'Transcription', subtitle: 'Parole → texte en temps réel', color: '#06b6d4', badge: 'Whisper AI' }, /* brand-b2 */ { idx: 1, title: 'Transcription', subtitle: 'Parole → texte en temps réel', color: '#06b6d4', badge: 'Whisper AI' }, /* brand-b2 */
@@ -1466,43 +1453,7 @@
{ idx: 11, title: 'Audit trail', subtitle: 'Traçabilité Loi 25 immutable', color: '#2563eb', badge: 'Loi 25' }, /* brand-b1 */ { idx: 11, title: 'Audit trail', subtitle: 'Traçabilité Loi 25 immutable', color: '#2563eb', badge: 'Loi 25' }, /* brand-b1 */
{ idx: 12, title: 'Conformité', subtitle: '9 ordres pros · EFVP CAI', color: '#c026d3', badge: 'MCN' } /* brand-b3 */ { idx: 12, title: 'Conformité', subtitle: '9 ordres pros · EFVP CAI', color: '#c026d3', badge: 'MCN' } /* brand-b3 */
], ],
/* CATEGORIES : 4 regroupements logiques. Chaque catégorie a ses sous-modes (ids des FEATURES). */
CATEGORIES: [
{
title: 'Capture',
short: 'Capture',
subtitle: 'Audio in : upload, recording, recherche',
color: '#06b6d4', /* brand-b2 cyan */
submodes: [1, 7, 8], /* Transcription (upload), Recording live, Recherche sémantique */
iconPath: '<rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/>'
},
{
title: 'Transformation IA',
short: 'IA',
subtitle: 'Diarisation, langues, résumés, Q&R',
color: '#2563eb', /* brand-b1 blue */
submodes: [2, 3, 9, 0], /* Diarisation, Langues, Résumé+actions, Chat IA */
iconPath: '<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/>'
},
{
title: 'Distribution',
short: 'Distrib',
subtitle: 'Exports, intégrations, partage',
color: '#c026d3', /* brand-b3 fuchsia */
submodes: [4, 10, 6, 5], /* Exports, Intégrations, Partage, Users */
iconPath: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>'
},
{
title: 'Gouvernance',
short: 'Gouv',
subtitle: 'Audit, Loi 25, AGPL, ordres pros',
color: '#2563eb', /* brand-b1 blue (sobre, institutionnel) */
submodes: [11, 12], /* Audit trail, Conformité Loi 25 */
iconPath: '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/>'
}
],
selectedFeature: 1, selectedFeature: 1,
activeCategory: 0,
isManual: false, isManual: false,
autoCycleTimer: null, autoCycleTimer: null,
manualResetTimer: null, manualResetTimer: null,
@@ -1512,42 +1463,19 @@
if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
this.startAutoCycle(); this.startAutoCycle();
}, },
/* Auto-cycle logic : avance dans les sous-modes de la catégorie active toutes les 1100ms. /* Auto-cycle logic : avance 1→12 (skip 0=IA mode, accessible via Brain card), 1100ms each.
Quand on atteint le dernier sous-mode → switch catégorie suivante (boucle 0→1→2→3→0). */ Cycle complet : 12 features × 1100ms ≈ 13.2s puis recommence à 1. */
startAutoCycle() { startAutoCycle() {
if (this.autoCycleTimer) clearInterval(this.autoCycleTimer); if (this.autoCycleTimer) clearInterval(this.autoCycleTimer);
this.autoCycleTimer = setInterval(() => { this.autoCycleTimer = setInterval(() => {
const cat = this.CATEGORIES[this.activeCategory]; /* Avance 1→2→...→12, puis retour à 1 (skip 0=IA) */
const currentIdx = cat.submodes.indexOf(this.selectedFeature); this.selectedFeature = this.selectedFeature >= 12 ? 1 : this.selectedFeature + 1;
if (currentIdx < cat.submodes.length - 1) { if (this.selectedFeature === 0) this.selectedFeature = 1;
/* Avance dans la catégorie courante */
this.selectedFeature = cat.submodes[currentIdx + 1];
} else {
/* Fin de catégorie → passe à la suivante */
this.activeCategory = (this.activeCategory + 1) % this.CATEGORIES.length;
this.selectedFeature = this.CATEGORIES[this.activeCategory].submodes[0];
}
}, 1100); }, 1100);
}, },
/* Click manuel sur un sous-mode (compatibilité 6 boutons originaux) */ /* Click manuel sur un bouton feature : sélectionne ce mode + freeze auto 4500ms */
handleManualSelect(i) { handleManualSelect(i) {
this.selectedFeature = i; this.selectedFeature = i;
/* Trouve la catégorie qui contient ce sous-mode */
for (let ci = 0; ci < this.CATEGORIES.length; ci++) {
if (this.CATEGORIES[ci].submodes.includes(i)) { this.activeCategory = ci; break; }
}
this.isManual = true;
if (this.autoCycleTimer) { clearInterval(this.autoCycleTimer); this.autoCycleTimer = null; }
if (this.manualResetTimer) clearTimeout(this.manualResetTimer);
this.manualResetTimer = setTimeout(() => {
this.isManual = false;
this.startAutoCycle();
}, 4500);
},
/* Click manuel sur une catégorie : sélectionne son premier sous-mode */
handleCategorySelect(ci) {
this.activeCategory = ci;
this.selectedFeature = this.CATEGORIES[ci].submodes[0];
this.isManual = true; this.isManual = true;
if (this.autoCycleTimer) { clearInterval(this.autoCycleTimer); this.autoCycleTimer = null; } if (this.autoCycleTimer) { clearInterval(this.autoCycleTimer); this.autoCycleTimer = null; }
if (this.manualResetTimer) clearTimeout(this.manualResetTimer); if (this.manualResetTimer) clearTimeout(this.manualResetTimer);
@@ -1578,6 +1506,15 @@
const labels = { 1: 'Trans', 2: 'Diari', 3: 'Lang', 4: 'Exp', 5: 'Users', 6: 'Part', const labels = { 1: 'Trans', 2: 'Diari', 3: 'Lang', 4: 'Exp', 5: 'Users', 6: 'Part',
7: 'Rec', 8: 'Search', 9: 'Résu', 10: 'Hub', 11: 'Audit', 12: 'Conf' }; 7: 'Rec', 8: 'Search', 9: 'Résu', 10: 'Hub', 11: 'Audit', 12: 'Conf' };
return labels[i] || ''; return labels[i] || '';
},
/* Labels compacts pour la grid 3×4 du right panel (raccourcis pour ne pas tronquer) */
featureGridLabel(i) {
const labels = {
1: 'Transcription', 2: 'Diarisation', 3: '99+ langues', 4: 'Exports',
5: 'Utilisateurs', 6: 'Partage', 7: 'Recording', 8: 'Recherche IA',
9: 'Résumés', 10: 'Intégrations', 11: 'Audit trail', 12: 'Conformité'
};
return labels[i] || '';
} }
}; };
} }

View File

@@ -192,12 +192,13 @@ def test_fonctionnalites_how_it_works_reactor_section():
assert 'handleManualSelect' in body, "Missing manual select handler" assert 'handleManualSelect' in body, "Missing manual select handler"
assert '1100' in body, "Missing 1100ms sub-mode cycle interval (refonte 2026-04-29)" assert '1100' in body, "Missing 1100ms sub-mode cycle interval (refonte 2026-04-29)"
assert '4500' in body, "Missing 4500ms manual reset timer" assert '4500' in body, "Missing 4500ms manual reset timer"
# Refonte 2026-04-29 : 4 catégories × 12 sous-modes # Refonte 2026-04-29 (v2) : 12 fonctions visibles directement (1-12), IA mode 0 via Brain card.
assert 'CATEGORIES' in body, "Missing CATEGORIES array (refonte 4 catégories)" # Bottom tab bar = 6 boutons originaux (Trans/Diari/Lang/Exp/Users/Part) ; right panel grid = 12 features.
assert 'activeCategory' in body, "Missing activeCategory state" assert 'featureGridLabel' in body, "Missing featureGridLabel (right grid 12 buttons)"
assert 'handleCategorySelect' in body, "Missing category click handler" assert '12 fonctions' in body, "Missing '12 fonctions' badge in right panel header"
for cat_title in ['Capture', 'Transformation IA', 'Distribution', 'Gouvernance']: # Labels compacts grid right panel
assert cat_title in body, f"Missing category : {cat_title}" for grid_label in ['Recording', 'Recherche IA', 'Résumés', 'Intégrations', 'Audit trail', 'Conformité']:
assert grid_label in body, f"Missing right grid label : {grid_label}"
# Nouveaux modes 7-12 # Nouveaux modes 7-12
assert 'recModeData' in body, "Missing Mode 7 (Recording live)" assert 'recModeData' in body, "Missing Mode 7 (Recording live)"
assert 'searchModeData' in body, "Missing Mode 8 (Recherche sémantique)" assert 'searchModeData' in body, "Missing Mode 8 (Recherche sémantique)"
@@ -273,9 +274,9 @@ def test_fonctionnalites_how_it_works_reactor_section():
assert 'dictia-bg-orbs' in body, "Missing floating orbs" assert 'dictia-bg-orbs' in body, "Missing floating orbs"
assert 'dictia-connecting-line' in body, "Missing connecting line phone↔IA" assert 'dictia-connecting-line' in body, "Missing connecting line phone↔IA"
# Stats row in section header (refonte 2026-04-29 : 4 catégories · 6 modules) # Stats row in section header (refonte v2 2026-04-29 : 12 fonctions visibles)
assert 'modules' in body, "Missing stats row 'modules'" assert 'modules' in body, "Missing stats row 'modules'"
assert 'catégories' in body, "Missing stats row 'catégories' (refonte)" assert 'fonctions' in body, "Missing stats row 'fonctions' (refonte v2)"
assert 'cloud' in body, "Missing stats row 'cloud'" assert 'cloud' in body, "Missing stats row 'cloud'"
assert 'Voir une démo' in body, "Missing demo CTA link" assert 'Voir une démo' in body, "Missing demo CTA link"