<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cargo-coupling Visualization</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/css/style.css">
<script src="https://unpkg.com/cytoscape@3.28.1/dist/cytoscape.min.js"></script>
<script src="https://unpkg.com/dagre@0.8.5/dist/dagre.min.js"></script>
<script src="https://unpkg.com/cytoscape-dagre@2.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div class="header-trigger" id="header-trigger"></div>
<div class="footer-trigger" id="footer-trigger"></div>
<button class="sidebar-toggle" id="sidebar-toggle" title="Toggle sidebar (s)">
<span class="icon">◀</span>
</button>
<div class="container">
<header class="header" id="header">
<div class="header-left">
<h1>🔗 cargo-coupling</h1>
</div>
<div class="header-stats" id="header-stats">
<span class="stat">Loading...</span>
</div>
<div class="header-right">
<button id="lang-toggle" class="btn btn-lang" title="Switch language">
<span id="lang-label">EN</span>
</button>
</div>
</header>
<main class="main">
<div class="graph-container" id="cy"></div>
<div class="tree-container" id="tree-view" style="display: none;"></div>
</main>
<aside class="sidebar" id="sidebar">
<div id="sidebar-resizer" class="resize-handle"></div>
<section class="panel">
<h2>Jobs</h2>
<div class="job-buttons">
<button id="job-entry-points" class="btn btn-job" title="Where should I start reading?">
🚀 Entry Points
</button>
<button id="job-path-finder" class="btn btn-job" title="How does A connect to B?">
🔍 Find Path
</button>
<button id="job-simple-view" class="btn btn-job" title="Show simplified architecture">
📊 Simple View
</button>
<button id="job-what-breaks" class="btn btn-job" title="What might break if I change this?" disabled>
⚠️ What Breaks?
</button>
</div>
<div id="job-result" class="job-result"></div>
</section>
<section class="panel" id="path-finder-panel" style="display: none;">
<h2>Path Finder</h2>
<div class="path-finder-inputs">
<select id="path-from" class="select">
<option value="">From module...</option>
</select>
<span style="color: var(--text-secondary);">→</span>
<select id="path-to" class="select">
<option value="">To module...</option>
</select>
</div>
<button id="find-path-btn" class="btn" style="width: 100%; margin-top: 0.5rem;">
Find Dependency Path
</button>
<div id="path-result" class="path-result"></div>
</section>
<section class="panel">
<h2>Search</h2>
<input type="text" id="search-input" class="search-input" placeholder="Search modules... (press /)">
</section>
<section class="panel">
<h2>View</h2>
<div class="view-buttons">
<button id="view-graph" class="btn btn-view active">Graph</button>
<button id="view-tree" class="btn btn-view">Tree</button>
</div>
<div class="filter-group" style="margin-top: 0.5rem;">
<label><input type="checkbox" id="center-mode-toggle"> Center on Click</label>
<p style="font-size: 0.6875rem; color: var(--text-secondary); margin-top: 0.25rem;">
Re-layout graph with selected node at center
</p>
</div>
<div class="filter-group" style="margin-top: 0.5rem;">
<label><input type="checkbox" id="show-items-toggle"> Show Items (fn/type)</label>
<p style="font-size: 0.6875rem; color: var(--text-secondary); margin-top: 0.25rem;">
Show function and type nodes in graph
</p>
</div>
</section>
<section class="panel" id="layout-panel">
<h2>Layout</h2>
<select id="layout-select" class="select">
<option value="cose">Force-directed</option>
<option value="dagre">Hierarchy</option>
<option value="concentric">Concentric</option>
<option value="grid">Grid</option>
</select>
</section>
<section class="panel">
<h2>Filters</h2>
<div class="filter-group">
<label>Strength</label>
<div class="checkbox-group" id="strength-filters">
<label><input type="checkbox" value="Intrusive" checked> Intrusive</label>
<label><input type="checkbox" value="Functional" checked> Functional</label>
<label><input type="checkbox" value="Model" checked> Model</label>
<label><input type="checkbox" value="Contract" checked> Contract</label>
</div>
</div>
<div class="filter-group">
<label>Distance</label>
<div class="checkbox-group" id="distance-filters">
<label><input type="checkbox" value="SameFunction" checked> Same Function</label>
<label><input type="checkbox" value="SameModule" checked> Same Module</label>
<label><input type="checkbox" value="DifferentModule" checked> Different Module</label>
<label><input type="checkbox" value="DifferentCrate"> External Crate</label>
</div>
</div>
<div class="filter-group">
<label>Volatility</label>
<div class="checkbox-group" id="volatility-filters">
<label><input type="checkbox" value="Low" checked> Low</label>
<label><input type="checkbox" value="Medium" checked> Medium</label>
<label><input type="checkbox" value="High" checked> High</label>
</div>
</div>
<div class="filter-group">
<label>Balance Score: <span id="balance-value">0.0 - 1.0</span></label>
<div class="range-slider">
<input type="range" id="balance-min" min="0" max="100" value="0">
<input type="range" id="balance-max" min="0" max="100" value="100">
</div>
</div>
<div class="filter-group">
<label><input type="checkbox" id="show-issues-only"> Show Issues Only</label>
<label><input type="checkbox" id="show-cycles-only"> Show Cycles Only</label>
<label><input type="checkbox" id="hide-external" checked> Hide External Crates</label>
</div>
<div class="filter-actions">
<button id="reset-filters" class="btn">Reset Filters</button>
<button id="fit-graph" class="btn">Fit to Screen</button>
</div>
</section>
<section class="panel legend-panel">
<h2>Legend <button id="toggle-legend" class="btn-toggle">[?]</button></h2>
<div id="legend-content" style="display: none;">
<div class="legend-section">
<h4>Edge Colors (Coupling Balance)</h4>
<div class="legend-items">
<div class="legend-item">
<span class="legend-color" style="background: #22c55e;"></span>
<span class="legend-label">Good: 凝集性/疎結合</span>
</div>
<div class="legend-item">
<span class="legend-color" style="background: #3b82f6;"></span>
<span class="legend-label">Stable: 低変動性</span>
</div>
<div class="legend-item">
<span class="legend-color" style="background: #eab308;"></span>
<span class="legend-label">Review: 確認推奨</span>
</div>
<div class="legend-item">
<span class="legend-color" style="background: #ef4444;"></span>
<span class="legend-label">Critical: 問題あり</span>
</div>
</div>
</div>
<div class="legend-section">
<h4>Edge Style (Distance)</h4>
<div class="legend-items">
<div class="legend-item">
<span class="legend-line solid"></span>
<span class="legend-label">Same Module</span>
</div>
<div class="legend-item">
<span class="legend-line dashed"></span>
<span class="legend-label">Different Module</span>
</div>
<div class="legend-item">
<span class="legend-line dotted"></span>
<span class="legend-label">External Crate</span>
</div>
</div>
</div>
<div class="legend-section balance-rules">
<h4>バランス方程式</h4>
<code>BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY</code>
<table class="balance-table">
<tr><td>強結合 + 近距離</td><td class="good">✅ OK</td></tr>
<tr><td>弱結合 + 遠距離</td><td class="good">✅ OK</td></tr>
<tr><td>強結合 + 遠距離</td><td class="bad">❌ 問題</td></tr>
<tr><td>強結合 + 高変動性</td><td class="bad">❌ 問題</td></tr>
</table>
</div>
</div>
</section>
<section class="panel">
<h2>Analysis</h2>
<div id="analysis-mode-indicator"></div>
<div class="analysis-buttons">
<button id="show-dependents" class="btn btn-analysis" disabled>
Show Dependents (→)
</button>
<button id="show-dependencies" class="btn btn-analysis" disabled>
Show Dependencies (←)
</button>
<button id="show-impact" class="btn btn-analysis" disabled>
Full Impact Analysis
</button>
</div>
<div id="blast-radius" style="display: none;"></div>
<p class="hint" id="analysis-hint">Select a node first</p>
</section>
<section class="panel" id="critical-issues-panel">
<h2>🔥 <span data-i18n="critical_issues">Critical Issues</span> <span id="critical-count" class="badge critical">0</span></h2>
<p style="font-size: 0.6875rem; color: var(--text-secondary); margin-bottom: 0.5rem;">
<span data-i18n="unbalanced_deps">Unbalanced coupling relationships</span>
</p>
<div id="critical-issues-list" class="critical-issues-list">
<p class="placeholder" data-i18n="analyzing">Analyzing...</p>
</div>
</section>
<section class="panel">
<h2>Hotspots</h2>
<p style="font-size: 0.75rem; color: var(--text-secondary); margin-bottom: 0.5rem;">
High-impact refactoring targets
</p>
<div id="hotspot-list" class="hotspot-list">
<p class="placeholder">Analyzing...</p>
</div>
</section>
<section class="panel">
<h2>Key Modules</h2>
<div class="quick-actions">
<button class="quick-action active" data-sort="connections">Connections</button>
<button class="quick-action" data-sort="issues">Issues</button>
<button class="quick-action" data-sort="health">Health</button>
</div>
<div id="module-rankings" class="module-rank-list">
<p class="placeholder">Loading...</p>
</div>
</section>
<section class="panel">
<h2>Cluster View</h2>
<div class="filter-actions">
<button id="detect-clusters" class="btn">Detect Clusters</button>
<button id="clear-clusters" class="btn">Clear Colors</button>
</div>
<div id="cluster-info" class="cluster-info"></div>
</section>
<section class="panel">
<h2>Issues <span id="issue-count" class="badge">0</span></h2>
<div id="issue-list" class="issue-list">
<p class="placeholder">No issues detected</p>
</div>
</section>
<section class="panel">
<h2>Export</h2>
<div class="filter-actions">
<button id="export-png" class="btn">PNG Image</button>
<button id="export-json" class="btn">JSON Data</button>
</div>
</section>
<section class="panel" id="details-panel">
<h2>Details</h2>
<div id="node-details">
<p class="placeholder">Click a node or edge to see details</p>
</div>
</section>
<section class="panel" id="item-graph-panel" style="display: none;">
<h2>📦 Item Dependencies <button id="close-item-graph" class="btn-close">×</button></h2>
<p class="item-graph-hint">Dependencies within this module</p>
<div class="item-filter-group">
<label><input type="checkbox" id="item-filter-fn" checked> Functions</label>
<label><input type="checkbox" id="item-filter-type" checked> Types</label>
<label><input type="checkbox" id="item-filter-trait" checked> Traits</label>
</div>
<div id="item-graph-container" class="item-graph-container"></div>
<div id="item-graph-legend" class="item-graph-legend">
<span class="legend-item"><span class="dot fn"></span> fn</span>
<span class="legend-item"><span class="dot type"></span> type</span>
<span class="legend-item"><span class="dot trait"></span> trait</span>
<span class="legend-item" style="margin-left: auto;"><span id="item-count">0</span> items</span>
</div>
<div id="item-details" class="item-details"></div>
</section>
<section class="panel" id="legend-panel">
<h2>Legend</h2>
<div class="legend">
<div class="legend-section">
<h4>Edge Color (Balance)</h4>
<div class="legend-item"><span class="color-box" style="background: #22c55e;"></span> Balanced (>0.8)</div>
<div class="legend-item"><span class="color-box" style="background: #eab308;"></span> Needs Review (0.4-0.8)</div>
<div class="legend-item"><span class="color-box" style="background: #ef4444;"></span> Critical (<0.4)</div>
<div class="legend-item"><span class="color-box" style="background: #dc2626; border: 2px solid #fff;"></span> Circular Dependency</div>
</div>
<div class="legend-section">
<h4>Edge Style (Distance)</h4>
<div class="legend-item"><span class="line-style solid"></span> Same Module</div>
<div class="legend-item"><span class="line-style dashed"></span> Different Module</div>
<div class="legend-item"><span class="line-style dotted"></span> Different Crate</div>
</div>
<div class="legend-section">
<h4>Edge Width (Strength)</h4>
<div class="legend-item">Thick = Intrusive, Thin = Contract</div>
</div>
</div>
</section>
<section class="panel">
<h2>Shortcuts <span style="opacity: 0.5;">(?)</span></h2>
<div class="shortcuts-list">
<div class="shortcut"><kbd>/</kbd> Search</div>
<div class="shortcut"><kbd>t</kbd> Toggle Tree/Graph</div>
<div class="shortcut"><kbd>s</kbd> Toggle sidebar</div>
<div class="shortcut"><kbd>f</kbd> Fit to screen</div>
<div class="shortcut"><kbd>r</kbd> Reset layout</div>
<div class="shortcut"><kbd>c</kbd> Toggle center mode</div>
<div class="shortcut"><kbd>e</kbd> Export PNG</div>
<div class="shortcut"><kbd>Esc</kbd> Clear selection</div>
</div>
</section>
</aside>
<footer class="footer" id="footer">
<div id="summary-stats"></div>
</footer>
</div>
<div id="help-modal" class="modal">
<div class="modal-content">
<h2>Keyboard Shortcuts</h2>
<table class="shortcuts-table">
<tr><td><kbd>/</kbd></td><td>Focus search</td></tr>
<tr><td><kbd>f</kbd></td><td>Fit graph to screen</td></tr>
<tr><td><kbd>r</kbd></td><td>Reset layout</td></tr>
<tr><td><kbd>c</kbd></td><td>Toggle center mode</td></tr>
<tr><td><kbd>t</kbd></td><td>Toggle Tree/Graph view</td></tr>
<tr><td><kbd>s</kbd></td><td>Toggle sidebar</td></tr>
<tr><td><kbd>e</kbd></td><td>Export as PNG</td></tr>
<tr><td><kbd>Esc</kbd></td><td>Clear selection</td></tr>
<tr><td><kbd>?</kbd></td><td>Toggle this help</td></tr>
</table>
<button onclick="toggleHelpModal()" class="btn">Close</button>
</div>
</div>
<div id="details-modal" class="details-modal hidden">
<div class="details-modal-backdrop"></div>
<div class="details-modal-content">
<div class="details-modal-header">
<h2 id="details-modal-title">Module Details</h2>
<button class="btn-close-modal" id="close-details-modal">×</button>
</div>
<div class="details-tabs">
<button class="tab active" data-tab="overview">Overview</button>
<button class="tab" data-tab="couplings">Couplings</button>
<button class="tab" data-tab="items">Items</button>
<button class="tab" data-tab="source">Source</button>
</div>
<div class="details-modal-body">
<div class="tab-content active" id="tab-overview"></div>
<div class="tab-content" id="tab-couplings"></div>
<div class="tab-content" id="tab-items"></div>
<div class="tab-content" id="tab-source"></div>
</div>
</div>
</div>
<script type="module" src="/js/main.js"></script>
<script>
function toggleHelpModal() {
const modal = document.getElementById('help-modal');
if (modal) modal.classList.toggle('visible');
}
</script>
</body>
</html>