gitmaps 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -118
- package/app/[...slug]/page.client.tsx +1 -0
- package/app/[...slug]/page.tsx +6 -0
- package/app/analytics.db +0 -0
- package/app/api/analytics/route.ts +64 -0
- package/app/api/auth/positions/route.ts +95 -33
- package/app/api/build-info/route.ts +19 -0
- package/app/api/chat/route.ts +13 -2
- package/app/api/og-image/route.ts +14 -0
- package/app/api/repo/file-content/route.ts +73 -20
- package/app/api/repo/load/route.test.ts +62 -0
- package/app/api/repo/load/route.ts +41 -1
- package/app/api/repo/pdf-thumb/route.ts +127 -0
- package/app/api/repo/resolve-slug/route.ts +51 -0
- package/app/api/repo/tree/route.ts +188 -104
- package/app/api/version/route.ts +26 -0
- package/app/globals.css +5706 -4938
- package/app/layout.tsx +1279 -490
- package/app/lib/auto-arrange.test.ts +158 -0
- package/app/lib/auto-arrange.ts +147 -0
- package/app/lib/canvas-export.ts +358 -358
- package/app/lib/canvas.ts +625 -564
- package/app/lib/cards.tsx +1361 -916
- package/app/lib/chat.tsx +65 -9
- package/app/lib/code-editor.ts +86 -2
- package/app/lib/context.test.ts +32 -0
- package/app/lib/context.ts +19 -3
- package/app/lib/cursor-sharing.ts +34 -0
- package/app/lib/events.tsx +71 -93
- package/app/lib/export-canvas.ts +287 -0
- package/app/lib/file-card-plugin.ts +148 -148
- package/app/lib/file-modal.tsx +49 -0
- package/app/lib/file-preview.ts +486 -427
- package/app/lib/github-import.test.ts +424 -0
- package/app/lib/initial-route-hydration.test.ts +283 -0
- package/app/lib/initial-route-hydration.ts +202 -0
- package/app/lib/landing-reset.test.ts +99 -0
- package/app/lib/landing-reset.ts +106 -0
- package/app/lib/landing-shell.test.ts +75 -0
- package/app/lib/large-repo-optimization.ts +37 -0
- package/app/lib/layout-snapshots.ts +320 -0
- package/app/lib/loading.test.ts +69 -0
- package/app/lib/loading.tsx +160 -45
- package/app/lib/mount-cleanup.test.ts +52 -0
- package/app/lib/mount-cleanup.ts +34 -0
- package/app/lib/mount-init.test.ts +123 -0
- package/app/lib/mount-init.ts +107 -0
- package/app/lib/mount-lifecycle.test.ts +39 -0
- package/app/lib/mount-lifecycle.ts +12 -0
- package/app/lib/mount-route-wiring.test.ts +87 -0
- package/app/lib/mount-route-wiring.ts +84 -0
- package/app/lib/multi-repo.ts +14 -0
- package/app/lib/onboarding-tutorial.ts +278 -0
- package/app/lib/positions.ts +190 -121
- package/app/lib/recent-commits.test.ts +947 -0
- package/app/lib/recent-commits.ts +227 -0
- package/app/lib/repo-handoff.test.ts +23 -0
- package/app/lib/repo-handoff.ts +16 -0
- package/app/lib/repo-progressive.ts +119 -0
- package/app/lib/repo-select.test.ts +61 -0
- package/app/lib/repo-select.ts +74 -0
- package/app/lib/repo.tsx +1383 -987
- package/app/lib/role.ts +228 -0
- package/app/lib/route-catchall.test.ts +27 -0
- package/app/lib/route-repo-entry.test.ts +95 -0
- package/app/lib/route-repo-entry.ts +36 -0
- package/app/lib/router-contract.test.ts +22 -0
- package/app/lib/router-contract.ts +19 -0
- package/app/lib/shared-layout.test.ts +86 -0
- package/app/lib/shared-layout.ts +82 -0
- package/app/lib/status-bar.test.ts +118 -0
- package/app/lib/status-bar.ts +365 -128
- package/app/lib/sync-controls.test.ts +43 -0
- package/app/lib/sync-controls.tsx +303 -0
- package/app/lib/test-dom.ts +145 -0
- package/app/lib/test-fixtures/router-contract/[...slug]/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/api/health/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/api/version/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/galaxy-canvas/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/page.tsx +3 -0
- package/app/lib/transclusion-smoke.test.ts +163 -0
- package/app/lib/tutorial.ts +301 -0
- package/app/lib/version.ts +93 -0
- package/app/lib/viewport-culling.ts +740 -735
- package/app/lib/virtual-files.ts +456 -0
- package/app/lib/webgl-text.ts +189 -0
- package/app/lib/{galaxydraw-bridge.ts → xydraw-bridge.ts} +485 -482
- package/app/lib/{galaxydraw.test.ts → xydraw.test.ts} +228 -229
- package/app/og-image.png +0 -0
- package/app/page.client.tsx +70 -269
- package/app/page.tsx +15 -16
- package/app/state/machine.js +13 -0
- package/package.json +84 -75
- package/server.ts +10 -0
- package/app/[owner]/[repo]/page.tsx +0 -6
- package/app/[slug]/page.tsx +0 -6
- package/packages/galaxydraw/README.md +0 -296
- package/packages/galaxydraw/banner.png +0 -0
- package/packages/galaxydraw/demo/build-static.ts +0 -100
- package/packages/galaxydraw/demo/client.ts +0 -154
- package/packages/galaxydraw/demo/dist/client.js +0 -8
- package/packages/galaxydraw/demo/index.html +0 -256
- package/packages/galaxydraw/demo/server.ts +0 -96
- package/packages/galaxydraw/dist/index.js +0 -984
- package/packages/galaxydraw/dist/index.js.map +0 -16
- package/packages/galaxydraw/node_modules/.bin/tsc.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsc.exe +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.exe +0 -0
- package/packages/galaxydraw/package.json +0 -49
- package/packages/galaxydraw/perf.test.ts +0 -284
- package/packages/galaxydraw/src/core/cards.ts +0 -435
- package/packages/galaxydraw/src/core/engine.ts +0 -339
- package/packages/galaxydraw/src/core/events.ts +0 -81
- package/packages/galaxydraw/src/core/layout.ts +0 -136
- package/packages/galaxydraw/src/core/minimap.ts +0 -216
- package/packages/galaxydraw/src/core/state.ts +0 -177
- package/packages/galaxydraw/src/core/viewport.ts +0 -106
- package/packages/galaxydraw/src/galaxydraw.css +0 -166
- package/packages/galaxydraw/src/index.ts +0 -40
- package/packages/galaxydraw/tsconfig.json +0 -30
package/app/layout.tsx
CHANGED
|
@@ -5,517 +5,1306 @@
|
|
|
5
5
|
* All interactivity is in page.client.tsx.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import path from 'path';
|
|
9
|
+
|
|
10
|
+
function getBuildInfo() {
|
|
11
|
+
const repoRoot = path.resolve(import.meta.dir, '..');
|
|
12
|
+
const commitProc = Bun.spawnSync(['git', 'rev-parse', '--short', 'HEAD'], {
|
|
13
|
+
cwd: repoRoot,
|
|
14
|
+
stdout: 'pipe',
|
|
15
|
+
stderr: 'pipe',
|
|
16
|
+
});
|
|
17
|
+
const dateProc = Bun.spawnSync(['git', 'log', '-1', '--format=%cs'], {
|
|
18
|
+
cwd: repoRoot,
|
|
19
|
+
stdout: 'pipe',
|
|
20
|
+
stderr: 'pipe',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
commit: commitProc.exitCode === 0 ? commitProc.stdout.toString().trim() : 'unknown',
|
|
25
|
+
date: dateProc.exitCode === 0 ? dateProc.stdout.toString().trim() : '',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
8
29
|
export default function RootLayout({ children }: { children: any }) {
|
|
9
|
-
|
|
10
|
-
<html lang="en">
|
|
11
|
-
<head>
|
|
12
|
-
<meta charSet="UTF-8" />
|
|
13
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
14
|
-
<meta name="description" content="Transcend the file tree. GitMaps renders knowledge on an infinite canvas — with layers, time-travel, and a minimap to never lose context." />
|
|
15
|
-
<title>GitMaps — Spatial Code Explorer</title>
|
|
16
|
-
<link rel="icon" type="image/png" href="/api/pwa-icon" />
|
|
17
|
-
<link rel="manifest" href="/api/manifest.json" />
|
|
18
|
-
<meta name="theme-color" content="#7c3aed" />
|
|
19
|
-
<link
|
|
20
|
-
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
21
|
-
rel="stylesheet"
|
|
22
|
-
/>
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
<div id="app">
|
|
26
|
-
<nav className="sidebar">
|
|
27
|
-
<div className="sidebar-header">
|
|
28
|
-
<div className="logo">
|
|
29
|
-
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="2">
|
|
30
|
-
<circle cx="12" cy="12" r="3" />
|
|
31
|
-
<circle cx="12" cy="4" r="1.5" />
|
|
32
|
-
<circle cx="12" cy="20" r="1.5" />
|
|
33
|
-
<circle cx="4" cy="8" r="1.5" />
|
|
34
|
-
<circle cx="20" cy="8" r="1.5" />
|
|
35
|
-
<circle cx="4" cy="16" r="1.5" />
|
|
36
|
-
<circle cx="20" cy="16" r="1.5" />
|
|
37
|
-
<path d="M12 7v2M12 15v2M8.5 9.5l-2.5-1M15.5 9.5l2.5-1M8.5 14.5l-2.5 1M15.5 14.5l2.5 1" />
|
|
38
|
-
</svg>
|
|
39
|
-
<span>GitMaps</span>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
30
|
+
const build = getBuildInfo();
|
|
42
31
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
return (
|
|
33
|
+
<html lang="en">
|
|
34
|
+
<head>
|
|
35
|
+
<meta charSet="UTF-8" />
|
|
36
|
+
<meta
|
|
37
|
+
name="viewport"
|
|
38
|
+
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
|
39
|
+
/>
|
|
40
|
+
<meta
|
|
41
|
+
name="description"
|
|
42
|
+
content="Transcend the file tree. GitMaps renders knowledge on an infinite canvas — with layers, time-travel, and a minimap to never lose context."
|
|
43
|
+
/>
|
|
44
|
+
<meta property="og:title" content="GitMaps — Spatial Code Explorer" />
|
|
45
|
+
<meta
|
|
46
|
+
property="og:description"
|
|
47
|
+
content="Every file in your repo. One infinite canvas. Layers, git time-travel, inline diffs."
|
|
48
|
+
/>
|
|
49
|
+
<meta property="og:image" content="https://gitmaps.xyz/api/og-image" />
|
|
50
|
+
<meta property="og:url" content="https://gitmaps.xyz" />
|
|
51
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
52
|
+
<meta name="twitter:image" content="https://gitmaps.xyz/api/og-image" />
|
|
53
|
+
<title>GitMaps — Spatial Code Explorer</title>
|
|
54
|
+
<link rel="icon" type="image/png" href="/api/pwa-icon" />
|
|
55
|
+
<link rel="manifest" href="/api/manifest.json" />
|
|
56
|
+
<meta name="theme-color" content="#7c3aed" />
|
|
57
|
+
<script
|
|
58
|
+
dangerouslySetInnerHTML={{
|
|
59
|
+
__html: `window.__GITMAPS_BUILD__ = ${JSON.stringify(build)};`,
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
<link
|
|
63
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
|
|
64
|
+
rel="stylesheet"
|
|
65
|
+
/>
|
|
66
|
+
</head>
|
|
67
|
+
<body>
|
|
68
|
+
{/* Mobile gate — canvas needs a real screen */}
|
|
69
|
+
<div
|
|
70
|
+
id="mobileGate"
|
|
71
|
+
style={{
|
|
72
|
+
display: "none",
|
|
73
|
+
position: "fixed",
|
|
74
|
+
inset: 0,
|
|
75
|
+
zIndex: 99999,
|
|
76
|
+
background: "#0a0a1a",
|
|
77
|
+
color: "#e2e8f0",
|
|
78
|
+
flexDirection: "column",
|
|
79
|
+
alignItems: "center",
|
|
80
|
+
justifyContent: "center",
|
|
81
|
+
padding: "2rem",
|
|
82
|
+
textAlign: "center",
|
|
83
|
+
fontFamily: "Inter, sans-serif",
|
|
84
|
+
gap: "1rem",
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<div style={{ fontSize: "3rem" }}>🗺️</div>
|
|
88
|
+
<h2 style={{ margin: 0, fontSize: "1.5rem", fontWeight: 600 }}>
|
|
89
|
+
GitMaps needs a bigger screen
|
|
90
|
+
</h2>
|
|
91
|
+
<p
|
|
92
|
+
style={{
|
|
93
|
+
margin: 0,
|
|
94
|
+
color: "#94a3b8",
|
|
95
|
+
maxWidth: "320px",
|
|
96
|
+
lineHeight: 1.6,
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
The infinite canvas works best on desktop or tablet. Come back on a
|
|
100
|
+
larger screen to explore your repos spatially.
|
|
101
|
+
</p>
|
|
102
|
+
<a
|
|
103
|
+
href="https://gitmaps.xyz"
|
|
104
|
+
style={{
|
|
105
|
+
marginTop: "0.5rem",
|
|
106
|
+
padding: "0.75rem 1.5rem",
|
|
107
|
+
background: "#7c3aed",
|
|
108
|
+
color: "white",
|
|
109
|
+
borderRadius: "8px",
|
|
110
|
+
textDecoration: "none",
|
|
111
|
+
fontWeight: 500,
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
Learn more
|
|
115
|
+
</a>
|
|
116
|
+
<button
|
|
117
|
+
id="mobileGateDismiss"
|
|
118
|
+
style={{
|
|
119
|
+
background: "none",
|
|
120
|
+
border: "1px solid #334155",
|
|
121
|
+
color: "#94a3b8",
|
|
122
|
+
padding: "0.5rem 1rem",
|
|
123
|
+
borderRadius: "6px",
|
|
124
|
+
cursor: "pointer",
|
|
125
|
+
fontSize: "0.85rem",
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
Continue anyway →
|
|
129
|
+
</button>
|
|
130
|
+
</div>
|
|
131
|
+
<script
|
|
132
|
+
dangerouslySetInnerHTML={{
|
|
133
|
+
__html: `
|
|
134
|
+
(function() {
|
|
135
|
+
window.__GITMAPS_BUILD_COMMIT__ = ${JSON.stringify(build.commit)};
|
|
136
|
+
window.__GITMAPS_BUILD_DATE__ = ${JSON.stringify(build.date)};
|
|
137
|
+
if (window.innerWidth < 768) {
|
|
138
|
+
var g = document.getElementById('mobileGate');
|
|
139
|
+
if (g) { g.style.display = 'flex'; }
|
|
140
|
+
var d = document.getElementById('mobileGateDismiss');
|
|
141
|
+
if (d) d.onclick = function() { g.style.display = 'none'; };
|
|
142
|
+
}
|
|
143
|
+
})();
|
|
144
|
+
`,
|
|
145
|
+
}}
|
|
146
|
+
/>
|
|
147
|
+
<div id="app">
|
|
148
|
+
<nav className="sidebar">
|
|
149
|
+
<div className="sidebar-header">
|
|
150
|
+
<div className="logo">
|
|
151
|
+
<svg
|
|
152
|
+
viewBox="0 0 24 24"
|
|
153
|
+
width="22"
|
|
154
|
+
height="22"
|
|
155
|
+
fill="none"
|
|
156
|
+
stroke="currentColor"
|
|
157
|
+
strokeWidth="2"
|
|
158
|
+
>
|
|
159
|
+
<circle cx="12" cy="12" r="3" />
|
|
160
|
+
<circle cx="12" cy="4" r="1.5" />
|
|
161
|
+
<circle cx="12" cy="20" r="1.5" />
|
|
162
|
+
<circle cx="4" cy="8" r="1.5" />
|
|
163
|
+
<circle cx="20" cy="8" r="1.5" />
|
|
164
|
+
<circle cx="4" cy="16" r="1.5" />
|
|
165
|
+
<circle cx="20" cy="16" r="1.5" />
|
|
166
|
+
<path d="M12 7v2M12 15v2M8.5 9.5l-2.5-1M15.5 9.5l2.5-1M8.5 14.5l-2.5 1M15.5 14.5l2.5 1" />
|
|
167
|
+
</svg>
|
|
168
|
+
<span>GitMaps</span>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
50
171
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
172
|
+
<div className="repo-selector">
|
|
173
|
+
<select id="repoSelect" className="repo-dropdown">
|
|
174
|
+
<option value="">Select a repository...</option>
|
|
175
|
+
</select>
|
|
176
|
+
<input type="text" id="repoPath" style={{ display: "none" }} />
|
|
177
|
+
<input
|
|
178
|
+
type="file"
|
|
179
|
+
id="folderPickerInput"
|
|
180
|
+
style={{ display: "none" }}
|
|
181
|
+
/>
|
|
182
|
+
<div
|
|
183
|
+
className="clone-status"
|
|
184
|
+
id="cloneStatus"
|
|
185
|
+
style={{ display: "none" }}
|
|
186
|
+
></div>
|
|
58
187
|
|
|
59
|
-
|
|
188
|
+
<button
|
|
189
|
+
id="githubImportBtn"
|
|
190
|
+
className="github-import-btn"
|
|
191
|
+
title="Import from GitHub"
|
|
192
|
+
>
|
|
193
|
+
<svg
|
|
194
|
+
viewBox="0 0 24 24"
|
|
195
|
+
width="14"
|
|
196
|
+
height="14"
|
|
197
|
+
fill="currentColor"
|
|
198
|
+
>
|
|
199
|
+
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
|
200
|
+
</svg>
|
|
201
|
+
Import from GitHub
|
|
202
|
+
</button>
|
|
203
|
+
</div>
|
|
60
204
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
<path d="M12 6v6l4 2" />
|
|
71
|
-
</svg>
|
|
72
|
-
<p>Load a repository</p>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
205
|
+
<div
|
|
206
|
+
id="repoTabs"
|
|
207
|
+
style={{
|
|
208
|
+
display: "none",
|
|
209
|
+
gap: "6px",
|
|
210
|
+
padding: "0 12px 8px",
|
|
211
|
+
flexWrap: "wrap",
|
|
212
|
+
}}
|
|
213
|
+
></div>
|
|
76
214
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
215
|
+
<div className="commit-timeline" id="commitTimeline">
|
|
216
|
+
<div className="section-header">
|
|
217
|
+
<span className="section-title">History</span>
|
|
218
|
+
<span className="badge" id="commitCount">
|
|
219
|
+
0
|
|
220
|
+
</span>
|
|
221
|
+
<button
|
|
222
|
+
id="pullBtn"
|
|
223
|
+
className="btn-ghost btn-xs"
|
|
224
|
+
title="Pull latest commits from remote"
|
|
225
|
+
style={{ marginLeft: "auto" }}
|
|
226
|
+
>
|
|
227
|
+
<svg
|
|
228
|
+
viewBox="0 0 24 24"
|
|
229
|
+
width="12"
|
|
230
|
+
height="12"
|
|
231
|
+
fill="none"
|
|
232
|
+
stroke="currentColor"
|
|
233
|
+
strokeWidth="2.5"
|
|
234
|
+
>
|
|
235
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
236
|
+
<polyline points="7 10 12 15 17 10" />
|
|
237
|
+
<line x1="12" y1="15" x2="12" y2="3" />
|
|
238
|
+
</svg>
|
|
239
|
+
Pull
|
|
240
|
+
</button>
|
|
241
|
+
</div>
|
|
242
|
+
<div className="timeline-container" id="timelineContainer">
|
|
243
|
+
<div className="empty-state">
|
|
244
|
+
<svg
|
|
245
|
+
viewBox="0 0 24 24"
|
|
246
|
+
width="24"
|
|
247
|
+
height="24"
|
|
248
|
+
fill="none"
|
|
249
|
+
stroke="currentColor"
|
|
250
|
+
strokeWidth="1.5"
|
|
251
|
+
opacity="0.3"
|
|
252
|
+
>
|
|
253
|
+
<circle cx="12" cy="12" r="10" />
|
|
254
|
+
<path d="M12 6v6l4 2" />
|
|
255
|
+
</svg>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
97
259
|
|
|
98
|
-
<div className="hotkey-toggle-wrapper">
|
|
99
|
-
<button id="hotkeyToggle" className="btn-ghost hotkey-toggle" title="Keyboard shortcuts">
|
|
100
|
-
<span>?</span>
|
|
101
|
-
</button>
|
|
102
|
-
<div className="hotkey-popup" id="hotkeyPopup">
|
|
103
|
-
<div className="hotkey-popup-title">Keyboard Shortcuts</div>
|
|
104
|
-
<div className="hotkey-grid">
|
|
105
|
-
<div className="hk"><kbd>Scroll</kbd> Zoom</div>
|
|
106
|
-
<div className="hk"><kbd>Space+Drag</kbd> Pan</div>
|
|
107
|
-
<div className="hk"><kbd>Click</kbd> Select</div>
|
|
108
|
-
<div className="hk"><kbd>Shift+Click</kbd> Multi-select</div>
|
|
109
|
-
<div className="hk"><kbd>Drag canvas</kbd> Rect select</div>
|
|
110
|
-
<div className="hk"><kbd>Drag card</kbd> Move</div>
|
|
111
|
-
<div className="hk"><kbd>Del</kbd> Hide file</div>
|
|
112
|
-
<div className="hk"><kbd>H</kbd> Arrange row</div>
|
|
113
|
-
<div className="hk"><kbd>V</kbd> Arrange column</div>
|
|
114
|
-
<div className="hk"><kbd>G</kbd> Arrange grid</div>
|
|
115
|
-
<div className="hk"><kbd>W</kbd> Fit to screen</div>
|
|
116
|
-
<div className="hk"><kbd>Ctrl+F</kbd> Search across files</div>
|
|
117
|
-
<div className="hk"><kbd>Ctrl+O</kbd> Find file</div>
|
|
118
|
-
<div className="hk"><kbd>Ctrl +/-</kbd> Text zoom</div>
|
|
119
|
-
<div className="hk"><kbd>Dbl-click</kbd> Open editor</div>
|
|
120
|
-
<div className="hk"><kbd>Alt+Click</kbd> Connect lines</div>
|
|
121
|
-
<div className="hk"><kbd>Arrow keys</kbd> Prev/next commit</div>
|
|
122
|
-
<div className="hk"><kbd>Ctrl+N</kbd> New file</div>
|
|
123
|
-
<div className="hk"><kbd>Ctrl+S</kbd> Save (in editor)</div>
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
</nav>
|
|
129
260
|
|
|
130
|
-
<main className="canvas-area">
|
|
131
|
-
<div className="canvas-header">
|
|
132
|
-
<div className="header-left">
|
|
133
|
-
<div className="current-commit" id="currentCommitInfo">
|
|
134
|
-
<span className="commit-hash-label">No commit selected</span>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
<div className="header-right">
|
|
138
|
-
<div className="arrange-toolbar" id="arrangeToolbar" style={{ display: 'none' }}>
|
|
139
|
-
<span className="arrange-label">Arrange:</span>
|
|
140
|
-
<button id="arrangeRow" className="btn-ghost btn-xs" title="Arrange in row (H)">
|
|
141
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
142
|
-
<rect x="2" y="7" width="5" height="10" rx="1" />
|
|
143
|
-
<rect x="9.5" y="7" width="5" height="10" rx="1" />
|
|
144
|
-
<rect x="17" y="7" width="5" height="10" rx="1" />
|
|
145
|
-
</svg>
|
|
146
|
-
</button>
|
|
147
|
-
<button id="arrangeCol" className="btn-ghost btn-xs" title="Arrange in column (V)">
|
|
148
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
149
|
-
<rect x="4" y="2" width="16" height="5" rx="1" />
|
|
150
|
-
<rect x="4" y="9.5" width="16" height="5" rx="1" />
|
|
151
|
-
<rect x="4" y="17" width="16" height="5" rx="1" />
|
|
152
|
-
</svg>
|
|
153
|
-
</button>
|
|
154
|
-
<button id="arrangeGrid" className="btn-ghost btn-xs" title="Arrange in grid (G)">
|
|
155
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
156
|
-
<rect x="3" y="3" width="7" height="7" rx="1" />
|
|
157
|
-
<rect x="14" y="3" width="7" height="7" rx="1" />
|
|
158
|
-
<rect x="3" y="14" width="7" height="7" rx="1" />
|
|
159
|
-
<rect x="14" y="14" width="7" height="7" rx="1" />
|
|
160
|
-
</svg>
|
|
161
|
-
</button>
|
|
162
|
-
<div style={{ width: 1, height: 16, background: 'var(--border)', margin: '0 4px' }}></div>
|
|
163
|
-
<button id="arrangeFit" className="btn-ghost btn-xs" title="Reset Size (W)">
|
|
164
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
165
|
-
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" />
|
|
166
|
-
</svg>
|
|
167
|
-
</button>
|
|
168
|
-
<button id="arrangeAI" className="btn-ghost btn-xs" title="Explain with AI...">
|
|
169
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
170
|
-
<path d="M11 2h2v4h-2zm0 16h2v4h-2zm11-7v2h-4v-2zm-16 0v2H2v-2zm12.3-5.3l1.4 1.4-2.8 2.8-1.4-1.4zm-9.8 9.8l1.4 1.4-2.8 2.8-1.4-1.4z" />
|
|
171
|
-
</svg>
|
|
172
|
-
</button>
|
|
173
|
-
</div>
|
|
174
|
-
<button id="toggleChangedFiles" className="btn-ghost btn-sm" title="Show changed files">
|
|
175
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
176
|
-
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
|
|
177
|
-
<polyline points="14 2 14 8 20 8" />
|
|
178
|
-
</svg>
|
|
179
|
-
<span id="fileCount">0</span>
|
|
180
|
-
</button>
|
|
181
|
-
<button id="showHidden" className="btn-ghost btn-sm" title="Show hidden files" style={{ display: 'none' }}>
|
|
182
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
183
|
-
<path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94" />
|
|
184
|
-
<path d="M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19" />
|
|
185
|
-
<line x1="1" y1="1" x2="23" y2="23" />
|
|
186
|
-
</svg>
|
|
187
|
-
<span id="hiddenCount">0</span>
|
|
188
|
-
</button>
|
|
189
|
-
<button id="toggleConnections" className="btn-ghost btn-sm" title="Toggle connection lines">
|
|
190
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
191
|
-
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
192
|
-
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
193
|
-
</svg>
|
|
194
|
-
</button>
|
|
195
|
-
<button id="dep-graph-btn" className="btn-ghost btn-sm" title="Toggle dependency graph (Ctrl+G)">
|
|
196
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
197
|
-
<circle cx="5" cy="5" r="2.5" /><circle cx="19" cy="5" r="2.5" />
|
|
198
|
-
<circle cx="12" cy="19" r="2.5" /><line x1="7" y1="6" x2="17" y2="6" />
|
|
199
|
-
<line x1="6" y1="7" x2="11" y2="17" /><line x1="18" y1="7" x2="13" y2="17" />
|
|
200
|
-
</svg>
|
|
201
|
-
</button>
|
|
202
|
-
<button id="toggleCanvasText" className="btn-ghost btn-sm" title="Toggle text rendering mode (DOM vs WebGL/Canvas)">
|
|
203
|
-
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
204
|
-
<polyline points="4 7 4 4 20 4 20 7" />
|
|
205
|
-
<line x1="9" y1="20" x2="15" y2="20" />
|
|
206
|
-
<line x1="12" y1="4" x2="12" y2="20" />
|
|
207
|
-
</svg>
|
|
208
|
-
</button>
|
|
209
|
-
<button id="autoDetectImports" className="btn-ghost btn-sm" title="Auto-detect import connections">
|
|
210
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
211
|
-
<path d="M9 3H5a2 2 0 00-2 2v4m6-6h10a2 2 0 012 2v4M9 3v18m0 0h10a2 2 0 002-2v-4M9 21H5a2 2 0 01-2-2v-4" />
|
|
212
|
-
<path d="M14 9l2 2-2 2" />
|
|
213
|
-
</svg>
|
|
214
|
-
</button>
|
|
215
|
-
<button id="shareLayout" className="btn-ghost btn-sm" title="Share Layout (Copy URL)">
|
|
216
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
217
|
-
<circle cx="18" cy="5" r="3" />
|
|
218
|
-
<circle cx="6" cy="12" r="3" />
|
|
219
|
-
<circle cx="18" cy="19" r="3" />
|
|
220
|
-
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
|
|
221
|
-
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
|
|
222
|
-
</svg>
|
|
223
|
-
</button>
|
|
224
|
-
<button id="helpOnboarding" className="btn-ghost btn-sm" title="Replay Tutorial (?)">
|
|
225
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
226
|
-
<circle cx="12" cy="12" r="10" />
|
|
227
|
-
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
|
|
228
|
-
<line x1="12" y1="17" x2="12.01" y2="17" />
|
|
229
|
-
</svg>
|
|
230
|
-
</button>
|
|
231
|
-
<button id="toggleControlMode" className="btn-ghost btn-sm" title="Toggle control mode: Simple (drag=pan) / Advanced (space+drag=pan)">
|
|
232
|
-
<svg id="controlModeIcon" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
233
|
-
{/* Default: Advanced (crosshair) — gets swapped by JS */}
|
|
234
|
-
<circle cx="12" cy="12" r="10" />
|
|
235
|
-
<line x1="12" y1="2" x2="12" y2="6" />
|
|
236
|
-
<line x1="12" y1="18" x2="12" y2="22" />
|
|
237
|
-
<line x1="2" y1="12" x2="6" y2="12" />
|
|
238
|
-
<line x1="18" y1="12" x2="22" y2="12" />
|
|
239
|
-
</svg>
|
|
240
|
-
</button>
|
|
241
|
-
<button id="openGlobalSearch" className="btn-ghost btn-sm" title="Search Files (Ctrl+F)">
|
|
242
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
243
|
-
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
244
|
-
</svg>
|
|
245
|
-
</button>
|
|
246
|
-
<button id="openBranchCompare" className="btn-ghost btn-sm" title="Compare Branches">
|
|
247
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
248
|
-
<circle cx="18" cy="18" r="3" /><circle cx="6" cy="6" r="3" />
|
|
249
|
-
<path d="M13 6h3a2 2 0 0 1 2 2v7" />
|
|
250
|
-
<path d="M6 9v12" />
|
|
251
|
-
</svg>
|
|
252
|
-
</button>
|
|
253
|
-
<button id="openSettings" className="btn-ghost btn-sm" title="Settings">
|
|
254
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
255
|
-
<circle cx="12" cy="12" r="3" />
|
|
256
|
-
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z" />
|
|
257
|
-
</svg>
|
|
258
|
-
</button>
|
|
259
|
-
<button id="toggleCanvasChat" className="btn-ghost btn-sm ai-chat-btn" title="AI Chat">
|
|
260
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
261
|
-
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z" />
|
|
262
|
-
</svg>
|
|
263
|
-
AI
|
|
264
|
-
</button>
|
|
265
|
-
</div>
|
|
266
|
-
</div>
|
|
267
261
|
|
|
268
|
-
|
|
262
|
+
<div className="sidebar-bottom">
|
|
263
|
+
<div className="canvas-controls">
|
|
264
|
+
<div className="control-row">
|
|
265
|
+
<button
|
|
266
|
+
id="resetView"
|
|
267
|
+
className="btn-ghost"
|
|
268
|
+
title="Reset View"
|
|
269
|
+
>
|
|
270
|
+
<svg
|
|
271
|
+
viewBox="0 0 24 24"
|
|
272
|
+
width="14"
|
|
273
|
+
height="14"
|
|
274
|
+
fill="none"
|
|
275
|
+
stroke="currentColor"
|
|
276
|
+
strokeWidth="2"
|
|
277
|
+
>
|
|
278
|
+
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
|
|
279
|
+
<path d="M3 3v5h5" />
|
|
280
|
+
</svg>
|
|
281
|
+
</button>
|
|
282
|
+
<button id="fitAll" className="btn-ghost" title="Fit All">
|
|
283
|
+
<svg
|
|
284
|
+
viewBox="0 0 24 24"
|
|
285
|
+
width="14"
|
|
286
|
+
height="14"
|
|
287
|
+
fill="none"
|
|
288
|
+
stroke="currentColor"
|
|
289
|
+
strokeWidth="2"
|
|
290
|
+
>
|
|
291
|
+
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" />
|
|
292
|
+
</svg>
|
|
293
|
+
</button>
|
|
294
|
+
<div className="zoom-inline">
|
|
295
|
+
<input
|
|
296
|
+
type="range"
|
|
297
|
+
id="zoomSlider"
|
|
298
|
+
min="0.1"
|
|
299
|
+
max="3"
|
|
300
|
+
step="0.1"
|
|
301
|
+
defaultValue="1"
|
|
302
|
+
/>
|
|
303
|
+
<span id="zoomValue">100%</span>
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
269
307
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
308
|
+
<div className="hotkey-toggle-wrapper">
|
|
309
|
+
<button
|
|
310
|
+
id="hotkeyToggle"
|
|
311
|
+
className="btn-ghost hotkey-toggle"
|
|
312
|
+
title="Keyboard shortcuts"
|
|
313
|
+
>
|
|
314
|
+
<span>?</span>
|
|
315
|
+
</button>
|
|
316
|
+
<div className="hotkey-popup" id="hotkeyPopup">
|
|
317
|
+
<div className="hotkey-popup-title">Keyboard Shortcuts</div>
|
|
318
|
+
<div className="hotkey-grid">
|
|
319
|
+
<div className="hk">
|
|
320
|
+
<kbd>Scroll</kbd> Zoom
|
|
321
|
+
</div>
|
|
322
|
+
<div className="hk">
|
|
323
|
+
<kbd>Space+Drag</kbd> Pan
|
|
324
|
+
</div>
|
|
325
|
+
<div className="hk">
|
|
326
|
+
<kbd>Click</kbd> Select
|
|
327
|
+
</div>
|
|
328
|
+
<div className="hk">
|
|
329
|
+
<kbd>Shift+Click</kbd> Multi-select
|
|
330
|
+
</div>
|
|
331
|
+
<div className="hk">
|
|
332
|
+
<kbd>Drag canvas</kbd> Rect select
|
|
333
|
+
</div>
|
|
334
|
+
<div className="hk">
|
|
335
|
+
<kbd>Drag card</kbd> Move
|
|
336
|
+
</div>
|
|
337
|
+
<div className="hk">
|
|
338
|
+
<kbd>Del</kbd> Hide file
|
|
339
|
+
</div>
|
|
340
|
+
<div className="hk">
|
|
341
|
+
<kbd>H</kbd> Arrange row
|
|
342
|
+
</div>
|
|
343
|
+
<div className="hk">
|
|
344
|
+
<kbd>V</kbd> Arrange column
|
|
345
|
+
</div>
|
|
346
|
+
<div className="hk">
|
|
347
|
+
<kbd>G</kbd> Arrange grid
|
|
348
|
+
</div>
|
|
349
|
+
<div className="hk">
|
|
350
|
+
<kbd>W</kbd> Fit to screen
|
|
351
|
+
</div>
|
|
352
|
+
<div className="hk">
|
|
353
|
+
<kbd>Ctrl+F</kbd> Search across files
|
|
354
|
+
</div>
|
|
355
|
+
<div className="hk">
|
|
356
|
+
<kbd>Ctrl+O</kbd> Find file
|
|
357
|
+
</div>
|
|
358
|
+
<div className="hk">
|
|
359
|
+
<kbd>Ctrl +/-</kbd> Text zoom
|
|
360
|
+
</div>
|
|
361
|
+
<div className="hk">
|
|
362
|
+
<kbd>Dbl-click</kbd> Open editor
|
|
363
|
+
</div>
|
|
364
|
+
<div className="hk">
|
|
365
|
+
<kbd>Alt+Click</kbd> Connect lines
|
|
366
|
+
</div>
|
|
367
|
+
<div className="hk">
|
|
368
|
+
<kbd>Arrow keys</kbd> Prev/next commit
|
|
369
|
+
</div>
|
|
370
|
+
<div className="hk">
|
|
371
|
+
<kbd>Ctrl+N</kbd> New file
|
|
372
|
+
</div>
|
|
373
|
+
<div className="hk">
|
|
374
|
+
<kbd>Ctrl+S</kbd> Save (in editor)
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
</nav>
|
|
283
381
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
382
|
+
<main className="canvas-area">
|
|
383
|
+
<div className="canvas-header">
|
|
384
|
+
<div className="header-left">
|
|
385
|
+
<div className="current-commit" id="currentCommitInfo">
|
|
386
|
+
<span className="commit-hash-label">No commit selected</span>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
<div className="header-right">
|
|
390
|
+
<div
|
|
391
|
+
className="arrange-toolbar"
|
|
392
|
+
id="arrangeToolbar"
|
|
393
|
+
style={{ display: "none" }}
|
|
394
|
+
>
|
|
395
|
+
<span className="arrange-label">Arrange:</span>
|
|
396
|
+
<button
|
|
397
|
+
id="arrangeRow"
|
|
398
|
+
className="btn-ghost btn-xs"
|
|
399
|
+
title="Arrange in row (H)"
|
|
400
|
+
>
|
|
401
|
+
<svg
|
|
402
|
+
viewBox="0 0 24 24"
|
|
403
|
+
width="14"
|
|
404
|
+
height="14"
|
|
405
|
+
fill="none"
|
|
406
|
+
stroke="currentColor"
|
|
407
|
+
strokeWidth="2"
|
|
408
|
+
>
|
|
409
|
+
<rect x="2" y="7" width="5" height="10" rx="1" />
|
|
410
|
+
<rect x="9.5" y="7" width="5" height="10" rx="1" />
|
|
411
|
+
<rect x="17" y="7" width="5" height="10" rx="1" />
|
|
412
|
+
</svg>
|
|
413
|
+
</button>
|
|
414
|
+
<button
|
|
415
|
+
id="arrangeCol"
|
|
416
|
+
className="btn-ghost btn-xs"
|
|
417
|
+
title="Arrange in column (V)"
|
|
418
|
+
>
|
|
419
|
+
<svg
|
|
420
|
+
viewBox="0 0 24 24"
|
|
421
|
+
width="14"
|
|
422
|
+
height="14"
|
|
423
|
+
fill="none"
|
|
424
|
+
stroke="currentColor"
|
|
425
|
+
strokeWidth="2"
|
|
426
|
+
>
|
|
427
|
+
<rect x="4" y="2" width="16" height="5" rx="1" />
|
|
428
|
+
<rect x="4" y="9.5" width="16" height="5" rx="1" />
|
|
429
|
+
<rect x="4" y="17" width="16" height="5" rx="1" />
|
|
430
|
+
</svg>
|
|
431
|
+
</button>
|
|
432
|
+
<button
|
|
433
|
+
id="arrangeGrid"
|
|
434
|
+
className="btn-ghost btn-xs"
|
|
435
|
+
title="Arrange in grid (G)"
|
|
436
|
+
>
|
|
437
|
+
<svg
|
|
438
|
+
viewBox="0 0 24 24"
|
|
439
|
+
width="14"
|
|
440
|
+
height="14"
|
|
441
|
+
fill="none"
|
|
442
|
+
stroke="currentColor"
|
|
443
|
+
strokeWidth="2"
|
|
444
|
+
>
|
|
445
|
+
<rect x="3" y="3" width="7" height="7" rx="1" />
|
|
446
|
+
<rect x="14" y="3" width="7" height="7" rx="1" />
|
|
447
|
+
<rect x="3" y="14" width="7" height="7" rx="1" />
|
|
448
|
+
<rect x="14" y="14" width="7" height="7" rx="1" />
|
|
449
|
+
</svg>
|
|
450
|
+
</button>
|
|
451
|
+
<div
|
|
452
|
+
style={{
|
|
453
|
+
width: 1,
|
|
454
|
+
height: 16,
|
|
455
|
+
background: "var(--border)",
|
|
456
|
+
margin: "0 4px",
|
|
457
|
+
}}
|
|
458
|
+
></div>
|
|
459
|
+
<button
|
|
460
|
+
id="arrangeFit"
|
|
461
|
+
className="btn-ghost btn-xs"
|
|
462
|
+
title="Reset Size (W)"
|
|
463
|
+
>
|
|
464
|
+
<svg
|
|
465
|
+
viewBox="0 0 24 24"
|
|
466
|
+
width="14"
|
|
467
|
+
height="14"
|
|
468
|
+
fill="none"
|
|
469
|
+
stroke="currentColor"
|
|
470
|
+
strokeWidth="2"
|
|
471
|
+
>
|
|
472
|
+
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" />
|
|
473
|
+
</svg>
|
|
474
|
+
</button>
|
|
475
|
+
<button
|
|
476
|
+
id="arrangeAI"
|
|
477
|
+
className="btn-ghost btn-xs"
|
|
478
|
+
title="Explain with AI..."
|
|
479
|
+
>
|
|
480
|
+
<svg
|
|
481
|
+
viewBox="0 0 24 24"
|
|
482
|
+
width="14"
|
|
483
|
+
height="14"
|
|
484
|
+
fill="currentColor"
|
|
485
|
+
>
|
|
486
|
+
<path d="M11 2h2v4h-2zm0 16h2v4h-2zm11-7v2h-4v-2zm-16 0v2H2v-2zm12.3-5.3l1.4 1.4-2.8 2.8-1.4-1.4zm-9.8 9.8l1.4 1.4-2.8 2.8-1.4-1.4z" />
|
|
487
|
+
</svg>
|
|
488
|
+
</button>
|
|
489
|
+
</div>
|
|
490
|
+
<button
|
|
491
|
+
id="toggleChangedFiles"
|
|
492
|
+
className="btn-ghost btn-sm"
|
|
493
|
+
title="Show changed files"
|
|
494
|
+
>
|
|
495
|
+
<svg
|
|
496
|
+
viewBox="0 0 24 24"
|
|
497
|
+
width="14"
|
|
498
|
+
height="14"
|
|
499
|
+
fill="none"
|
|
500
|
+
stroke="currentColor"
|
|
501
|
+
strokeWidth="2"
|
|
502
|
+
>
|
|
503
|
+
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
|
|
504
|
+
<polyline points="14 2 14 8 20 8" />
|
|
505
|
+
</svg>
|
|
506
|
+
<span id="fileCount">0</span>
|
|
507
|
+
</button>
|
|
508
|
+
<button
|
|
509
|
+
id="showHidden"
|
|
510
|
+
className="btn-ghost btn-sm"
|
|
511
|
+
title="Show hidden files"
|
|
512
|
+
style={{ display: "none" }}
|
|
513
|
+
>
|
|
514
|
+
<svg
|
|
515
|
+
viewBox="0 0 24 24"
|
|
516
|
+
width="14"
|
|
517
|
+
height="14"
|
|
518
|
+
fill="none"
|
|
519
|
+
stroke="currentColor"
|
|
520
|
+
strokeWidth="2"
|
|
521
|
+
>
|
|
522
|
+
<path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94" />
|
|
523
|
+
<path d="M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19" />
|
|
524
|
+
<line x1="1" y1="1" x2="23" y2="23" />
|
|
525
|
+
</svg>
|
|
526
|
+
<span id="hiddenCount">0</span>
|
|
527
|
+
</button>
|
|
528
|
+
<button
|
|
529
|
+
id="toggleConnections"
|
|
530
|
+
className="btn-ghost btn-sm"
|
|
531
|
+
title="Toggle connection lines"
|
|
532
|
+
>
|
|
533
|
+
<svg
|
|
534
|
+
viewBox="0 0 24 24"
|
|
535
|
+
width="14"
|
|
536
|
+
height="14"
|
|
537
|
+
fill="none"
|
|
538
|
+
stroke="currentColor"
|
|
539
|
+
strokeWidth="2"
|
|
540
|
+
>
|
|
541
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
542
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
543
|
+
</svg>
|
|
544
|
+
</button>
|
|
545
|
+
<button
|
|
546
|
+
id="dep-graph-btn"
|
|
547
|
+
className="btn-ghost btn-sm"
|
|
548
|
+
title="Toggle dependency graph (Ctrl+G)"
|
|
549
|
+
>
|
|
550
|
+
<svg
|
|
551
|
+
viewBox="0 0 24 24"
|
|
552
|
+
width="14"
|
|
553
|
+
height="14"
|
|
554
|
+
fill="none"
|
|
555
|
+
stroke="currentColor"
|
|
556
|
+
strokeWidth="2"
|
|
557
|
+
>
|
|
558
|
+
<circle cx="5" cy="5" r="2.5" />
|
|
559
|
+
<circle cx="19" cy="5" r="2.5" />
|
|
560
|
+
<circle cx="12" cy="19" r="2.5" />
|
|
561
|
+
<line x1="7" y1="6" x2="17" y2="6" />
|
|
562
|
+
<line x1="6" y1="7" x2="11" y2="17" />
|
|
563
|
+
<line x1="18" y1="7" x2="13" y2="17" />
|
|
564
|
+
</svg>
|
|
565
|
+
</button>
|
|
566
|
+
<button
|
|
567
|
+
id="toggleCanvasText"
|
|
568
|
+
className="btn-ghost btn-sm"
|
|
569
|
+
title="Toggle text rendering mode (DOM vs WebGL/Canvas)"
|
|
570
|
+
>
|
|
571
|
+
<svg
|
|
572
|
+
viewBox="0 0 24 24"
|
|
573
|
+
width="16"
|
|
574
|
+
height="16"
|
|
575
|
+
fill="none"
|
|
576
|
+
stroke="currentColor"
|
|
577
|
+
strokeWidth="2"
|
|
578
|
+
strokeLinecap="round"
|
|
579
|
+
strokeLinejoin="round"
|
|
580
|
+
>
|
|
581
|
+
<polyline points="4 7 4 4 20 4 20 7" />
|
|
582
|
+
<line x1="9" y1="20" x2="15" y2="20" />
|
|
583
|
+
<line x1="12" y1="4" x2="12" y2="20" />
|
|
584
|
+
</svg>
|
|
585
|
+
</button>
|
|
586
|
+
<button
|
|
587
|
+
id="autoDetectImports"
|
|
588
|
+
className="btn-ghost btn-sm"
|
|
589
|
+
title="Auto-detect import connections"
|
|
590
|
+
>
|
|
591
|
+
<svg
|
|
592
|
+
viewBox="0 0 24 24"
|
|
593
|
+
width="14"
|
|
594
|
+
height="14"
|
|
595
|
+
fill="none"
|
|
596
|
+
stroke="currentColor"
|
|
597
|
+
strokeWidth="2"
|
|
598
|
+
>
|
|
599
|
+
<path d="M9 3H5a2 2 0 00-2 2v4m6-6h10a2 2 0 012 2v4M9 3v18m0 0h10a2 2 0 002-2v-4M9 21H5a2 2 0 01-2-2v-4" />
|
|
600
|
+
<path d="M14 9l2 2-2 2" />
|
|
601
|
+
</svg>
|
|
602
|
+
</button>
|
|
603
|
+
<button
|
|
604
|
+
id="shareLayout"
|
|
605
|
+
className="btn-ghost btn-sm"
|
|
606
|
+
title="Share Layout (Copy URL)"
|
|
607
|
+
>
|
|
608
|
+
<svg
|
|
609
|
+
viewBox="0 0 24 24"
|
|
610
|
+
width="14"
|
|
611
|
+
height="14"
|
|
612
|
+
fill="none"
|
|
613
|
+
stroke="currentColor"
|
|
614
|
+
strokeWidth="2"
|
|
615
|
+
>
|
|
616
|
+
<circle cx="18" cy="5" r="3" />
|
|
617
|
+
<circle cx="6" cy="12" r="3" />
|
|
618
|
+
<circle cx="18" cy="19" r="3" />
|
|
619
|
+
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
|
|
620
|
+
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
|
|
621
|
+
</svg>
|
|
622
|
+
</button>
|
|
623
|
+
<button
|
|
624
|
+
id="toggleControlMode"
|
|
625
|
+
className="btn-ghost btn-sm"
|
|
626
|
+
title="Toggle control mode: Simple (drag=pan) / Advanced (space+drag=pan)"
|
|
627
|
+
>
|
|
628
|
+
<svg
|
|
629
|
+
id="controlModeIcon"
|
|
630
|
+
viewBox="0 0 24 24"
|
|
631
|
+
width="14"
|
|
632
|
+
height="14"
|
|
633
|
+
fill="none"
|
|
634
|
+
stroke="currentColor"
|
|
635
|
+
strokeWidth="2"
|
|
636
|
+
>
|
|
637
|
+
{/* Default: Advanced (crosshair) — gets swapped by JS */}
|
|
638
|
+
<circle cx="12" cy="12" r="10" />
|
|
639
|
+
<line x1="12" y1="2" x2="12" y2="6" />
|
|
640
|
+
<line x1="12" y1="18" x2="12" y2="22" />
|
|
641
|
+
<line x1="2" y1="12" x2="6" y2="12" />
|
|
642
|
+
<line x1="18" y1="12" x2="22" y2="12" />
|
|
643
|
+
</svg>
|
|
644
|
+
</button>
|
|
645
|
+
<button
|
|
646
|
+
id="openSnapshots"
|
|
647
|
+
className="btn-ghost btn-sm"
|
|
648
|
+
title="Layout Snapshots"
|
|
649
|
+
>
|
|
650
|
+
<svg
|
|
651
|
+
viewBox="0 0 24 24"
|
|
652
|
+
width="14"
|
|
653
|
+
height="14"
|
|
654
|
+
fill="none"
|
|
655
|
+
stroke="currentColor"
|
|
656
|
+
strokeWidth="2"
|
|
657
|
+
strokeLinecap="round"
|
|
658
|
+
strokeLinejoin="round"
|
|
659
|
+
>
|
|
660
|
+
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" />
|
|
661
|
+
<circle cx="12" cy="13" r="4" />
|
|
662
|
+
<path d="M15 8h.01" />
|
|
663
|
+
</svg>
|
|
664
|
+
</button>
|
|
665
|
+
<button
|
|
666
|
+
id="openGlobalSearch"
|
|
667
|
+
className="btn-ghost btn-sm"
|
|
668
|
+
title="Search Files (Ctrl+F)"
|
|
669
|
+
>
|
|
670
|
+
<svg
|
|
671
|
+
viewBox="0 0 24 24"
|
|
672
|
+
width="14"
|
|
673
|
+
height="14"
|
|
674
|
+
fill="none"
|
|
675
|
+
stroke="currentColor"
|
|
676
|
+
strokeWidth="2"
|
|
677
|
+
strokeLinecap="round"
|
|
678
|
+
strokeLinejoin="round"
|
|
679
|
+
>
|
|
680
|
+
<circle cx="11" cy="11" r="8" />
|
|
681
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
682
|
+
</svg>
|
|
683
|
+
</button>
|
|
684
|
+
<button
|
|
685
|
+
id="openBranchCompare"
|
|
686
|
+
className="btn-ghost btn-sm"
|
|
687
|
+
title="Compare Branches"
|
|
688
|
+
>
|
|
689
|
+
<svg
|
|
690
|
+
viewBox="0 0 24 24"
|
|
691
|
+
width="14"
|
|
692
|
+
height="14"
|
|
693
|
+
fill="none"
|
|
694
|
+
stroke="currentColor"
|
|
695
|
+
strokeWidth="2"
|
|
696
|
+
strokeLinecap="round"
|
|
697
|
+
strokeLinejoin="round"
|
|
698
|
+
>
|
|
699
|
+
<circle cx="18" cy="18" r="3" />
|
|
700
|
+
<circle cx="6" cy="6" r="3" />
|
|
701
|
+
<path d="M13 6h3a2 2 0 0 1 2 2v7" />
|
|
702
|
+
<path d="M6 9v12" />
|
|
703
|
+
</svg>
|
|
704
|
+
</button>
|
|
705
|
+
<button
|
|
706
|
+
id="openSettings"
|
|
707
|
+
className="btn-ghost btn-sm"
|
|
708
|
+
title="Settings"
|
|
709
|
+
>
|
|
710
|
+
<svg
|
|
711
|
+
viewBox="0 0 24 24"
|
|
712
|
+
width="14"
|
|
713
|
+
height="14"
|
|
714
|
+
fill="none"
|
|
715
|
+
stroke="currentColor"
|
|
716
|
+
strokeWidth="2"
|
|
717
|
+
strokeLinecap="round"
|
|
718
|
+
strokeLinejoin="round"
|
|
719
|
+
>
|
|
720
|
+
<circle cx="12" cy="12" r="3" />
|
|
721
|
+
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z" />
|
|
722
|
+
</svg>
|
|
723
|
+
</button>
|
|
724
|
+
<button
|
|
725
|
+
id="toggleCanvasChat"
|
|
726
|
+
className="btn-ghost btn-sm ai-chat-btn"
|
|
727
|
+
title="AI Chat"
|
|
728
|
+
>
|
|
729
|
+
<svg
|
|
730
|
+
viewBox="0 0 24 24"
|
|
731
|
+
width="14"
|
|
732
|
+
height="14"
|
|
733
|
+
fill="none"
|
|
734
|
+
stroke="currentColor"
|
|
735
|
+
strokeWidth="2"
|
|
736
|
+
>
|
|
737
|
+
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z" />
|
|
738
|
+
</svg>
|
|
739
|
+
AI
|
|
740
|
+
</button>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
302
743
|
|
|
744
|
+
{children}
|
|
303
745
|
|
|
746
|
+
{/* Changed Files Panel */}
|
|
747
|
+
<div
|
|
748
|
+
className="changed-files-panel"
|
|
749
|
+
id="changedFilesPanel"
|
|
750
|
+
style={{ display: "none" }}
|
|
751
|
+
>
|
|
752
|
+
<div className="panel-header">
|
|
753
|
+
<span className="panel-title">Changed Files</span>
|
|
754
|
+
<button
|
|
755
|
+
id="closeChangedFiles"
|
|
756
|
+
className="btn-ghost btn-xs"
|
|
757
|
+
title="Close"
|
|
758
|
+
>
|
|
759
|
+
<svg
|
|
760
|
+
viewBox="0 0 24 24"
|
|
761
|
+
width="12"
|
|
762
|
+
height="12"
|
|
763
|
+
fill="none"
|
|
764
|
+
stroke="currentColor"
|
|
765
|
+
strok fill="none"
|
|
766
|
+
stroke="currentColor"
|
|
767
|
+
strokeWidth="2.5"
|
|
768
|
+
>
|
|
769
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
770
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
771
|
+
</svg>
|
|
772
|
+
</button>
|
|
773
|
+
</div>
|
|
774
|
+
<div className="changed-files-list" id="changedFilesList"></div>
|
|
775
|
+
</div>
|
|
304
776
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
777
|
+
{/* Connections Panel */}
|
|
778
|
+
<div
|
|
779
|
+
className="connections-panel"
|
|
780
|
+
id="connectionsPanel"
|
|
781
|
+
style={{ display: "none" }}
|
|
782
|
+
>
|
|
783
|
+
<div
|
|
784
|
+
className="panel-header"
|
|
785
|
+
style={{
|
|
786
|
+
display: "flex",
|
|
787
|
+
justifyContent: "space-between",
|
|
788
|
+
alignItems: "center",
|
|
789
|
+
padding: "12px 16px",
|
|
790
|
+
borderBottom: "1px solid var(--border)",
|
|
791
|
+
}}
|
|
792
|
+
>
|
|
793
|
+
<span
|
|
794
|
+
className="panel-title"
|
|
795
|
+
style={{
|
|
796
|
+
fontSize: "0.85rem",
|
|
797
|
+
fontWeight: 600,
|
|
798
|
+
color: "var(--text-primary)",
|
|
799
|
+
}}
|
|
800
|
+
>
|
|
801
|
+
Connections{" "}
|
|
802
|
+
<span
|
|
803
|
+
id="connCount"
|
|
804
|
+
style={{
|
|
805
|
+
marginLeft: "6px",
|
|
806
|
+
background: "rgba(255,255,255,0.1)",
|
|
807
|
+
padding: "2px 8px",
|
|
808
|
+
borderRadius: "12px",
|
|
809
|
+
fontSize: "0.75rem",
|
|
810
|
+
}}
|
|
811
|
+
>
|
|
812
|
+
0
|
|
813
|
+
</span>
|
|
814
|
+
</span>
|
|
815
|
+
<button
|
|
816
|
+
id="closeConnectionsPanel"
|
|
817
|
+
className="btn-ghost btn-xs"
|
|
818
|
+
title="Close"
|
|
819
|
+
>
|
|
820
|
+
<svg
|
|
821
|
+
viewBox="0 0 24 24"
|
|
822
|
+
width="12"
|
|
823
|
+
height="12"
|
|
824
|
+
fill="none"
|
|
825
|
+
stroke="currentColor"
|
|
826
|
+
strokeWidth="2.5"
|
|
827
|
+
>
|
|
828
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
829
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
830
|
+
</svg>
|
|
831
|
+
</button>
|
|
832
|
+
</div>
|
|
833
|
+
<div
|
|
834
|
+
style={{
|
|
835
|
+
padding: "8px 16px",
|
|
836
|
+
fontSize: "0.75rem",
|
|
837
|
+
color: "var(--text-muted)",
|
|
838
|
+
borderBottom: "1px solid var(--border)",
|
|
839
|
+
background: "rgba(0,0,0,0.2)",
|
|
840
|
+
}}
|
|
841
|
+
>
|
|
842
|
+
💡 Tip: <strong>Alt+Click</strong> any line number then select a
|
|
843
|
+
target to connect them.
|
|
844
|
+
</div>
|
|
845
|
+
<div
|
|
846
|
+
className="connections-list"
|
|
847
|
+
id="connectionsList"
|
|
848
|
+
style={{ flex: 1, overflowY: "auto" }}
|
|
849
|
+
></div>
|
|
850
|
+
</div>
|
|
318
851
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
852
|
+
<div className="minimap-container">
|
|
853
|
+
<div className="minimap" id="minimap">
|
|
854
|
+
<div className="minimap-viewport" id="minimapViewport"></div>
|
|
855
|
+
</div>
|
|
856
|
+
<button
|
|
857
|
+
id="expandMinimap"
|
|
858
|
+
className="btn-ghost btn-xs minimap-expand"
|
|
859
|
+
title="Expand minimap"
|
|
860
|
+
>
|
|
861
|
+
<svg
|
|
862
|
+
viewBox="0 0 24 24"
|
|
863
|
+
width="11"
|
|
864
|
+
height="11"
|
|
865
|
+
fill="none"
|
|
866
|
+
stroke="currentColor"
|
|
867
|
+
strokeWidth="2"
|
|
868
|
+
>
|
|
869
|
+
<polyline points="15 3 21 3 21 9" />
|
|
870
|
+
<polyline points="9 21 3 21 3 15" />
|
|
871
|
+
<line x1="21" y1="3" x2="14" y2="10" />
|
|
872
|
+
<line x1="3" y1="21" x2="10" y2="14" />
|
|
873
|
+
</svg>
|
|
874
|
+
</button>
|
|
875
|
+
</div>
|
|
341
876
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
877
|
+
{/* Sticky Zoom Controls — floating pill, bottom-right */}
|
|
878
|
+
<div id="stickyZoomControls" className="sticky-zoom-pill">
|
|
879
|
+
<button id="stickyZoomOut" className="sz-btn" title="Zoom out">
|
|
880
|
+
<svg
|
|
881
|
+
viewBox="0 0 24 24"
|
|
882
|
+
width="14"
|
|
883
|
+
height="14"
|
|
884
|
+
fill="none"
|
|
885
|
+
stroke="currentColor"
|
|
886
|
+
strokeWidth="2.5"
|
|
887
|
+
>
|
|
888
|
+
<line x1="5" y1="12" x2="19" y2="12" />
|
|
889
|
+
</svg>
|
|
890
|
+
</button>
|
|
891
|
+
<input
|
|
892
|
+
type="range"
|
|
893
|
+
id="stickyZoomSlider"
|
|
894
|
+
className="sz-slider"
|
|
895
|
+
min="0.1"
|
|
896
|
+
max="3"
|
|
897
|
+
step="0.05"
|
|
898
|
+
defaultValue="1"
|
|
899
|
+
/>
|
|
900
|
+
<button id="stickyZoomIn" className="sz-btn" title="Zoom in">
|
|
901
|
+
<svg
|
|
902
|
+
viewBox="0 0 24 24"
|
|
903
|
+
width="14"
|
|
904
|
+
height="14"
|
|
905
|
+
fill="none"
|
|
906
|
+
stroke="currentColor"
|
|
907
|
+
strokeWidth="2.5"
|
|
908
|
+
>
|
|
909
|
+
<line x1="12" y1="5" x2="12" y2="19" />
|
|
910
|
+
<line x1="5" y1="12" x2="19" y2="12" />
|
|
911
|
+
</svg>
|
|
912
|
+
</button>
|
|
913
|
+
<span id="stickyZoomValue" className="sz-value">
|
|
914
|
+
100%
|
|
915
|
+
</span>
|
|
916
|
+
<div className="sz-divider" />
|
|
917
|
+
<button
|
|
918
|
+
id="stickyFitAll"
|
|
919
|
+
className="sz-btn sz-fit"
|
|
920
|
+
title="Fit all cards"
|
|
921
|
+
>
|
|
922
|
+
<svg
|
|
923
|
+
viewBox="0 0 24 24"
|
|
924
|
+
width="14"
|
|
925
|
+
height="14"
|
|
926
|
+
fill="none"
|
|
927
|
+
stroke="currentColor"
|
|
928
|
+
strokeWidth="2"
|
|
929
|
+
>
|
|
930
|
+
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" />
|
|
931
|
+
</svg>
|
|
932
|
+
</button>
|
|
933
|
+
</div>
|
|
346
934
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
<div className="modal-header">
|
|
352
|
-
<div className="modal-header-left">
|
|
353
|
-
<span className="file-path" id="previewFilePath"></span>
|
|
354
|
-
<span className="modal-line-count" id="previewLineCount"></span>
|
|
355
|
-
<span className="modal-file-status" id="previewFileStatus"></span>
|
|
356
|
-
</div>
|
|
357
|
-
<div className="modal-header-right">
|
|
358
|
-
<div className="modal-diff-nav" id="modalDiffNav" style={{ display: 'none', marginRight: '16px', gap: '4px', alignItems: 'center' }}>
|
|
359
|
-
<button className="btn-ghost btn-xs" id="diffNavPrev" title="Previous changed file (k)">
|
|
360
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
|
361
|
-
</button>
|
|
362
|
-
<button className="btn-ghost btn-xs" id="diffNavNext" title="Next changed file (j)">
|
|
363
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
|
364
|
-
</button>
|
|
365
|
-
</div>
|
|
366
|
-
<div className="modal-view-tabs" id="modalViewTabs">
|
|
367
|
-
<button className="modal-tab active" data-view="edit">
|
|
368
|
-
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2">
|
|
369
|
-
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" />
|
|
370
|
-
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" />
|
|
371
|
-
</svg>
|
|
372
|
-
Edit
|
|
373
|
-
</button>
|
|
374
|
-
<button className="modal-tab" data-view="diff">
|
|
375
|
-
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2">
|
|
376
|
-
<path d="M12 3v18M3 12h18" />
|
|
377
|
-
</svg>
|
|
378
|
-
Diff
|
|
379
|
-
</button>
|
|
380
|
-
</div>
|
|
381
|
-
<span className="modal-save-status" id="modalSaveStatus" style={{ display: 'none' }}></span>
|
|
382
|
-
<button className="btn-ghost btn-xs modal-outline-toggle" id="outlineToggle" title="Toggle symbol outline (Ctrl+Shift+O)">
|
|
383
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
384
|
-
<line x1="8" y1="6" x2="21" y2="6" /><line x1="8" y1="12" x2="21" y2="12" /><line x1="8" y1="18" x2="21" y2="18" />
|
|
385
|
-
<line x1="3" y1="6" x2="3.01" y2="6" /><line x1="3" y1="12" x2="3.01" y2="12" /><line x1="3" y1="18" x2="3.01" y2="18" />
|
|
386
|
-
</svg>
|
|
387
|
-
</button>
|
|
388
|
-
<button className="modal-close" id="closePreview">×</button>
|
|
389
|
-
</div>
|
|
390
|
-
</div>
|
|
391
|
-
<div className="modal-body-wrapper">
|
|
392
|
-
<pre className="modal-body" id="modalBodyPre"><code id="previewContent"></code></pre>
|
|
393
|
-
<div className="modal-outline-panel" id="modalOutlinePanel" style={{ display: 'none' }}></div>
|
|
394
|
-
</div>
|
|
395
|
-
<div className="modal-blame-container" id="modalBlameContainer" style={{ display: 'none' }}></div>
|
|
396
|
-
<div className="modal-chat-container" id="modalChatContainer" style={{ display: 'none' }}></div>
|
|
397
|
-
<div className="modal-edit-container" id="modalEditContainer" style={{ display: 'none' }}>
|
|
398
|
-
<textarea id="modalEditTextarea" className="modal-edit-textarea" spellCheck={false} autoComplete="off"></textarea>
|
|
399
|
-
<div className="modal-edit-toolbar" id="modalEditToolbar">
|
|
400
|
-
<span className="edit-line-info" id="editLineInfo">Line 1, Col 1</span>
|
|
401
|
-
<div className="edit-toolbar-right">
|
|
402
|
-
<div className="edit-commit-section" id="editCommitSection" style={{ display: 'none' }}>
|
|
403
|
-
<input
|
|
404
|
-
type="text"
|
|
405
|
-
id="editCommitMsg"
|
|
406
|
-
className="edit-commit-input"
|
|
407
|
-
placeholder="Commit message..."
|
|
408
|
-
spellCheck={false}
|
|
409
|
-
autoComplete="off"
|
|
410
|
-
/>
|
|
411
|
-
<button className="btn-ghost btn-sm edit-commit-btn" id="editCommitBtn" title="Commit this file">
|
|
412
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
413
|
-
<circle cx="12" cy="12" r="4" />
|
|
414
|
-
<line x1="1.05" y1="12" x2="7" y2="12" />
|
|
415
|
-
<line x1="17.01" y1="12" x2="22.96" y2="12" />
|
|
416
|
-
</svg>
|
|
417
|
-
Commit
|
|
418
|
-
</button>
|
|
419
|
-
<button className="btn-ghost btn-xs edit-commit-cancel" id="editCommitCancel" title="Cancel">
|
|
420
|
-
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2.5">
|
|
421
|
-
<line x1="18" y1="6" x2="6" y2="18" />
|
|
422
|
-
<line x1="6" y1="6" x2="18" y2="18" />
|
|
423
|
-
</svg>
|
|
424
|
-
</button>
|
|
425
|
-
</div>
|
|
426
|
-
<button className="btn-ghost btn-sm edit-save-btn" id="editSaveBtn" title="Save (Ctrl+S)">
|
|
427
|
-
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2">
|
|
428
|
-
<path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z" />
|
|
429
|
-
<polyline points="17 21 17 13 7 13 7 21" />
|
|
430
|
-
<polyline points="7 3 7 8 15 8" />
|
|
431
|
-
</svg>
|
|
432
|
-
Save
|
|
433
|
-
</button>
|
|
434
|
-
</div>
|
|
435
|
-
</div>
|
|
436
|
-
</div>
|
|
437
|
-
</div>
|
|
438
|
-
</div>
|
|
935
|
+
{/* Bottom Layers Bar */}
|
|
936
|
+
<div id="layersBarContainer"></div>
|
|
937
|
+
</main>
|
|
938
|
+
</div>
|
|
439
939
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
940
|
+
{/* File Preview Modal */}
|
|
941
|
+
<div className="file-preview-modal" id="filePreviewModal">
|
|
942
|
+
<div className="modal-backdrop"></div>
|
|
943
|
+
<div className="modal-content">
|
|
944
|
+
<div className="modal-header">
|
|
945
|
+
<div className="modal-header-left">
|
|
946
|
+
<span className="file-path" id="previewFilePath"></span>
|
|
947
|
+
<span
|
|
948
|
+
className="modal-file-status"
|
|
949
|
+
id="previewFileStatus"
|
|
950
|
+
></span>
|
|
951
|
+
</div>
|
|
952
|
+
<div className="modal-header-right">
|
|
953
|
+
<div
|
|
954
|
+
className="modal-diff-nav"
|
|
955
|
+
id="modalDiffNav"
|
|
956
|
+
style={{
|
|
957
|
+
display: "none",
|
|
958
|
+
marginRight: "16px",
|
|
959
|
+
gap: "4px",
|
|
960
|
+
alignItems: "center",
|
|
961
|
+
}}
|
|
962
|
+
>
|
|
963
|
+
<button
|
|
964
|
+
className="btn-ghost btn-xs"
|
|
965
|
+
id="diffNavPrev"
|
|
966
|
+
title="Previous changed file (k)"
|
|
967
|
+
>
|
|
968
|
+
<svg
|
|
969
|
+
viewBox="0 0 24 24"
|
|
970
|
+
width="14"
|
|
971
|
+
height="14"
|
|
972
|
+
fill="none"
|
|
973
|
+
stroke="currentColor"
|
|
974
|
+
strokeWidth="2.5"
|
|
975
|
+
>
|
|
976
|
+
<polyline points="15 18 9 12 15 6"></polyline>
|
|
977
|
+
</svg>
|
|
978
|
+
</button>
|
|
979
|
+
<button
|
|
980
|
+
className="btn-ghost btn-xs"
|
|
981
|
+
id="diffNavNext"
|
|
982
|
+
title="Next changed file (j)"
|
|
983
|
+
>
|
|
984
|
+
<svg
|
|
985
|
+
viewBox="0 0 24 24"
|
|
986
|
+
width="14"
|
|
987
|
+
height="14"
|
|
988
|
+
fill="none"
|
|
989
|
+
stroke="currentColor"
|
|
990
|
+
strokeWidth="2.5"
|
|
991
|
+
>
|
|
992
|
+
<polyline points="9 18 15 12 9 6"></polyline>
|
|
993
|
+
</svg>
|
|
994
|
+
</button>
|
|
995
|
+
</div>
|
|
996
|
+
<div className="modal-view-tabs" id="modalViewTabs">
|
|
997
|
+
<button className="modal-tab active" data-view="edit">
|
|
998
|
+
<svg
|
|
999
|
+
viewBox="0 0 24 24"
|
|
1000
|
+
width="12"
|
|
1001
|
+
height="12"
|
|
1002
|
+
fill="none"
|
|
1003
|
+
stroke="currentColor"
|
|
1004
|
+
strokeWidth="2"
|
|
1005
|
+
>
|
|
1006
|
+
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" />
|
|
1007
|
+
</svg>
|
|
1008
|
+
Edit
|
|
1009
|
+
</button>
|
|
1010
|
+
<button className="modal-tab" data-view="diff">
|
|
1011
|
+
<svg
|
|
1012
|
+
viewBox="0 0 24 24"
|
|
1013
|
+
width="12"
|
|
1014
|
+
height="12"
|
|
1015
|
+
fill="none"
|
|
1016
|
+
stroke="currentColor"
|
|
1017
|
+
strokeWidth="2"
|
|
1018
|
+
>
|
|
1019
|
+
<path d="M12 3v18M3 12h18" />
|
|
1020
|
+
</svg>
|
|
1021
|
+
Diff
|
|
1022
|
+
</button>
|
|
510
1023
|
</div>
|
|
511
|
-
<
|
|
512
|
-
|
|
1024
|
+
<span
|
|
1025
|
+
id="modalSaveStatus"
|
|
1026
|
+
style={{ display: "none" }}
|
|
1027
|
+
></span>
|
|
1028
|
+
<button
|
|
1029
|
+
className="btn-ghost btn-xs modal-outline-toggle"
|
|
1030
|
+
id="outlineToggle"
|
|
1031
|
+
title="Toggle symbol outline (Ctrl+Shift+O)"
|
|
1032
|
+
>
|
|
1033
|
+
<svg
|
|
1034
|
+
viewBox="0 0 24 24"
|
|
1035
|
+
width="14"
|
|
1036
|
+
height="14"
|
|
1037
|
+
fill="none"
|
|
1038
|
+
stroke="currentColor"
|
|
1039
|
+
strokeWidth="2"
|
|
1040
|
+
>
|
|
1041
|
+
<line x1="8" y1="6" x2="21" y2="6" />
|
|
1042
|
+
<line x1="8" y1="12" x2="21" y2="12" />
|
|
1043
|
+
<line x1="8" y1="18" x2="21" y2="18" />
|
|
1044
|
+
<line x1="3" y1="6" x2="3.01" y2="6" />
|
|
1045
|
+
<line x1="3" y1="12" x2="3.01" y2="12" />
|
|
1046
|
+
<line x1="3" y1="18" x2="3.01" y2="18" />
|
|
1047
|
+
</svg>
|
|
1048
|
+
</button>
|
|
1049
|
+
<button className="modal-close" id="closePreview">
|
|
1050
|
+
×
|
|
1051
|
+
</button>
|
|
1052
|
+
</div>
|
|
1053
|
+
</div>
|
|
1054
|
+
<div className="modal-body-wrapper">
|
|
1055
|
+
<pre className="modal-body" id="modalBodyPre">
|
|
1056
|
+
<code id="previewContent"></code>
|
|
1057
|
+
</pre>
|
|
1058
|
+
<div
|
|
1059
|
+
className="modal-outline-panel"
|
|
1060
|
+
id="modalOutlinePanel"
|
|
1061
|
+
style={{ display: "none" }}
|
|
1062
|
+
></div>
|
|
1063
|
+
</div>
|
|
1064
|
+
<div
|
|
1065
|
+
className="modal-blame-container"
|
|
1066
|
+
id="modalBlameContainer"
|
|
1067
|
+
style={{ display: "none" }}
|
|
1068
|
+
></div>
|
|
1069
|
+
<div
|
|
1070
|
+
className="modal-chat-container"
|
|
1071
|
+
id="modalChatContainer"
|
|
1072
|
+
style={{ display: "none" }}
|
|
1073
|
+
></div>
|
|
1074
|
+
<div
|
|
1075
|
+
className="modal-edit-container"
|
|
1076
|
+
id="modalEditContainer"
|
|
1077
|
+
style={{ display: "none" }}
|
|
1078
|
+
>
|
|
1079
|
+
<textarea
|
|
1080
|
+
id="modalEditTextarea"
|
|
1081
|
+
className="modal-edit-textarea"
|
|
1082
|
+
spellCheck={false}
|
|
1083
|
+
autoComplete="off"
|
|
1084
|
+
></textarea>
|
|
1085
|
+
<div className="modal-edit-toolbar" id="modalEditToolbar">
|
|
1086
|
+
<span className="edit-line-info" id="editLineInfo">
|
|
1087
|
+
Line 1, Col 1
|
|
1088
|
+
</span>
|
|
1089
|
+
<div className="edit-toolbar-right">
|
|
1090
|
+
<div
|
|
1091
|
+
className="edit-commit-section"
|
|
1092
|
+
id="editCommitSection"
|
|
1093
|
+
style={{ display: "none" }}
|
|
1094
|
+
>
|
|
1095
|
+
<input
|
|
1096
|
+
type="text"
|
|
1097
|
+
id="editCommitMsg"
|
|
1098
|
+
className="edit-commit-input"
|
|
1099
|
+
placeholder="Commit message..."
|
|
1100
|
+
spellCheck={false}
|
|
1101
|
+
autoComplete="off"
|
|
1102
|
+
/>
|
|
1103
|
+
<button
|
|
1104
|
+
className="btn-ghost btn-sm edit-commit-btn"
|
|
1105
|
+
id="editCommitBtn"
|
|
1106
|
+
title="Commit this file"
|
|
1107
|
+
>
|
|
1108
|
+
<svg
|
|
1109
|
+
viewBox="0 0 24 24"
|
|
1110
|
+
width="14"
|
|
1111
|
+
height="14"
|
|
1112
|
+
fill="none"
|
|
1113
|
+
stroke="currentColor"
|
|
1114
|
+
strokeWidth="2"
|
|
1115
|
+
>
|
|
1116
|
+
<circle cx="12" cy="12" r="4" />
|
|
1117
|
+
<path d="M5 12l5 5L20 7" />
|
|
1118
|
+
</svg>
|
|
1119
|
+
Commit
|
|
1120
|
+
</button>
|
|
1121
|
+
<button
|
|
1122
|
+
className="btn-ghost btn-xs edit-commit-cancel"
|
|
1123
|
+
id="editCommitCancel"
|
|
1124
|
+
title="Cancel"
|
|
1125
|
+
>
|
|
1126
|
+
<svg
|
|
1127
|
+
viewBox="0 0 24 24"
|
|
1128
|
+
width="12"
|
|
1129
|
+
height="12"
|
|
1130
|
+
fill="none"
|
|
1131
|
+
stroke="currentColor"
|
|
1132
|
+
strokeWidth="2.5"
|
|
1133
|
+
>
|
|
1134
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
1135
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
1136
|
+
</svg>
|
|
1137
|
+
</button>
|
|
1138
|
+
</div>
|
|
1139
|
+
<button
|
|
1140
|
+
className="btn-ghost btn-sm edit-save-btn"
|
|
1141
|
+
id="editSaveBtn"
|
|
1142
|
+
title="Save (Ctrl+S)"
|
|
1143
|
+
>
|
|
1144
|
+
<svg
|
|
1145
|
+
viewBox="0 0 24 24"
|
|
1146
|
+
width="14"
|
|
1147
|
+
height="14"
|
|
1148
|
+
fill="none"
|
|
1149
|
+
stroke="currentColor"
|
|
1150
|
+
strokeWidth="2"
|
|
1151
|
+
>
|
|
1152
|
+
<path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z" />
|
|
1153
|
+
<polyline points="17 21 17 13 7 13 7 21" />
|
|
1154
|
+
<polyline points="7 3 7 8 15 8" />
|
|
1155
|
+
</svg>
|
|
1156
|
+
Save
|
|
1157
|
+
</button>
|
|
1158
|
+
</div>
|
|
1159
|
+
</div>
|
|
1160
|
+
</div>
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
|
|
1164
|
+
{/* GitHub Import Modal */}
|
|
1165
|
+
<div className="github-modal" id="githubModal">
|
|
1166
|
+
<div className="github-modal-backdrop"></div>
|
|
1167
|
+
<div className="github-modal-content">
|
|
1168
|
+
<div className="github-modal-header">
|
|
1169
|
+
<div className="github-modal-title">
|
|
1170
|
+
<svg
|
|
1171
|
+
viewBox="0 0 24 24"
|
|
1172
|
+
width="20"
|
|
1173
|
+
height="20"
|
|
1174
|
+
fill="currentColor"
|
|
1175
|
+
style={{ opacity: 0.7 }}
|
|
1176
|
+
>
|
|
1177
|
+
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
|
1178
|
+
</svg>
|
|
1179
|
+
<span>Import from GitHub</span>
|
|
1180
|
+
</div>
|
|
1181
|
+
<button className="github-modal-close" id="githubModalClose">
|
|
1182
|
+
×
|
|
1183
|
+
</button>
|
|
1184
|
+
</div>
|
|
1185
|
+
<div className="github-search-row">
|
|
1186
|
+
<input
|
|
1187
|
+
type="text"
|
|
1188
|
+
id="githubUserInput"
|
|
1189
|
+
className="github-user-input"
|
|
1190
|
+
placeholder="Username, org, or paste a GitHub URL..."
|
|
1191
|
+
spellCheck={false}
|
|
1192
|
+
autoComplete="off"
|
|
1193
|
+
/>
|
|
1194
|
+
<select id="githubSortSelect" className="github-sort-select">
|
|
1195
|
+
<option value="updated">Recently Updated</option>
|
|
1196
|
+
<option value="stars">Most Stars</option>
|
|
1197
|
+
<option value="name">Name A→Z</option>
|
|
1198
|
+
</select>
|
|
1199
|
+
<button id="githubSearchBtn" className="github-search-btn">
|
|
1200
|
+
<svg
|
|
1201
|
+
viewBox="0 0 24 24"
|
|
1202
|
+
width="14"
|
|
1203
|
+
height="14"
|
|
1204
|
+
fill="none"
|
|
1205
|
+
stroke="currentColor"
|
|
1206
|
+
strokeWidth="2.5"
|
|
1207
|
+
>
|
|
1208
|
+
<circle cx="11" cy="11" r="8" />
|
|
1209
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
1210
|
+
</svg>
|
|
1211
|
+
Search
|
|
1212
|
+
</button>
|
|
1213
|
+
</div>
|
|
1214
|
+
<div
|
|
1215
|
+
className="github-url-clone-row"
|
|
1216
|
+
id="githubUrlCloneRow"
|
|
1217
|
+
style={{ display: "none" }}
|
|
1218
|
+
>
|
|
1219
|
+
<div className="github-url-detected">
|
|
1220
|
+
<svg
|
|
1221
|
+
viewBox="0 0 24 24"
|
|
1222
|
+
width="14"
|
|
1223
|
+
height="14"
|
|
1224
|
+
fill="none"
|
|
1225
|
+
stroke="currentColor"
|
|
1226
|
+
strokeWidth="2"
|
|
1227
|
+
>
|
|
1228
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
1229
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
1230
|
+
</svg>
|
|
1231
|
+
<span id="githubDetectedUrl">URL detected</span>
|
|
1232
|
+
</div>
|
|
1233
|
+
<button
|
|
1234
|
+
id="githubUrlCloneBtn"
|
|
1235
|
+
className="github-clone-btn github-url-clone-btn"
|
|
1236
|
+
>
|
|
1237
|
+
Clone & Open
|
|
1238
|
+
</button>
|
|
1239
|
+
</div>
|
|
1240
|
+
<div
|
|
1241
|
+
className="github-filter-row"
|
|
1242
|
+
id="githubFilterRow"
|
|
1243
|
+
style={{ display: "none" }}
|
|
1244
|
+
>
|
|
1245
|
+
<input
|
|
1246
|
+
type="text"
|
|
1247
|
+
id="githubRepoFilter"
|
|
1248
|
+
className="github-repo-filter"
|
|
1249
|
+
placeholder="Filter repos by name..."
|
|
1250
|
+
spellCheck={false}
|
|
1251
|
+
autoComplete="off"
|
|
1252
|
+
/>
|
|
1253
|
+
</div>
|
|
1254
|
+
<div
|
|
1255
|
+
className="github-profile"
|
|
1256
|
+
id="githubProfile"
|
|
1257
|
+
style={{ display: "none" }}
|
|
1258
|
+
></div>
|
|
1259
|
+
<div className="github-repos-grid" id="githubReposGrid">
|
|
1260
|
+
<div className="github-empty-state">
|
|
1261
|
+
<svg
|
|
1262
|
+
viewBox="0 0 24 24"
|
|
1263
|
+
width="40"
|
|
1264
|
+
height="40"
|
|
1265
|
+
fill="none"
|
|
1266
|
+
stroke="currentColor"
|
|
1267
|
+
strokeWidth="1"
|
|
1268
|
+
opacity="0.2"
|
|
1269
|
+
>
|
|
1270
|
+
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
|
|
1271
|
+
</svg>
|
|
1272
|
+
<p>Enter a GitHub username to browse their repositories</p>
|
|
1273
|
+
</div>
|
|
1274
|
+
</div>
|
|
1275
|
+
<div
|
|
1276
|
+
className="github-pagination"
|
|
1277
|
+
id="githubPagination"
|
|
1278
|
+
style={{ display: "none" }}
|
|
1279
|
+
>
|
|
1280
|
+
<button id="githubPrevPage" className="github-page-btn" disabled>
|
|
1281
|
+
← Previous
|
|
1282
|
+
</button>
|
|
1283
|
+
<span id="githubPageInfo" className="github-page-info">
|
|
1284
|
+
Page 1
|
|
1285
|
+
</span>
|
|
1286
|
+
<button id="githubNextPage" className="github-page-btn">
|
|
1287
|
+
Next →
|
|
1288
|
+
</button>
|
|
1289
|
+
</div>
|
|
1290
|
+
</div>
|
|
1291
|
+
</div>
|
|
1292
|
+
<script
|
|
1293
|
+
dangerouslySetInnerHTML={{
|
|
1294
|
+
__html: `
|
|
513
1295
|
if ('serviceWorker' in navigator) {
|
|
514
1296
|
navigator.serviceWorker.register('/api/sw.js', { scope: '/' })
|
|
515
1297
|
.catch(function(e) { console.warn('[SW] Registration failed:', e); });
|
|
516
1298
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
1299
|
+
fetch('/api/analytics', {
|
|
1300
|
+
method: 'POST',
|
|
1301
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1302
|
+
body: JSON.stringify({ path: location.pathname })
|
|
1303
|
+
}).catch(function(){});
|
|
1304
|
+
`,
|
|
1305
|
+
}}
|
|
1306
|
+
/>
|
|
1307
|
+
</body>
|
|
1308
|
+
</html>
|
|
1309
|
+
);
|
|
521
1310
|
}
|