diff --git a/.claude/metrics/hooks-metrics.json b/.claude/metrics/hooks-metrics.json index 96cc20e4..6f7445cc 100644 --- a/.claude/metrics/hooks-metrics.json +++ b/.claude/metrics/hooks-metrics.json @@ -4262,6 +4262,27 @@ "file": "/home/theflow/projects/tractatus/public/index.html", "result": "passed", "reason": null + }, + { + "hook": "validate-file-edit", + "timestamp": "2025-10-19T02:52:42.520Z", + "file": "/home/theflow/projects/tractatus/public/js/components/interactive-diagram.js", + "result": "passed", + "reason": null + }, + { + "hook": "validate-file-edit", + "timestamp": "2025-10-19T02:53:17.907Z", + "file": "/home/theflow/projects/tractatus/public/js/components/interactive-diagram.js", + "result": "passed", + "reason": null + }, + { + "hook": "validate-file-edit", + "timestamp": "2025-10-19T02:53:29.476Z", + "file": "/home/theflow/projects/tractatus/public/js/components/interactive-diagram.js", + "result": "passed", + "reason": null } ], "blocks": [ @@ -4489,9 +4510,9 @@ } ], "session_stats": { - "total_edit_hooks": 424, + "total_edit_hooks": 427, "total_edit_blocks": 32, - "last_updated": "2025-10-19T02:50:18.922Z", + "last_updated": "2025-10-19T02:53:29.476Z", "total_write_hooks": 185, "total_write_blocks": 5 } diff --git a/public/js/components/interactive-diagram.js b/public/js/components/interactive-diagram.js index f59c54bf..d91be405 100644 --- a/public/js/components/interactive-diagram.js +++ b/public/js/components/interactive-diagram.js @@ -110,62 +110,88 @@ class InteractiveDiagram { } setup() { - const svg = document.getElementById('interactive-arch-diagram'); - if (!svg) { - console.warn('[InteractiveDiagram] SVG diagram not found'); + // SVG is loaded via tag, need to access its contentDocument + const objectElement = document.getElementById('interactive-svg-object'); + if (!objectElement) { + console.warn('[InteractiveDiagram] SVG object element not found'); return; } - const nodes = svg.querySelectorAll('.service-node'); - console.log(`[InteractiveDiagram] Found ${nodes.length} service nodes`); + // Wait for object to load + const initializeSVG = () => { + const svgDoc = objectElement.contentDocument; + if (!svgDoc) { + console.warn('[InteractiveDiagram] Could not access SVG contentDocument'); + return; + } - nodes.forEach(node => { - const serviceId = node.getAttribute('data-service'); + const svg = svgDoc.getElementById('interactive-arch-diagram'); + if (!svg) { + console.warn('[InteractiveDiagram] SVG diagram not found in contentDocument'); + return; + } - node.addEventListener('click', (e) => { - e.preventDefault(); - this.showServiceDetails(serviceId); + // Store reference to SVG document for later use + this.svgDoc = svgDoc; + this.svg = svg; + + const nodes = svg.querySelectorAll('.service-node'); + console.log(`[InteractiveDiagram] Found ${nodes.length} service nodes`); + + nodes.forEach(node => { + const serviceId = node.getAttribute('data-service'); + + node.addEventListener('click', (e) => { + e.preventDefault(); + this.showServiceDetails(serviceId); + }); + + node.addEventListener('mouseenter', () => { + this.highlightService(serviceId); + }); + + node.addEventListener('mouseleave', () => { + this.unhighlightService(serviceId); + }); }); - node.addEventListener('mouseenter', () => { - this.highlightService(serviceId); - }); + this.addKeyboardNavigation(nodes); + }; - node.addEventListener('mouseleave', () => { - this.unhighlightService(serviceId); - }); - }); - - this.addKeyboardNavigation(nodes); + // If object already loaded, initialize immediately + if (objectElement.contentDocument) { + initializeSVG(); + } else { + // Otherwise wait for load event + objectElement.addEventListener('load', initializeSVG); + } } highlightService(serviceId) { - const svg = document.getElementById('interactive-arch-diagram'); - if (!svg) return; + if (!this.svg) return; - const connectionLine = svg.querySelector(`#conn-${serviceId}`); + const connectionLine = this.svg.querySelector(`#conn-${serviceId}`); if (connectionLine) { connectionLine.classList.add('active'); } - const node = svg.querySelector(`#node-${serviceId}`); + const node = this.svg.querySelector(`#node-${serviceId}`); if (node) { node.classList.add('hover'); } } unhighlightService(serviceId) { - const svg = document.getElementById('interactive-arch-diagram'); - if (!svg) return; + if (!this.svg) return; if (this.activeService === serviceId) return; - const connectionLine = svg.querySelector(`#conn-${serviceId}`); + const connectionLine = this.svg.querySelector(`#conn-${serviceId}`); if (connectionLine) { connectionLine.classList.remove('active'); } - const node = svg.querySelector(`#node-${serviceId}`); + const node = this.svg.querySelector(`#node-${serviceId}`); if (node) { node.classList.remove('hover'); } @@ -180,17 +206,16 @@ class InteractiveDiagram { this.activeService = serviceId; - const svg = document.getElementById('interactive-arch-diagram'); - if (svg) { - svg.querySelectorAll('.service-node').forEach(n => n.classList.remove('active')); - svg.querySelectorAll('.connection-line').forEach(l => l.classList.remove('active')); + if (this.svg) { + this.svg.querySelectorAll('.service-node').forEach(n => n.classList.remove('active')); + this.svg.querySelectorAll('.connection-line').forEach(l => l.classList.remove('active')); - const node = svg.querySelector(`#node-${serviceId}`); + const node = this.svg.querySelector(`#node-${serviceId}`); if (node) { node.classList.add('active'); } - const connectionLine = svg.querySelector(`#conn-${serviceId}`); + const connectionLine = this.svg.querySelector(`#conn-${serviceId}`); if (connectionLine) { connectionLine.classList.add('active'); } @@ -318,10 +343,9 @@ class InteractiveDiagram { }, 300); } - const svg = document.getElementById('interactive-arch-diagram'); - if (svg) { - svg.querySelectorAll('.service-node').forEach(n => n.classList.remove('active')); - svg.querySelectorAll('.connection-line').forEach(l => l.classList.remove('active')); + if (this.svg) { + this.svg.querySelectorAll('.service-node').forEach(n => n.classList.remove('active')); + this.svg.querySelectorAll('.connection-line').forEach(l => l.classList.remove('active')); } this.activeService = null;