tfrere HF Staff commited on
Commit
136864c
·
1 Parent(s): 7a26229

fix url, fix mermaid zoom perfs, fix model perfs hover

Browse files
app/public/hf-space-parent-listener.js ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Script pour la fenêtre parente des Spaces Hugging Face
3
+ * Ce script écoute les messages de l'iframe et met à jour l'URL de la fenêtre parente
4
+ *
5
+ * Instructions d'utilisation :
6
+ * 1. Ajoutez ce script à votre Space Hugging Face dans le fichier app.py ou dans un composant Gradio
7
+ * 2. Ou utilisez-le dans une page HTML qui contient votre iframe
8
+ */
9
+
10
+ (function () {
11
+ 'use strict';
12
+
13
+ console.log('HF Space Parent Listener initialized');
14
+
15
+ // Écouter les messages de l'iframe
16
+ window.addEventListener('message', function (event) {
17
+ console.log('Received message from iframe:', event.data);
18
+
19
+ // Vérifier le type de message
20
+ if (event.data && event.data.type) {
21
+ switch (event.data.type) {
22
+ case 'urlChange':
23
+ case 'anchorChange':
24
+ case 'HF_SPACE_URL_UPDATE':
25
+ handleUrlChange(event.data);
26
+ break;
27
+ default:
28
+ console.log('Unknown message type:', event.data.type);
29
+ }
30
+ }
31
+ });
32
+
33
+ function handleUrlChange(data) {
34
+ try {
35
+ const hash = data.hash || data.anchorId;
36
+ const url = data.url;
37
+
38
+ if (hash) {
39
+ // Mettre à jour l'URL avec la nouvelle ancre
40
+ const newUrl = new URL(window.location);
41
+ newUrl.hash = hash;
42
+
43
+ // Utiliser replaceState pour éviter d'ajouter une entrée dans l'historique
44
+ window.history.replaceState(null, '', newUrl.toString());
45
+
46
+ console.log('Updated parent URL to:', newUrl.toString());
47
+
48
+ // Optionnel : faire défiler vers l'élément correspondant dans la page parente
49
+ const targetElement = document.querySelector(hash);
50
+ if (targetElement) {
51
+ targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
52
+ }
53
+ }
54
+ } catch (error) {
55
+ console.error('Error updating parent URL:', error);
56
+ }
57
+ }
58
+
59
+ // Fonction utilitaire pour tester la communication
60
+ window.testIframeCommunication = function () {
61
+ console.log('Testing iframe communication...');
62
+ const iframe = document.querySelector('iframe');
63
+ if (iframe) {
64
+ iframe.contentWindow.postMessage({ type: 'test' }, '*');
65
+ } else {
66
+ console.log('No iframe found');
67
+ }
68
+ };
69
+
70
+ })();
app/src/components/TableOfContents.astro CHANGED
@@ -513,20 +513,67 @@ const { tableOfContentAutoCollapse = false } = Astro.props as Props;
513
  if (window.location.href !== newUrl) {
514
  history.pushState(null, null, newUrl);
515
 
516
- // Communiquer avec l'iframe parent (pour les Spaces HF)
517
  if (window.parent !== window) {
518
  try {
519
- window.parent.postMessage(
 
 
 
 
 
 
 
 
 
 
520
  {
521
  type: "urlChange",
522
  url: newUrl,
523
  hash: headingId,
524
  },
525
- "*",
526
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  } catch (e) {
528
- // Ignorer les erreurs de communication avec le parent
529
- console.debug("Could not communicate with parent window:", e);
 
 
530
  }
531
  }
532
  }
 
513
  if (window.location.href !== newUrl) {
514
  history.pushState(null, null, newUrl);
515
 
516
+ // Essayer différentes méthodes pour communiquer avec la fenêtre parente
517
  if (window.parent !== window) {
518
  try {
519
+ // Méthode 1: Essayer de modifier directement l'URL du parent (si autorisé)
520
+ try {
521
+ window.parent.location.hash = headingId;
522
+ console.debug("Successfully updated parent URL directly");
523
+ return;
524
+ } catch (e) {
525
+ console.debug("Direct parent URL update blocked:", e.message);
526
+ }
527
+
528
+ // Méthode 2: Utiliser postMessage avec différents formats
529
+ const messages = [
530
  {
531
  type: "urlChange",
532
  url: newUrl,
533
  hash: headingId,
534
  },
535
+ {
536
+ type: "anchorChange",
537
+ anchorId: headingId,
538
+ url: newUrl,
539
+ },
540
+ {
541
+ type: "HF_SPACE_URL_UPDATE",
542
+ hash: headingId,
543
+ url: newUrl,
544
+ },
545
+ ];
546
+
547
+ messages.forEach((msg) => {
548
+ try {
549
+ window.parent.postMessage(msg, "*");
550
+ } catch (e) {
551
+ console.debug("PostMessage failed:", e.message);
552
+ }
553
+ });
554
+
555
+ // Méthode 3: Essayer avec l'origine spécifique si on peut la détecter
556
+ try {
557
+ const parentOrigin = window.parent.location.origin;
558
+ window.parent.postMessage(
559
+ {
560
+ type: "urlChange",
561
+ url: newUrl,
562
+ hash: headingId,
563
+ },
564
+ parentOrigin,
565
+ );
566
+ } catch (e) {
567
+ console.debug(
568
+ "PostMessage with specific origin failed:",
569
+ e.message,
570
+ );
571
+ }
572
  } catch (e) {
573
+ console.debug(
574
+ "All parent communication methods failed:",
575
+ e.message,
576
+ );
577
  }
578
  }
579
  }
app/src/content/embeds/base-model-performance.html CHANGED
@@ -455,7 +455,7 @@
455
  tooltip.innerHTML = `
456
  <div class="tooltip-title">${model.name}</div>
457
  <div class="tooltip-row">
458
- <span class="tooltip-label">Taille:</span>
459
  <span class="tooltip-value">${model.size.toFixed(1)}B params</span>
460
  </div>
461
  <div class="tooltip-row">
@@ -463,7 +463,7 @@
463
  <span class="tooltip-value">${model.winRate.toFixed(1)}%</span>
464
  </div>
465
  <div class="tooltip-row">
466
- <span class="tooltip-label">Efficacité:</span>
467
  <span class="tooltip-value">${(model.winRate / model.size).toFixed(2)} pts/B</span>
468
  </div>
469
  `;
 
455
  tooltip.innerHTML = `
456
  <div class="tooltip-title">${model.name}</div>
457
  <div class="tooltip-row">
458
+ <span class="tooltip-label">Size:</span>
459
  <span class="tooltip-value">${model.size.toFixed(1)}B params</span>
460
  </div>
461
  <div class="tooltip-row">
 
463
  <span class="tooltip-value">${model.winRate.toFixed(1)}%</span>
464
  </div>
465
  <div class="tooltip-row">
466
+ <span class="tooltip-label">Efficiency:</span>
467
  <span class="tooltip-value">${(model.winRate / model.size).toFixed(2)} pts/B</span>
468
  </div>
469
  `;
app/src/scripts/mermaid-zoom-optimized.js ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Mermaid Zoom Integration - Version Optimisée
3
+ * Système léger pour beaucoup de diagrammes Mermaid
4
+ */
5
+
6
+ console.log("🚀 Mermaid Zoom Script v16.0 loaded - OPTIMIZED for many diagrams");
7
+
8
+ // Cache pour les images générées
9
+ const imageCache = new Map();
10
+
11
+ // Fonction pour appliquer les styles Mermaid au SVG selon le thème
12
+ function applyMermaidStylesToSvg(svgElement) {
13
+ try {
14
+ const isDark = document.documentElement.getAttribute("data-theme") === "dark";
15
+
16
+ // Couleurs selon le thème
17
+ const colors = isDark ? {
18
+ nodeFill: '#1a1a1a',
19
+ nodeStroke: '#ffffff',
20
+ clusterFill: '#2a2a2a',
21
+ clusterStroke: '#ffffff',
22
+ pathStroke: '#ffffff',
23
+ textColor: '#ffffff'
24
+ } : {
25
+ nodeFill: '#ffffff',
26
+ nodeStroke: '#333333',
27
+ clusterFill: '#f9f9f9',
28
+ clusterStroke: '#333333',
29
+ pathStroke: '#333333',
30
+ textColor: '#333333'
31
+ };
32
+
33
+ // Appliquer border-radius et couleurs
34
+ const rects = svgElement.querySelectorAll('rect:not(.flowchart-link), .node rect, .nodeLabel rect');
35
+ rects.forEach(rect => {
36
+ rect.setAttribute('rx', '8');
37
+ rect.setAttribute('ry', '8');
38
+ rect.setAttribute('fill', colors.nodeFill);
39
+ rect.setAttribute('stroke', colors.nodeStroke);
40
+ });
41
+
42
+ const clusterRects = svgElement.querySelectorAll('.cluster rect');
43
+ clusterRects.forEach(rect => {
44
+ rect.setAttribute('rx', '8');
45
+ rect.setAttribute('ry', '8');
46
+ rect.setAttribute('fill', colors.clusterFill);
47
+ rect.setAttribute('stroke', colors.clusterStroke);
48
+ });
49
+
50
+ const paths = svgElement.querySelectorAll('.edgePath');
51
+ paths.forEach(path => {
52
+ path.setAttribute('stroke', colors.pathStroke);
53
+ });
54
+
55
+ const textElements = svgElement.querySelectorAll('text, .nodeLabel text, .edgeLabel text');
56
+ textElements.forEach(text => {
57
+ text.setAttribute('fill', colors.textColor);
58
+ });
59
+
60
+ } catch (error) {
61
+ console.error('❌ Error applying styles to SVG:', error);
62
+ }
63
+ }
64
+
65
+ // Fonction pour générer une clé de cache unique
66
+ function getCacheKey(svgElement, theme) {
67
+ const svgContent = svgElement.outerHTML;
68
+ const hash = svgContent.length + svgContent.slice(0, 100);
69
+ return `${hash}-${theme}`;
70
+ }
71
+
72
+ // Fonction pour convertir SVG en image (avec cache)
73
+ function convertSvgToImageCached(svgElement, wrapper, theme) {
74
+ const cacheKey = getCacheKey(svgElement, theme);
75
+
76
+ // Vérifier le cache
77
+ if (imageCache.has(cacheKey)) {
78
+ console.log(`📦 Using cached image for theme: ${theme}`);
79
+ return imageCache.get(cacheKey);
80
+ }
81
+
82
+ try {
83
+ const wrapperRect = wrapper.getBoundingClientRect();
84
+ const wrapperWidth = Math.round(wrapperRect.width);
85
+ const wrapperHeight = Math.round(wrapperRect.height);
86
+
87
+ // Cloner le SVG
88
+ const clonedSvg = svgElement.cloneNode(true);
89
+ applyMermaidStylesToSvg(clonedSvg);
90
+
91
+ // Créer une image 2x plus grande pour le zoom
92
+ const zoomFactor = 2;
93
+ const imageWidth = wrapperWidth * zoomFactor;
94
+ const imageHeight = wrapperHeight * zoomFactor;
95
+
96
+ clonedSvg.setAttribute('width', imageWidth);
97
+ clonedSvg.setAttribute('height', imageHeight);
98
+
99
+ // Créer l'URL de l'image
100
+ const svgData = new XMLSerializer().serializeToString(clonedSvg);
101
+ const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
102
+ const svgUrl = URL.createObjectURL(svgBlob);
103
+
104
+ // Créer l'élément image
105
+ const imgElement = document.createElement('img');
106
+ imgElement.src = svgUrl;
107
+ imgElement.style.width = `${wrapperWidth}px`;
108
+ imgElement.style.height = `${wrapperHeight}px`;
109
+ imgElement.style.display = 'block';
110
+ imgElement.setAttribute('data-zoomable', '1');
111
+ imgElement.classList.add('mermaid-zoom-image');
112
+
113
+ const result = {
114
+ imgElement,
115
+ svgUrl,
116
+ dimensions: { wrapperWidth, wrapperHeight, imageWidth, imageHeight }
117
+ };
118
+
119
+ // Mettre en cache
120
+ imageCache.set(cacheKey, result);
121
+ console.log(`💾 Cached image for theme: ${theme}`);
122
+
123
+ return result;
124
+
125
+ } catch (error) {
126
+ console.error("❌ Error converting SVG to image:", error);
127
+ return null;
128
+ }
129
+ }
130
+
131
+ // Fonction pour initialiser le zoom sur un diagramme Mermaid
132
+ function initMermaidZoom(mermaidEl, index) {
133
+ // Vérifier si déjà wrappé
134
+ if (mermaidEl.parentElement?.classList.contains("mermaid-zoom-wrapper")) {
135
+ return;
136
+ }
137
+
138
+ console.log(`📦 Setting up zoom for Mermaid ${index}`);
139
+
140
+ // Créer le wrapper
141
+ const wrapper = document.createElement("div");
142
+ wrapper.className = "mermaid-zoom-wrapper";
143
+ wrapper.setAttribute("data-zoomable", "1");
144
+ wrapper.style.display = "block";
145
+ wrapper.style.width = "100%";
146
+ wrapper.style.maxWidth = "100%";
147
+
148
+ // Insérer le wrapper avant l'élément Mermaid
149
+ mermaidEl.parentNode.insertBefore(wrapper, mermaidEl);
150
+ wrapper.appendChild(mermaidEl);
151
+
152
+ // Ajouter l'événement de clic (conversion à la demande)
153
+ wrapper.addEventListener("click", (e) => {
154
+ e.preventDefault();
155
+ e.stopPropagation();
156
+
157
+ const svgElement = mermaidEl.querySelector("svg");
158
+ if (!svgElement) return;
159
+
160
+ const currentTheme = document.documentElement.getAttribute("data-theme");
161
+ console.log(`🖱️ Mermaid ${index} clicked, converting for zoom`);
162
+
163
+ // Convertir l'image (avec cache)
164
+ const result = convertSvgToImageCached(svgElement, wrapper, currentTheme);
165
+ if (!result) return;
166
+
167
+ // Remplacer le contenu par l'image
168
+ wrapper.innerHTML = '';
169
+ wrapper.appendChild(result.imgElement);
170
+
171
+ // Initialiser medium-zoom
172
+ const isDark = currentTheme === "dark";
173
+ const background = isDark ? "rgba(0,0,0,.9)" : "rgba(0,0,0,.85)";
174
+
175
+ const zoomInstance = window.mediumZoom(result.imgElement, {
176
+ background,
177
+ margin: 24,
178
+ scrollOffset: 0,
179
+ });
180
+
181
+ console.log(`🎉 Zoom initialized for Mermaid ${index}`);
182
+
183
+ // Forcer les z-index élevés
184
+ const forceZIndex = () => {
185
+ const overlay = document.querySelector('.medium-zoom-overlay');
186
+ const zoomedImage = document.querySelector('.medium-zoom-image--opened');
187
+
188
+ if (overlay) {
189
+ overlay.style.zIndex = '9999999';
190
+ overlay.style.setProperty('z-index', '9999999', 'important');
191
+ }
192
+
193
+ if (zoomedImage) {
194
+ zoomedImage.style.zIndex = '10000000';
195
+ zoomedImage.style.setProperty('z-index', '10000000', 'important');
196
+ zoomedImage.style.filter = 'none';
197
+ zoomedImage.style.setProperty('filter', 'none', 'important');
198
+ }
199
+ };
200
+
201
+ // Écouter les événements de zoom
202
+ result.imgElement.addEventListener('zoom:open', forceZIndex);
203
+ result.imgElement.addEventListener('zoom:opened', forceZIndex);
204
+
205
+ // Observer pour forcer les styles
206
+ const observer = new MutationObserver(forceZIndex);
207
+ observer.observe(document.body, { childList: true, subtree: true });
208
+
209
+ // Nettoyer l'observer après 5 secondes
210
+ setTimeout(() => observer.disconnect(), 5000);
211
+ });
212
+ }
213
+
214
+ // Fonction principale optimisée
215
+ function setupMermaidZoomOptimized() {
216
+ const mermaidElements = document.querySelectorAll(".mermaid");
217
+ console.log(`🔍 Found ${mermaidElements.length} Mermaid elements`);
218
+
219
+ mermaidElements.forEach((mermaidEl, index) => {
220
+ initMermaidZoom(mermaidEl, index);
221
+ });
222
+ }
223
+
224
+ // Observer global optimisé (un seul observer pour tout)
225
+ function setupGlobalObserver() {
226
+ const observer = new MutationObserver((mutations) => {
227
+ let shouldUpdate = false;
228
+
229
+ mutations.forEach((mutation) => {
230
+ if (mutation.type === 'childList') {
231
+ // Vérifier si de nouveaux diagrammes Mermaid ont été ajoutés
232
+ mutation.addedNodes.forEach(node => {
233
+ if (node.nodeType === 1) { // Element node
234
+ if (node.classList?.contains('mermaid') ||
235
+ node.querySelector?.('.mermaid')) {
236
+ shouldUpdate = true;
237
+ }
238
+ }
239
+ });
240
+ }
241
+ });
242
+
243
+ if (shouldUpdate) {
244
+ console.log(`🔄 New Mermaid diagrams detected, updating...`);
245
+ setTimeout(setupMermaidZoomOptimized, 100);
246
+ }
247
+ });
248
+
249
+ observer.observe(document.body, {
250
+ childList: true,
251
+ subtree: true
252
+ });
253
+
254
+ console.log(`👁️ Global observer started`);
255
+ }
256
+
257
+ // Initialisation optimisée
258
+ function initMermaidZoomOptimized() {
259
+ console.log("🎯 Initializing optimized Mermaid zoom");
260
+
261
+ // Attendre que mediumZoom soit disponible
262
+ const checkMediumZoom = () => {
263
+ if (window.mediumZoom) {
264
+ console.log("✅ mediumZoom found, initializing optimized Mermaid zoom");
265
+ setupMermaidZoomOptimized();
266
+ setupGlobalObserver();
267
+ } else {
268
+ console.log("⏳ Waiting for mediumZoom...");
269
+ setTimeout(checkMediumZoom, 100);
270
+ }
271
+ };
272
+
273
+ checkMediumZoom();
274
+ }
275
+
276
+ // Auto-initialisation
277
+ if (document.readyState === "loading") {
278
+ document.addEventListener("DOMContentLoaded", initMermaidZoomOptimized);
279
+ } else {
280
+ initMermaidZoomOptimized();
281
+ }
282
+
283
+ // Aussi après le chargement complet
284
+ window.addEventListener("load", () => {
285
+ setTimeout(initMermaidZoomOptimized, 1000);
286
+ });
287
+
288
+ // Nettoyer le cache périodiquement (éviter les fuites mémoire)
289
+ setInterval(() => {
290
+ if (imageCache.size > 20) {
291
+ console.log(`🧹 Cleaning image cache (${imageCache.size} items)`);
292
+ imageCache.clear();
293
+ }
294
+ }, 60000); // Toutes les minutes
app/src/scripts/mermaid-zoom.js CHANGED
@@ -9,27 +9,29 @@ function applyMermaidStylesToSvg(svgElement) {
9
  const isDark = document.documentElement.getAttribute("data-theme") === "dark";
10
  console.log(`🎨 Applying Mermaid styles for theme: ${isDark ? 'dark' : 'light'}`);
11
 
12
- // Couleurs selon le thème
13
  const colors = isDark ? {
14
  nodeFill: '#1a1a1a',
15
  nodeStroke: '#ffffff',
16
- nodeStrokeWidth: '1',
17
  clusterFill: '#2a2a2a',
18
  clusterStroke: '#ffffff',
19
- clusterStrokeWidth: '1',
20
  pathStroke: '#ffffff',
21
- pathStrokeWidth: '1',
22
- textColor: '#ffffff'
 
23
  } : {
24
  nodeFill: '#ffffff',
25
- nodeStroke: '#333333',
26
- nodeStrokeWidth: '1',
27
  clusterFill: '#f9f9f9',
28
- clusterStroke: '#333333',
29
- clusterStrokeWidth: '1',
30
- pathStroke: '#333333',
31
- pathStrokeWidth: '1',
32
- textColor: '#333333'
 
33
  };
34
 
35
  // Appliquer border-radius aux rectangles
@@ -74,19 +76,33 @@ function applyMermaidStylesToSvg(svgElement) {
74
  }
75
  });
76
 
77
- // Appliquer les couleurs aux chemins
78
- const paths = svgElement.querySelectorAll('.edgePath');
79
  paths.forEach(path => {
80
  path.setAttribute('stroke', colors.pathStroke);
81
  path.setAttribute('stroke-width', colors.pathStrokeWidth);
82
  });
83
 
 
 
 
 
 
 
 
84
  // Appliquer les couleurs au texte
85
  const textElements = svgElement.querySelectorAll('text, .nodeLabel text, .edgeLabel text');
86
  textElements.forEach(text => {
87
  text.setAttribute('fill', colors.textColor);
88
  });
89
 
 
 
 
 
 
 
 
90
  console.log(`🎨 Applied Mermaid styles: ${rects.length} rects, ${clusters.length} clusters, ${paths.length} paths, ${textElements.length} text elements`);
91
 
92
  } catch (error) {
@@ -199,26 +215,41 @@ function convertSvgToImagePreservingDimensions(svgElement, wrapper, originalMerm
199
  // Appliquer les styles Mermaid
200
  applyMermaidStylesToSvg(clonedSvg);
201
 
202
- // Forcer les dimensions exactes du wrapper sur le SVG
203
- clonedSvg.setAttribute('width', wrapperWidth);
204
- clonedSvg.setAttribute('height', wrapperHeight);
205
- clonedSvg.style.width = `${wrapperWidth}px`;
206
- clonedSvg.style.height = `${wrapperHeight}px`;
 
 
 
 
 
 
 
 
 
 
 
207
 
208
  // Créer une URL data pour le SVG
209
  const svgData = new XMLSerializer().serializeToString(clonedSvg);
210
  const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
211
  const svgUrl = URL.createObjectURL(svgBlob);
212
 
213
- // Créer un élément img avec les MÊMES dimensions que le wrapper
214
  const imgElement = document.createElement('img');
215
  imgElement.src = svgUrl;
216
- imgElement.style.width = `${wrapperWidth}px`;
217
- imgElement.style.height = `${wrapperHeight}px`;
218
  imgElement.style.display = 'block';
219
  imgElement.setAttribute('data-zoomable', '1');
220
  imgElement.classList.add('mermaid-zoom-image'); // Classe spécifique pour Mermaid
221
 
 
 
 
 
222
  console.log(`🖼️ Image created with exact dimensions:`, { width: wrapperWidth, height: wrapperHeight });
223
 
224
  // Remplacer le contenu du wrapper par l'image
@@ -691,7 +722,7 @@ function setupMermaidZoom() {
691
  } else {
692
  console.log(`❌ No SVG found in Mermaid element ${index}`);
693
  }
694
- }, 2000);
695
  });
696
  }
697
 
@@ -778,7 +809,7 @@ window.addEventListener("load", () => {
778
 
779
  // Observer simple pour les nouveaux diagrammes Mermaid
780
  const observer = new MutationObserver(() => {
781
- setTimeout(initMermaidZoom, 500);
782
  });
783
 
784
  observer.observe(document.body, {
@@ -786,4 +817,4 @@ observer.observe(document.body, {
786
  subtree: true,
787
  });
788
 
789
- console.log("🚀 Mermaid Zoom Script v14.0 loaded - REAL medium-zoom with JavaScript z-index fix");
 
9
  const isDark = document.documentElement.getAttribute("data-theme") === "dark";
10
  console.log(`🎨 Applying Mermaid styles for theme: ${isDark ? 'dark' : 'light'}`);
11
 
12
+ // Couleurs selon le thème - avec plus de contraste pour le zoom
13
  const colors = isDark ? {
14
  nodeFill: '#1a1a1a',
15
  nodeStroke: '#ffffff',
16
+ nodeStrokeWidth: '2', // Plus épais pour plus de visibilité
17
  clusterFill: '#2a2a2a',
18
  clusterStroke: '#ffffff',
19
+ clusterStrokeWidth: '2',
20
  pathStroke: '#ffffff',
21
+ pathStrokeWidth: '2', // Plus épais pour les flèches
22
+ textColor: '#ffffff',
23
+ linkColor: '#ffffff' // Couleur spécifique pour les liens
24
  } : {
25
  nodeFill: '#ffffff',
26
+ nodeStroke: '#000000', // Noir pur pour plus de contraste
27
+ nodeStrokeWidth: '2',
28
  clusterFill: '#f9f9f9',
29
+ clusterStroke: '#000000', // Noir pur
30
+ clusterStrokeWidth: '2',
31
+ pathStroke: '#000000', // Noir pur pour les flèches
32
+ pathStrokeWidth: '2',
33
+ textColor: '#000000', // Noir pur
34
+ linkColor: '#000000' // Noir pur pour les liens
35
  };
36
 
37
  // Appliquer border-radius aux rectangles
 
76
  }
77
  });
78
 
79
+ // Appliquer les couleurs aux chemins et flèches
80
+ const paths = svgElement.querySelectorAll('.edgePath, path, .flowchart-link');
81
  paths.forEach(path => {
82
  path.setAttribute('stroke', colors.pathStroke);
83
  path.setAttribute('stroke-width', colors.pathStrokeWidth);
84
  });
85
 
86
+ // Appliquer les couleurs aux liens spécifiquement
87
+ const links = svgElement.querySelectorAll('.flowchart-link, .edgeLabel');
88
+ links.forEach(link => {
89
+ link.setAttribute('stroke', colors.linkColor);
90
+ link.setAttribute('fill', colors.linkColor);
91
+ });
92
+
93
  // Appliquer les couleurs au texte
94
  const textElements = svgElement.querySelectorAll('text, .nodeLabel text, .edgeLabel text');
95
  textElements.forEach(text => {
96
  text.setAttribute('fill', colors.textColor);
97
  });
98
 
99
+ // Appliquer les couleurs aux marqueurs de flèches
100
+ const markers = svgElement.querySelectorAll('marker, marker path');
101
+ markers.forEach(marker => {
102
+ marker.setAttribute('fill', colors.pathStroke);
103
+ marker.setAttribute('stroke', colors.pathStroke);
104
+ });
105
+
106
  console.log(`🎨 Applied Mermaid styles: ${rects.length} rects, ${clusters.length} clusters, ${paths.length} paths, ${textElements.length} text elements`);
107
 
108
  } catch (error) {
 
215
  // Appliquer les styles Mermaid
216
  applyMermaidStylesToSvg(clonedSvg);
217
 
218
+ // Créer une image PLUS GRANDE pour permettre un vrai zoom (2x la taille)
219
+ const zoomFactor = 2;
220
+ const imageWidth = wrapperWidth * zoomFactor;
221
+ const imageHeight = wrapperHeight * zoomFactor;
222
+
223
+ // Forcer les dimensions plus grandes sur le SVG
224
+ clonedSvg.setAttribute('width', imageWidth);
225
+ clonedSvg.setAttribute('height', imageHeight);
226
+ clonedSvg.style.width = `${imageWidth}px`;
227
+ clonedSvg.style.height = `${imageHeight}px`;
228
+
229
+ console.log(`🔍 Creating zoomable image:`, {
230
+ original: { width: wrapperWidth, height: wrapperHeight },
231
+ zoomed: { width: imageWidth, height: imageHeight },
232
+ factor: zoomFactor
233
+ });
234
 
235
  // Créer une URL data pour le SVG
236
  const svgData = new XMLSerializer().serializeToString(clonedSvg);
237
  const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
238
  const svgUrl = URL.createObjectURL(svgBlob);
239
 
240
+ // Créer un élément img avec les dimensions du wrapper (affichage normal)
241
  const imgElement = document.createElement('img');
242
  imgElement.src = svgUrl;
243
+ imgElement.style.width = `${wrapperWidth}px`; // Affichage normal
244
+ imgElement.style.height = `${wrapperHeight}px`; // Affichage normal
245
  imgElement.style.display = 'block';
246
  imgElement.setAttribute('data-zoomable', '1');
247
  imgElement.classList.add('mermaid-zoom-image'); // Classe spécifique pour Mermaid
248
 
249
+ // Ajouter les attributs pour medium-zoom (dimensions réelles de l'image)
250
+ imgElement.setAttribute('data-zoom-width', imageWidth);
251
+ imgElement.setAttribute('data-zoom-height', imageHeight);
252
+
253
  console.log(`🖼️ Image created with exact dimensions:`, { width: wrapperWidth, height: wrapperHeight });
254
 
255
  // Remplacer le contenu du wrapper par l'image
 
722
  } else {
723
  console.log(`❌ No SVG found in Mermaid element ${index}`);
724
  }
725
+ }, 1000); // Réduit de 2000ms à 1000ms pour être plus rapide
726
  });
727
  }
728
 
 
809
 
810
  // Observer simple pour les nouveaux diagrammes Mermaid
811
  const observer = new MutationObserver(() => {
812
+ setTimeout(initMermaidZoom, 200); // Réduit de 500ms à 200ms
813
  });
814
 
815
  observer.observe(document.body, {
 
817
  subtree: true,
818
  });
819
 
820
+ console.log("🚀 Mermaid Zoom Script v18.0 loaded - Enhanced contrast for arrows and links");