-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
283 lines (271 loc) · 18.6 KB
/
index.html
File metadata and controls
283 lines (271 loc) · 18.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#1a1a1a">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="description" content="Advanced Python codebase visualization tool with real-time analysis, metrics dashboard, and intelligent insights">
<title>MilkFish Codebase Visualizer - Advanced Python Code Analysis</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%231a1a1a'/><path d='M50,20 L80,50 L50,80 L20,50 Z' fill='%23e83e8c'/><circle cx='50' cy='50' r='15' fill='%231a1a1a'/></svg>">
<link rel="stylesheet" href="css/styles.css">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
</head>
<body>
<header>
<div class="header-content">
<img src="logo.png" alt="MilkFish Logo" class="header-logo" onerror="this.style.display='none'">
<h1>MilkFish Codebase Visualizer</h1>
</div>
</header>
<main>
<div class="main-wrapper">
<div class="top-container">
<!-- Input Section -->
<div class="input-section">
<h2>Select Python Files</h2>
<div class="file-inputs">
<div class="file-input-container">
<input type="file" id="file-input" accept=".py" multiple aria-label="Select Python files">
<label for="file-input">
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zm-1 2l5 5h-5V4zM6 20V4h5v7h7v9H6z"/></svg>
<span>Select Files</span>
</label>
</div>
<div class="file-input-container">
<input type="file" id="directory-input" webkitdirectory directory multiple aria-label="Select directory containing Python files">
<label for="directory-input">
<svg class="icon" viewBox="0 0 24 24"><path d="M10 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-8l-2-2z"/></svg>
<span>Select Directory</span>
</label>
</div>
</div>
<!-- GitHub Repository Input -->
<div class="github-input">
<h3>Or Analyze GitHub Repository</h3>
<div class="github-input-container">
<input type="text" id="github-repo-url"
placeholder="https://github.com/username/repository"
autocomplete="off"
spellcheck="false">
<button id="github-fetch-btn">
<svg class="icon" viewBox="0 0 24 24"><path d="M11 2a9 9 0 1 0 5.7 16l4.3 4.3 1.4-1.4-4.3-4.3A9 9 0 0 0 11 2zm0 2a7 7 0 1 1 0 14 7 7 0 0 1 0-14z"/></svg>
<span>Clone & Analyze</span>
</button>
</div>
<div id="repo-info" class="repo-info" style="display: none;">
<div class="repo-header">
<h4 id="repo-name">Repository Name</h4>
<div class="repo-stats">
<span><svg class="icon icon-sm" viewBox="0 0 24 24"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg> <span id="repo-stars">0</span></span>
<span><svg class="icon icon-sm" viewBox="0 0 24 24"><path d="M6 3v6l3.5 3.5L6 16v5h3v-3.5L12.5 14l3.5 3.5V21h3v-5l-3.5-3.5L19 9V3h-3v3.5L12.5 10 9 6.5V3H6z"/></svg> <span id="repo-forks">0</span></span>
</div>
</div>
<p id="repo-description">Repository description</p>
</div>
</div>
<!-- Selection Controls -->
<div class="selection-controls">
<button id="clear-selection-btn" class="secondary-btn" disabled>
<svg class="icon" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6zm2 3h14l-1.5 13h-11L5 9zm4-5h6v2H9V4zm2 8v7h2v-7h-2zm-3 0v7h2v-7H8zm6 0v7h2v-7h-2z"/></svg>
<span>Clear Selection</span>
</button>
<div class="file-count">
<span id="python-file-count">0</span> Python files selected
(<span>0.00</span>MB of 15MB)
</div>
</div>
<!-- Action Controls -->
<div class="controls">
<button id="analyze-btn" disabled>
<svg class="icon" viewBox="0 0 24 24"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0L19.2 12l-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>
<span>Analyze Codebase</span>
</button>
<div id="loading-indicator" class="loading-indicator" style="display: none;">
<div class="spinner"></div>
<span id="loading-text">Loading repository...</span>
</div>
</div>
<!-- File List -->
<div id="file-list-container">
<h3>Selected Files:</h3>
<ul id="file-list">
<li class="empty-message">No Python files selected</li>
</ul>
</div>
</div>
<!-- Visualization Section -->
<div class="visualization-section">
<h2>Codebase Visualization</h2>
<div class="visualization-controls">
<div class="buttons">
<button id="zoom-in" title="Zoom In (+ key)" aria-label="Zoom in"><svg class="icon" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg></button>
<button id="zoom-out" title="Zoom Out (- key)" aria-label="Zoom out"><svg class="icon" viewBox="0 0 24 24"><path d="M19 13H5v-2h14v2z"/></svg></button>
<button id="reset-view" title="Reset View (Ctrl+0)" aria-label="Reset view"><svg class="icon" viewBox="0 0 24 24"><path d="M17.65 6.35A7.96 7.96 0 0 0 12 4a8 8 0 1 0 8 8h-2a6 6 0 1 1-1.76-4.24L14 10h7V3l-3.35 3.35z"/></svg></button>
<button id="fullscreen-btn" class="fullscreen-btn" title="Toggle Fullscreen (F key)" aria-label="Toggle fullscreen"><svg class="icon" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg></button>
</div>
<div class="export-controls">
<button id="export-json" title="Export as JSON" aria-label="Export as JSON">
<span>{ }</span>
</button>
<button id="export-svg" title="Export as SVG" aria-label="Export as SVG">
<span>SVG</span>
</button>
<button id="export-png" title="Export as PNG" aria-label="Export as PNG">
<span>PNG</span>
</button>
</div>
</div>
<div id="visualization">
<div class="viz-empty-state" id="viz-empty-state">
<div class="empty-icon"><svg width="64" height="64" viewBox="0 0 24 24" fill="var(--magenta-primary)"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" opacity="0.3"/><circle cx="8" cy="10" r="1.5" opacity="0.6"/><circle cx="12" cy="8" r="1.5" opacity="0.6"/><circle cx="16" cy="10" r="1.5" opacity="0.6"/><circle cx="10" cy="14" r="1" opacity="0.4"/><circle cx="14" cy="14" r="1" opacity="0.4"/><line x1="8" y1="10" x2="12" y2="8" stroke="var(--magenta-primary)" stroke-width="0.5" opacity="0.3"/><line x1="12" y1="8" x2="16" y2="10" stroke="var(--magenta-primary)" stroke-width="0.5" opacity="0.3"/><line x1="10" y1="14" x2="14" y2="14" stroke="var(--magenta-primary)" stroke-width="0.5" opacity="0.3"/><line x1="8" y1="10" x2="10" y2="14" stroke="var(--magenta-primary)" stroke-width="0.5" opacity="0.3"/><line x1="16" y1="10" x2="14" y2="14" stroke="var(--magenta-primary)" stroke-width="0.5" opacity="0.3"/></svg></div>
<h3>No Visualization Yet</h3>
<p>Upload Python files or clone a GitHub repository to visualize your codebase.</p>
<div class="steps">
<div class="step"><span class="step-num">1</span> Select files, a directory, or paste a GitHub URL</div>
<div class="step"><span class="step-num">2</span> Click "Analyze Codebase" to generate the graph</div>
<div class="step"><span class="step-num">3</span> Explore nodes, connections, and metrics</div>
</div>
<p id="pyodide-status" style="margin-top: 16px; font-size: 0.8rem; opacity: 0.6; transition: opacity 1s;">Initializing...</p>
</div>
</div>
<!-- Graph Legend (click to filter) -->
<div class="graph-legend" id="graph-legend">
<button class="legend-toggle-all" id="legend-toggle-all" title="Toggle all">All</button>
<div class="legend-item active" data-type="file">
<div class="legend-color file-color"></div>
<span>File</span>
</div>
<div class="legend-item active" data-type="class">
<div class="legend-color class-color"></div>
<span>Class</span>
</div>
<div class="legend-item active" data-type="function">
<div class="legend-color function-color"></div>
<span>Function</span>
</div>
<div class="legend-item active" data-type="method">
<div class="legend-color method-color"></div>
<span>Method</span>
</div>
<div class="legend-item active" data-type="import">
<div class="legend-color import-color"></div>
<span>Import</span>
</div>
<div class="legend-item active" data-type="module">
<div class="legend-color module-color"></div>
<span>Module</span>
</div>
<div class="legend-item active" data-type="todo">
<div class="legend-color todo-color"></div>
<span>TODO</span>
</div>
</div>
</div>
</div>
<!-- Details Panel -->
<div class="details-panel">
<div class="details-panel-inner">
<h2>Details</h2>
<div id="node-details">
<p>Click on a node to see details</p>
</div>
</div>
</div>
</div>
</main>
<!-- Subdirectory Selection Modal -->
<div id="subdirectory-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="subdirectory-modal-title">
<div class="modal-content">
<div class="modal-header">
<h3 id="subdirectory-modal-title">Select Subdirectories to Include</h3>
<span class="close-modal">×</span>
</div>
<div class="modal-body">
<div class="error-message" style="display: none;"></div>
<p>Your selected directory contains multiple subdirectories. Please select which ones to include in the analysis:</p>
<div id="subdirectory-list" class="checkbox-list">
<!-- Subdirectories will be listed here dynamically -->
</div>
<div class="common-ignore-section">
<h4>Quick Actions:</h4>
<button id="ignore-common-btn" class="secondary-btn">
<svg class="icon" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8 0-1.85.63-3.55 1.69-4.9L16.9 18.31A7.9 7.9 0 0 1 12 20zm6.31-3.1L7.1 5.69A7.9 7.9 0 0 1 12 4c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9z"/></svg>
<span>Ignore Common Directories</span>
</button>
<p class="hint-text">(.venv, node_modules, __pycache__, .git, tests, etc.)</p>
</div>
</div>
<div class="modal-footer">
<div id="file-count-info">
<span id="selected-file-count">0</span> Python files selected
</div>
<div class="modal-actions">
<button id="cancel-subdirectory-btn" class="secondary-btn">Cancel</button>
<button id="confirm-subdirectory-btn">Confirm Selection</button>
</div>
</div>
</div>
</div>
<footer>
<div class="footer-content">
<p>MilkFish Codebase Visualizer - Advanced Python Code Analysis Tool</p>
<div class="personal-branding">
<p>Developed by <strong>Matthew Haskins</strong></p>
<div class="social-links">
<a href="https://maloskins.com" target="_blank" rel="noopener" title="Portfolio">
<svg class="icon" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1a2 2 0 0 0 2 2v1.93zm6.9-2.54A2 2 0 0 0 16 16h-1v-3a1 1 0 0 0-1-1H8v-2h2a1 1 0 0 0 1-1V7h2a2 2 0 0 0 2-2v-.41A8 8 0 0 1 20 12c0 2.08-.8 3.97-2.1 5.39z"/></svg>
<span>Portfolio</span>
</a>
<a href="https://github.com/MaLoskins?tab=repositories" target="_blank" rel="noopener" title="GitHub">
<svg class="icon" viewBox="0 0 24 24"><path d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34-.46-1.16-1.11-1.47-1.11-1.47-.91-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.87 1.52 2.34 1.07 2.91.83.09-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.92 0-1.11.38-2 1.03-2.71-.1-.25-.45-1.29.1-2.64 0 0 .84-.27 2.75 1.02.79-.22 1.65-.33 2.5-.33.85 0 1.71.11 2.5.33 1.91-1.29 2.75-1.02 2.75-1.02.55 1.35.2 2.39.1 2.64.65.71 1.03 1.6 1.03 2.71 0 3.82-2.34 4.66-4.57 4.91.36.31.69.92.69 1.85V21c0 .27.16.59.67.5A10 10 0 0 0 12 2z"/></svg>
<span>GitHub</span>
</a>
<a href="https://www.linkedin.com/in/matthew-haskins-2875a41ab/" target="_blank" rel="noopener" title="LinkedIn">
<svg class="icon" viewBox="0 0 24 24"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/></svg>
<span>LinkedIn</span>
</a>
<a href="https://github.com/MaLoskins/python-codebase-visualizer" target="_blank" rel="noopener" title="Repository">
<svg class="icon" viewBox="0 0 24 24"><path d="M4 6H2v14a2 2 0 0 0 2 2h14v-2H4V6zm16-4H8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-1 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z"/></svg>
<span>Source</span>
</a>
</div>
</div>
</div>
</footer>
<!-- Load Scripts -->
<script src="js/parser.js"></script>
<script src="js/graph.js"></script>
<script src="js/github.js"></script>
<script src="js/export.js"></script>
<script src="js/main.js"></script>
<!-- Preload Pyodide for faster analysis -->
<script>
// Preload Pyodide in the background to improve user experience
document.addEventListener('DOMContentLoaded', function() {
if (typeof loadPyodide === 'function' && !window.pyodideLoaded) {
console.log("Preloading Pyodide for enhanced Python analysis...");
// Show loading status in the empty state
const statusEl = document.getElementById('pyodide-status');
if (statusEl) statusEl.textContent = 'Loading Python engine...';
try {
loadPyodide().then(pyodide => {
console.log("Pyodide preloaded successfully - Advanced AST parsing ready");
window.pyodideLoaded = true;
window.pyodideInstance = pyodide;
if (statusEl) statusEl.textContent = 'Python engine ready';
setTimeout(() => { if (statusEl) statusEl.style.opacity = '0'; }, 2000);
}).catch(error => {
console.error("Failed to preload Pyodide:", error);
if (statusEl) statusEl.textContent = 'Using fallback parser';
});
} catch (error) {
console.error("Error preloading Pyodide:", error);
}
}
});
</script>
</body>
</html>