@principal-ai/file-city-react 0.5.22 → 0.5.24
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/dist/components/ArchitectureMapHighlightLayers.d.ts +6 -2
- package/dist/components/ArchitectureMapHighlightLayers.d.ts.map +1 -1
- package/dist/components/ArchitectureMapHighlightLayers.js +74 -2
- package/dist/components/FileCity3D/FileCity3D.d.ts +18 -1
- package/dist/components/FileCity3D/FileCity3D.d.ts.map +1 -1
- package/dist/components/FileCity3D/FileCity3D.js +91 -48
- package/dist/components/FileCity3D/index.d.ts +2 -2
- package/dist/components/FileCity3D/index.d.ts.map +1 -1
- package/dist/components/FileCity3D/index.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/stories/sample-data.d.ts.map +1 -1
- package/dist/stories/sample-data.js +44 -42
- package/dist/utils/visualizationResolution.d.ts +72 -0
- package/dist/utils/visualizationResolution.d.ts.map +1 -0
- package/dist/utils/visualizationResolution.js +100 -0
- package/package.json +1 -1
- package/src/components/ArchitectureMapHighlightLayers.tsx +101 -2
- package/src/components/FileCity3D/FileCity3D.tsx +125 -54
- package/src/components/FileCity3D/index.ts +2 -0
- package/src/index.ts +10 -1
- package/src/stories/2D3DComparison.stories.tsx +527 -0
- package/src/stories/sample-data.ts +47 -45
- package/src/utils/visualizationResolution.ts +170 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import { ArchitectureMapHighlightLayers } from '../components/ArchitectureMapHighlightLayers';
|
|
5
|
+
import { FileCity3D, type HighlightLayer, type IsolationMode, type CityData } from '../components/FileCity3D';
|
|
6
|
+
import { createFileColorHighlightLayers } from '../utils/fileColorHighlightLayers';
|
|
7
|
+
import authServerCityData from '../../../../assets/auth-server-city-data.json';
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'Comparison/2D vs 3D',
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen',
|
|
13
|
+
},
|
|
14
|
+
} satisfies Meta;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
|
|
18
|
+
type ViewMode = '2d' | '3d-flat' | '3d-grown';
|
|
19
|
+
|
|
20
|
+
export const ViewModeSwitch: StoryObj = {
|
|
21
|
+
render: function RenderViewModeSwitch() {
|
|
22
|
+
const [viewMode, setViewMode] = useState<ViewMode>('2d');
|
|
23
|
+
const [overlayOpacity, setOverlayOpacity] = useState(1);
|
|
24
|
+
const [hideOverlay, setHideOverlay] = useState(false);
|
|
25
|
+
const cityData = authServerCityData as CityData;
|
|
26
|
+
const highlightLayers = createFileColorHighlightLayers(cityData.buildings);
|
|
27
|
+
|
|
28
|
+
const handleViewModeChange = (mode: ViewMode) => {
|
|
29
|
+
if (mode !== '2d' && viewMode === '2d') {
|
|
30
|
+
// Switching from 2D to 3D - reset overlay state before changing mode
|
|
31
|
+
setOverlayOpacity(1);
|
|
32
|
+
setHideOverlay(false);
|
|
33
|
+
}
|
|
34
|
+
setViewMode(mode);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Fade out overlay after switching to 3D
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (viewMode !== '2d') {
|
|
40
|
+
// Wait for 3D to render, then fade out
|
|
41
|
+
const fadeTimer = setTimeout(() => {
|
|
42
|
+
setOverlayOpacity(0);
|
|
43
|
+
}, 100);
|
|
44
|
+
// Remove overlay after fade completes
|
|
45
|
+
const removeTimer = setTimeout(() => {
|
|
46
|
+
setHideOverlay(true);
|
|
47
|
+
}, 400);
|
|
48
|
+
return () => {
|
|
49
|
+
clearTimeout(fadeTimer);
|
|
50
|
+
clearTimeout(removeTimer);
|
|
51
|
+
};
|
|
52
|
+
} else {
|
|
53
|
+
setHideOverlay(false);
|
|
54
|
+
setOverlayOpacity(1);
|
|
55
|
+
}
|
|
56
|
+
}, [viewMode]);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
60
|
+
<div
|
|
61
|
+
style={{
|
|
62
|
+
padding: '12px 16px',
|
|
63
|
+
backgroundColor: '#1f2937',
|
|
64
|
+
borderBottom: '1px solid #374151',
|
|
65
|
+
display: 'flex',
|
|
66
|
+
gap: '8px',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<span style={{ color: '#9ca3af', marginRight: '8px', fontSize: '14px' }}>View Mode:</span>
|
|
71
|
+
{(['2d', '3d-flat', '3d-grown'] as ViewMode[]).map(mode => (
|
|
72
|
+
<button
|
|
73
|
+
key={mode}
|
|
74
|
+
onClick={() => handleViewModeChange(mode)}
|
|
75
|
+
style={{
|
|
76
|
+
padding: '6px 12px',
|
|
77
|
+
borderRadius: '6px',
|
|
78
|
+
border: 'none',
|
|
79
|
+
cursor: 'pointer',
|
|
80
|
+
fontSize: '13px',
|
|
81
|
+
fontWeight: 500,
|
|
82
|
+
backgroundColor: viewMode === mode ? '#3b82f6' : '#374151',
|
|
83
|
+
color: viewMode === mode ? '#ffffff' : '#d1d5db',
|
|
84
|
+
transition: 'all 0.15s ease',
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
{mode === '2d' ? '2D Canvas' : mode === '3d-flat' ? '3D (Flat)' : '3D (Grown)'}
|
|
88
|
+
</button>
|
|
89
|
+
))}
|
|
90
|
+
<span style={{ color: '#6b7280', fontSize: '12px', marginLeft: '16px' }}>
|
|
91
|
+
Compare initial render between 2D canvas and 3D flat view
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div style={{ flex: 1, backgroundColor: '#0f1419', position: 'relative' }}>
|
|
96
|
+
{/* 3D layer (behind) */}
|
|
97
|
+
{viewMode !== '2d' && (
|
|
98
|
+
<FileCity3D
|
|
99
|
+
cityData={cityData}
|
|
100
|
+
highlightLayers={highlightLayers}
|
|
101
|
+
width="100%"
|
|
102
|
+
height="100%"
|
|
103
|
+
isGrown={viewMode === '3d-grown'}
|
|
104
|
+
showControls={true}
|
|
105
|
+
backgroundColor="#0f1419"
|
|
106
|
+
/>
|
|
107
|
+
)}
|
|
108
|
+
|
|
109
|
+
{/* 2D layer (on top, fades out when switching to 3D) */}
|
|
110
|
+
{(viewMode === '2d' || !hideOverlay) && (
|
|
111
|
+
<div
|
|
112
|
+
style={{
|
|
113
|
+
position: 'absolute',
|
|
114
|
+
top: 0,
|
|
115
|
+
left: 0,
|
|
116
|
+
right: 0,
|
|
117
|
+
bottom: 0,
|
|
118
|
+
opacity: viewMode === '2d' ? 1 : overlayOpacity,
|
|
119
|
+
transition: 'opacity 300ms ease-out',
|
|
120
|
+
pointerEvents: viewMode === '2d' ? 'auto' : 'none',
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
<ArchitectureMapHighlightLayers
|
|
124
|
+
cityData={cityData}
|
|
125
|
+
highlightLayers={highlightLayers}
|
|
126
|
+
fullSize={true}
|
|
127
|
+
canvasBackgroundColor="#0f1419"
|
|
128
|
+
defaultBuildingColor="#36454F"
|
|
129
|
+
defaultDirectoryColor="#111827"
|
|
130
|
+
enableZoom={viewMode === '2d'}
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export const SideBySide: StoryObj = {
|
|
141
|
+
render: function RenderSideBySide() {
|
|
142
|
+
const cityData = authServerCityData as CityData;
|
|
143
|
+
const highlightLayers = createFileColorHighlightLayers(cityData.buildings);
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
147
|
+
<div
|
|
148
|
+
style={{
|
|
149
|
+
padding: '12px 16px',
|
|
150
|
+
backgroundColor: '#1f2937',
|
|
151
|
+
borderBottom: '1px solid #374151',
|
|
152
|
+
}}
|
|
153
|
+
>
|
|
154
|
+
<span style={{ color: '#9ca3af', fontSize: '14px' }}>
|
|
155
|
+
Side-by-side comparison: 2D Canvas (left) vs 3D Flat (right)
|
|
156
|
+
</span>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div style={{ flex: 1, display: 'flex' }}>
|
|
160
|
+
<div
|
|
161
|
+
style={{
|
|
162
|
+
flex: 1,
|
|
163
|
+
borderRight: '1px solid #374151',
|
|
164
|
+
display: 'flex',
|
|
165
|
+
flexDirection: 'column',
|
|
166
|
+
}}
|
|
167
|
+
>
|
|
168
|
+
<div
|
|
169
|
+
style={{
|
|
170
|
+
padding: '8px 12px',
|
|
171
|
+
backgroundColor: '#111827',
|
|
172
|
+
borderBottom: '1px solid #374151',
|
|
173
|
+
color: '#9ca3af',
|
|
174
|
+
fontSize: '12px',
|
|
175
|
+
fontWeight: 500,
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
2D CANVAS
|
|
179
|
+
</div>
|
|
180
|
+
<div style={{ flex: 1, backgroundColor: '#0f1419' }}>
|
|
181
|
+
<ArchitectureMapHighlightLayers
|
|
182
|
+
cityData={cityData}
|
|
183
|
+
highlightLayers={highlightLayers}
|
|
184
|
+
fullSize={true}
|
|
185
|
+
canvasBackgroundColor="#0f1419"
|
|
186
|
+
defaultBuildingColor="#36454F"
|
|
187
|
+
defaultDirectoryColor="#111827"
|
|
188
|
+
enableZoom={true}
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
|
|
194
|
+
<div
|
|
195
|
+
style={{
|
|
196
|
+
padding: '8px 12px',
|
|
197
|
+
backgroundColor: '#111827',
|
|
198
|
+
borderBottom: '1px solid #374151',
|
|
199
|
+
color: '#9ca3af',
|
|
200
|
+
fontSize: '12px',
|
|
201
|
+
fontWeight: 500,
|
|
202
|
+
}}
|
|
203
|
+
>
|
|
204
|
+
3D FLAT
|
|
205
|
+
</div>
|
|
206
|
+
<div style={{ flex: 1, backgroundColor: '#0f1419' }}>
|
|
207
|
+
<FileCity3D
|
|
208
|
+
cityData={cityData}
|
|
209
|
+
highlightLayers={highlightLayers}
|
|
210
|
+
width="100%"
|
|
211
|
+
height="100%"
|
|
212
|
+
isGrown={false}
|
|
213
|
+
showControls={false}
|
|
214
|
+
backgroundColor="#0f1419"
|
|
215
|
+
/>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// Test scenarios for highlight comparison
|
|
225
|
+
// No explicit isolationMode - let resolution determine everything
|
|
226
|
+
interface TestScenario {
|
|
227
|
+
id: string;
|
|
228
|
+
name: string;
|
|
229
|
+
description: string;
|
|
230
|
+
focusDirectory: string | null;
|
|
231
|
+
focusColor?: string | null;
|
|
232
|
+
highlightLayers: HighlightLayer[];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const testScenarios: TestScenario[] = [
|
|
236
|
+
{
|
|
237
|
+
id: 'S1-baseline',
|
|
238
|
+
name: 'S1: Baseline',
|
|
239
|
+
description: 'Full city view, no focus, no highlights - all file colors shown',
|
|
240
|
+
focusDirectory: null,
|
|
241
|
+
highlightLayers: [],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'S2-focus-only',
|
|
245
|
+
name: 'S2: Focus Only (src)',
|
|
246
|
+
description: 'Camera zooms to src, file colors filtered to focus area',
|
|
247
|
+
focusDirectory: 'auth-server/src',
|
|
248
|
+
focusColor: '#3b82f6',
|
|
249
|
+
highlightLayers: [],
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: 'S2b-focus-only-tests',
|
|
253
|
+
name: 'S2b: Focus Only (bruno)',
|
|
254
|
+
description: 'Camera zooms to bruno directory',
|
|
255
|
+
focusDirectory: 'auth-server/bruno',
|
|
256
|
+
focusColor: '#22c55e',
|
|
257
|
+
highlightLayers: [],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: 'S3-highlight-only',
|
|
261
|
+
name: 'S3: Highlight Only',
|
|
262
|
+
description: 'Full view with highlight layer, file colors filtered to highlight area',
|
|
263
|
+
focusDirectory: null,
|
|
264
|
+
highlightLayers: [
|
|
265
|
+
{
|
|
266
|
+
id: 'api-layer',
|
|
267
|
+
name: 'API Routes',
|
|
268
|
+
enabled: true,
|
|
269
|
+
color: '#22c55e',
|
|
270
|
+
items: [{ path: 'auth-server/src/app/api', type: 'directory' as const }],
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
id: 'S4-focus-highlight-same',
|
|
276
|
+
name: 'S4: Focus + Highlight (same directory)',
|
|
277
|
+
description: 'Focus and highlight on same directory',
|
|
278
|
+
focusDirectory: 'auth-server/src/app/api',
|
|
279
|
+
focusColor: '#3b82f6',
|
|
280
|
+
highlightLayers: [
|
|
281
|
+
{
|
|
282
|
+
id: 'api-layer',
|
|
283
|
+
name: 'API Routes',
|
|
284
|
+
enabled: true,
|
|
285
|
+
color: '#3b82f6',
|
|
286
|
+
items: [{ path: 'auth-server/src/app/api', type: 'directory' as const }],
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
id: 'S5-focus-highlight-subset',
|
|
292
|
+
name: 'S5: Focus + Highlight (subset)',
|
|
293
|
+
description: 'Focus on src, highlight only lib subset',
|
|
294
|
+
focusDirectory: 'auth-server/src',
|
|
295
|
+
focusColor: '#3b82f6',
|
|
296
|
+
highlightLayers: [
|
|
297
|
+
{
|
|
298
|
+
id: 'lib-layer',
|
|
299
|
+
name: 'Libraries',
|
|
300
|
+
enabled: true,
|
|
301
|
+
color: '#8b5cf6',
|
|
302
|
+
items: [{ path: 'auth-server/src/lib', type: 'directory' as const }],
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
id: 'S6-multiple-highlights-focus',
|
|
308
|
+
name: 'S6: Multiple Highlights (with focus)',
|
|
309
|
+
description: 'Two highlight layers within focused area',
|
|
310
|
+
focusDirectory: 'auth-server/src',
|
|
311
|
+
focusColor: '#3b82f6',
|
|
312
|
+
highlightLayers: [
|
|
313
|
+
{
|
|
314
|
+
id: 'api-layer',
|
|
315
|
+
name: 'API Routes',
|
|
316
|
+
enabled: true,
|
|
317
|
+
color: '#22c55e',
|
|
318
|
+
items: [{ path: 'auth-server/src/app/api', type: 'directory' as const }],
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: 'lib-layer',
|
|
322
|
+
name: 'Libraries',
|
|
323
|
+
enabled: true,
|
|
324
|
+
color: '#f59e0b',
|
|
325
|
+
items: [{ path: 'auth-server/src/lib', type: 'directory' as const }],
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: 'S7-multiple-highlights-no-focus',
|
|
331
|
+
name: 'S7: Multiple Highlights (no focus)',
|
|
332
|
+
description: 'Two highlight layers, file colors filtered to both areas',
|
|
333
|
+
focusDirectory: null,
|
|
334
|
+
highlightLayers: [
|
|
335
|
+
{
|
|
336
|
+
id: 'api-layer',
|
|
337
|
+
name: 'API Routes',
|
|
338
|
+
enabled: true,
|
|
339
|
+
color: '#3b82f6',
|
|
340
|
+
items: [{ path: 'auth-server/src/app/api', type: 'directory' as const }],
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
id: 'bruno-layer',
|
|
344
|
+
name: 'Bruno Tests',
|
|
345
|
+
enabled: true,
|
|
346
|
+
color: '#ef4444',
|
|
347
|
+
items: [{ path: 'auth-server/bruno', type: 'directory' as const }],
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: 'S8-single-file',
|
|
353
|
+
name: 'S8: Single File Highlight',
|
|
354
|
+
description: 'Highlight a single file',
|
|
355
|
+
focusDirectory: null,
|
|
356
|
+
highlightLayers: [
|
|
357
|
+
{
|
|
358
|
+
id: 'single-file-layer',
|
|
359
|
+
name: 'Single File',
|
|
360
|
+
enabled: true,
|
|
361
|
+
color: '#ec4899',
|
|
362
|
+
items: [{ path: 'auth-server/src/app/api/auth/workos/callback/route.ts', type: 'file' as const }],
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: 'S9-multiple-files',
|
|
368
|
+
name: 'S9: Multiple Files Highlight',
|
|
369
|
+
description: 'Highlight multiple individual files',
|
|
370
|
+
focusDirectory: null,
|
|
371
|
+
highlightLayers: [
|
|
372
|
+
{
|
|
373
|
+
id: 'files-layer',
|
|
374
|
+
name: 'Selected Files',
|
|
375
|
+
enabled: true,
|
|
376
|
+
color: '#14b8a6',
|
|
377
|
+
items: [
|
|
378
|
+
{ path: 'auth-server/src/app/api/auth/workos/callback/route.ts', type: 'file' as const },
|
|
379
|
+
{ path: 'auth-server/src/app/api/auth/workos/verify/route.ts', type: 'file' as const },
|
|
380
|
+
{ path: 'auth-server/src/app/api/auth/workos/token/route.ts', type: 'file' as const },
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
],
|
|
384
|
+
},
|
|
385
|
+
];
|
|
386
|
+
|
|
387
|
+
export const ScenarioComparison: StoryObj = {
|
|
388
|
+
render: function RenderScenarioComparison() {
|
|
389
|
+
const [currentScenarioIndex, setCurrentScenarioIndex] = useState(0);
|
|
390
|
+
const scenario = testScenarios[currentScenarioIndex];
|
|
391
|
+
const cityData = authServerCityData as CityData;
|
|
392
|
+
|
|
393
|
+
// Base file color layers - resolution will filter these based on highlights/focus
|
|
394
|
+
const fileColorLayers = createFileColorHighlightLayers(cityData.buildings);
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
<div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
398
|
+
{/* Scenario selector */}
|
|
399
|
+
<div
|
|
400
|
+
style={{
|
|
401
|
+
padding: '12px 16px',
|
|
402
|
+
backgroundColor: '#1f2937',
|
|
403
|
+
borderBottom: '1px solid #374151',
|
|
404
|
+
display: 'flex',
|
|
405
|
+
gap: '8px',
|
|
406
|
+
alignItems: 'center',
|
|
407
|
+
flexWrap: 'wrap',
|
|
408
|
+
}}
|
|
409
|
+
>
|
|
410
|
+
<span style={{ color: '#9ca3af', fontSize: '14px', marginRight: '8px' }}>Scenario:</span>
|
|
411
|
+
{testScenarios.map((s, index) => (
|
|
412
|
+
<button
|
|
413
|
+
key={s.id}
|
|
414
|
+
onClick={() => setCurrentScenarioIndex(index)}
|
|
415
|
+
style={{
|
|
416
|
+
padding: '4px 8px',
|
|
417
|
+
borderRadius: '4px',
|
|
418
|
+
border: 'none',
|
|
419
|
+
cursor: 'pointer',
|
|
420
|
+
fontSize: '11px',
|
|
421
|
+
fontWeight: 500,
|
|
422
|
+
backgroundColor: currentScenarioIndex === index ? '#3b82f6' : '#374151',
|
|
423
|
+
color: currentScenarioIndex === index ? '#ffffff' : '#d1d5db',
|
|
424
|
+
}}
|
|
425
|
+
>
|
|
426
|
+
{s.name}
|
|
427
|
+
</button>
|
|
428
|
+
))}
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
{/* Scenario info */}
|
|
432
|
+
<div
|
|
433
|
+
style={{
|
|
434
|
+
padding: '8px 16px',
|
|
435
|
+
backgroundColor: '#111827',
|
|
436
|
+
borderBottom: '1px solid #374151',
|
|
437
|
+
fontSize: '12px',
|
|
438
|
+
color: '#9ca3af',
|
|
439
|
+
}}
|
|
440
|
+
>
|
|
441
|
+
<strong>{scenario.name}</strong>: {scenario.description}
|
|
442
|
+
{scenario.focusDirectory && (
|
|
443
|
+
<span style={{ marginLeft: '12px', color: '#22c55e' }}>
|
|
444
|
+
Focus: {scenario.focusDirectory}
|
|
445
|
+
</span>
|
|
446
|
+
)}
|
|
447
|
+
{scenario.highlightLayers.length > 0 && (
|
|
448
|
+
<span style={{ marginLeft: '12px', color: '#3b82f6' }}>
|
|
449
|
+
Layers: {scenario.highlightLayers.map(l => l.name).join(', ')}
|
|
450
|
+
</span>
|
|
451
|
+
)}
|
|
452
|
+
</div>
|
|
453
|
+
|
|
454
|
+
{/* Side by side comparison */}
|
|
455
|
+
<div style={{ flex: 1, display: 'flex' }}>
|
|
456
|
+
<div
|
|
457
|
+
style={{
|
|
458
|
+
flex: 1,
|
|
459
|
+
borderRight: '1px solid #374151',
|
|
460
|
+
display: 'flex',
|
|
461
|
+
flexDirection: 'column',
|
|
462
|
+
}}
|
|
463
|
+
>
|
|
464
|
+
<div
|
|
465
|
+
style={{
|
|
466
|
+
padding: '8px 12px',
|
|
467
|
+
backgroundColor: '#111827',
|
|
468
|
+
borderBottom: '1px solid #374151',
|
|
469
|
+
color: '#9ca3af',
|
|
470
|
+
fontSize: '12px',
|
|
471
|
+
fontWeight: 500,
|
|
472
|
+
}}
|
|
473
|
+
>
|
|
474
|
+
2D CANVAS
|
|
475
|
+
</div>
|
|
476
|
+
<div style={{ flex: 1, backgroundColor: '#0f1419' }}>
|
|
477
|
+
<ArchitectureMapHighlightLayers
|
|
478
|
+
cityData={cityData}
|
|
479
|
+
highlightLayers={scenario.highlightLayers}
|
|
480
|
+
fileColorLayers={fileColorLayers}
|
|
481
|
+
zoomToPath={scenario.focusDirectory}
|
|
482
|
+
focusColor={scenario.focusColor}
|
|
483
|
+
allowZoomToPath={true}
|
|
484
|
+
zoomAnimationSpeed={0.12}
|
|
485
|
+
fullSize={true}
|
|
486
|
+
canvasBackgroundColor="#0f1419"
|
|
487
|
+
defaultBuildingColor="#36454F"
|
|
488
|
+
defaultDirectoryColor="#111827"
|
|
489
|
+
enableZoom={true}
|
|
490
|
+
/>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
|
|
494
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
|
|
495
|
+
<div
|
|
496
|
+
style={{
|
|
497
|
+
padding: '8px 12px',
|
|
498
|
+
backgroundColor: '#111827',
|
|
499
|
+
borderBottom: '1px solid #374151',
|
|
500
|
+
color: '#9ca3af',
|
|
501
|
+
fontSize: '12px',
|
|
502
|
+
fontWeight: 500,
|
|
503
|
+
}}
|
|
504
|
+
>
|
|
505
|
+
3D
|
|
506
|
+
</div>
|
|
507
|
+
<div style={{ flex: 1, backgroundColor: '#0f1419' }}>
|
|
508
|
+
<FileCity3D
|
|
509
|
+
cityData={cityData}
|
|
510
|
+
highlightLayers={scenario.highlightLayers}
|
|
511
|
+
fileColorLayers={fileColorLayers}
|
|
512
|
+
focusDirectory={scenario.focusDirectory}
|
|
513
|
+
focusColor={scenario.focusColor}
|
|
514
|
+
width="100%"
|
|
515
|
+
height="100%"
|
|
516
|
+
isGrown={true}
|
|
517
|
+
showControls={true}
|
|
518
|
+
backgroundColor="#0f1419"
|
|
519
|
+
/>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
);
|
|
525
|
+
},
|
|
526
|
+
};
|
|
527
|
+
|
|
@@ -6,67 +6,69 @@ import {
|
|
|
6
6
|
import { FileInfo } from '@principal-ai/repository-abstraction';
|
|
7
7
|
|
|
8
8
|
// Sample file structure representing a typical project
|
|
9
|
-
|
|
9
|
+
// lineCount is estimated as size / 35 (avg ~35 bytes per line)
|
|
10
|
+
const sampleFileStructure: Array<{ path: string; size: number; lineCount: number }> = [
|
|
10
11
|
// Source files
|
|
11
|
-
{ path: 'src/index.ts', size: 1500 },
|
|
12
|
-
{ path: 'src/App.tsx', size: 3200 },
|
|
13
|
-
{ path: 'src/components/Header.tsx', size: 1800 },
|
|
14
|
-
{ path: 'src/components/Footer.tsx', size: 1200 },
|
|
15
|
-
{ path: 'src/components/Sidebar.tsx', size: 2100 },
|
|
16
|
-
{ path: 'src/components/Card.tsx', size: 900 },
|
|
17
|
-
{ path: 'src/components/Button.tsx', size: 600 },
|
|
18
|
-
{ path: 'src/utils/helpers.ts', size: 2500 },
|
|
19
|
-
{ path: 'src/utils/api.ts', size: 3100 },
|
|
20
|
-
{ path: 'src/utils/validators.ts', size: 1400 },
|
|
21
|
-
{ path: 'src/hooks/useAuth.ts', size: 800 },
|
|
22
|
-
{ path: 'src/hooks/useData.ts', size: 1100 },
|
|
23
|
-
{ path: 'src/styles/main.css', size: 4500 },
|
|
24
|
-
{ path: 'src/styles/components.css', size: 2800 },
|
|
12
|
+
{ path: 'src/index.ts', size: 1500, lineCount: 45 },
|
|
13
|
+
{ path: 'src/App.tsx', size: 3200, lineCount: 95 },
|
|
14
|
+
{ path: 'src/components/Header.tsx', size: 1800, lineCount: 55 },
|
|
15
|
+
{ path: 'src/components/Footer.tsx', size: 1200, lineCount: 35 },
|
|
16
|
+
{ path: 'src/components/Sidebar.tsx', size: 2100, lineCount: 65 },
|
|
17
|
+
{ path: 'src/components/Card.tsx', size: 900, lineCount: 28 },
|
|
18
|
+
{ path: 'src/components/Button.tsx', size: 600, lineCount: 20 },
|
|
19
|
+
{ path: 'src/utils/helpers.ts', size: 2500, lineCount: 75 },
|
|
20
|
+
{ path: 'src/utils/api.ts', size: 3100, lineCount: 92 },
|
|
21
|
+
{ path: 'src/utils/validators.ts', size: 1400, lineCount: 42 },
|
|
22
|
+
{ path: 'src/hooks/useAuth.ts', size: 800, lineCount: 25 },
|
|
23
|
+
{ path: 'src/hooks/useData.ts', size: 1100, lineCount: 34 },
|
|
24
|
+
{ path: 'src/styles/main.css', size: 4500, lineCount: 180 },
|
|
25
|
+
{ path: 'src/styles/components.css', size: 2800, lineCount: 112 },
|
|
25
26
|
|
|
26
27
|
// Test files
|
|
27
|
-
{ path: 'tests/unit/app.test.ts', size: 2200 },
|
|
28
|
-
{ path: 'tests/unit/header.test.ts', size: 1600 },
|
|
29
|
-
{ path: 'tests/unit/footer.test.tsx', size: 1400 },
|
|
30
|
-
{ path: 'tests/integration/api.test.ts', size: 3400 },
|
|
31
|
-
{ path: '__tests__/components.test.tsx', size: 2900 },
|
|
32
|
-
{ path: '__tests__/utils.test.ts', size: 1900 },
|
|
28
|
+
{ path: 'tests/unit/app.test.ts', size: 2200, lineCount: 68 },
|
|
29
|
+
{ path: 'tests/unit/header.test.ts', size: 1600, lineCount: 50 },
|
|
30
|
+
{ path: 'tests/unit/footer.test.tsx', size: 1400, lineCount: 44 },
|
|
31
|
+
{ path: 'tests/integration/api.test.ts', size: 3400, lineCount: 105 },
|
|
32
|
+
{ path: '__tests__/components.test.tsx', size: 2900, lineCount: 90 },
|
|
33
|
+
{ path: '__tests__/utils.test.ts', size: 1900, lineCount: 58 },
|
|
33
34
|
|
|
34
35
|
// Config files
|
|
35
|
-
{ path: 'package.json', size: 1200 },
|
|
36
|
-
{ path: 'tsconfig.json', size: 800 },
|
|
37
|
-
{ path: 'webpack.config.js', size: 2100 },
|
|
38
|
-
{ path: '.eslintrc.js', size: 600 },
|
|
39
|
-
{ path: '.prettierrc', size: 200 },
|
|
40
|
-
{ path: 'README.md', size: 3500 },
|
|
36
|
+
{ path: 'package.json', size: 1200, lineCount: 45 },
|
|
37
|
+
{ path: 'tsconfig.json', size: 800, lineCount: 30 },
|
|
38
|
+
{ path: 'webpack.config.js', size: 2100, lineCount: 65 },
|
|
39
|
+
{ path: '.eslintrc.js', size: 600, lineCount: 22 },
|
|
40
|
+
{ path: '.prettierrc', size: 200, lineCount: 8 },
|
|
41
|
+
{ path: 'README.md', size: 3500, lineCount: 120 },
|
|
41
42
|
|
|
42
43
|
// Documentation
|
|
43
|
-
{ path: 'docs/README.md', size: 4200 },
|
|
44
|
-
{ path: 'docs/API.md', size: 5100 },
|
|
45
|
-
{ path: 'docs/CONTRIBUTING.md', size: 2300 },
|
|
44
|
+
{ path: 'docs/README.md', size: 4200, lineCount: 140 },
|
|
45
|
+
{ path: 'docs/API.md', size: 5100, lineCount: 170 },
|
|
46
|
+
{ path: 'docs/CONTRIBUTING.md', size: 2300, lineCount: 80 },
|
|
46
47
|
|
|
47
48
|
// Build files
|
|
48
|
-
{ path: 'dist/bundle.js', size: 45000 },
|
|
49
|
-
{ path: 'dist/index.html', size: 800 },
|
|
50
|
-
{ path: 'dist/styles.css', size: 12000 },
|
|
49
|
+
{ path: 'dist/bundle.js', size: 45000, lineCount: 1500 },
|
|
50
|
+
{ path: 'dist/index.html', size: 800, lineCount: 30 },
|
|
51
|
+
{ path: 'dist/styles.css', size: 12000, lineCount: 480 },
|
|
51
52
|
|
|
52
53
|
// Node modules (sample)
|
|
53
|
-
{ path: 'node_modules/react/index.js', size: 8000 },
|
|
54
|
-
{ path: 'node_modules/react/package.json', size: 1500 },
|
|
55
|
-
{ path: 'node_modules/typescript/lib/typescript.js', size: 65000 },
|
|
56
|
-
{ path: 'node_modules/@types/react/index.d.ts', size: 3200 },
|
|
54
|
+
{ path: 'node_modules/react/index.js', size: 8000, lineCount: 250 },
|
|
55
|
+
{ path: 'node_modules/react/package.json', size: 1500, lineCount: 55 },
|
|
56
|
+
{ path: 'node_modules/typescript/lib/typescript.js', size: 65000, lineCount: 2200 },
|
|
57
|
+
{ path: 'node_modules/@types/react/index.d.ts', size: 3200, lineCount: 100 },
|
|
57
58
|
|
|
58
59
|
// Deprecated files
|
|
59
|
-
{ path: 'src/deprecated/OldComponent.tsx', size: 2400 },
|
|
60
|
-
{ path: 'src/deprecated/LegacyAPI.ts', size: 3100 },
|
|
60
|
+
{ path: 'src/deprecated/OldComponent.tsx', size: 2400, lineCount: 72 },
|
|
61
|
+
{ path: 'src/deprecated/LegacyAPI.ts', size: 3100, lineCount: 95 },
|
|
61
62
|
];
|
|
62
63
|
|
|
63
64
|
// Convert file structure to FileInfo objects
|
|
64
|
-
function createFileInfoList(files: Array<{ path: string; size: number }>): FileInfo[] {
|
|
65
|
+
function createFileInfoList(files: Array<{ path: string; size: number; lineCount: number }>): FileInfo[] {
|
|
65
66
|
return files.map(file => ({
|
|
66
67
|
name: file.path.split('/').pop() || file.path,
|
|
67
68
|
path: file.path,
|
|
68
69
|
relativePath: file.path,
|
|
69
70
|
size: file.size,
|
|
71
|
+
lineCount: file.lineCount,
|
|
70
72
|
extension: file.path.includes('.') ? '.' + (file.path.split('.').pop() || '') : '',
|
|
71
73
|
lastModified: new Date(),
|
|
72
74
|
isDirectory: false,
|
|
@@ -99,11 +101,11 @@ export function createSampleCityData(): CityData {
|
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
// Smaller sample file structure
|
|
102
|
-
const smallFileStructure: Array<{ path: string; size: number }> = [
|
|
103
|
-
{ path: 'src/index.ts', size: 1500 },
|
|
104
|
-
{ path: 'src/App.tsx', size: 3200 },
|
|
105
|
-
{ path: 'src/utils/helpers.ts', size: 800 },
|
|
106
|
-
{ path: 'package.json', size: 1200 },
|
|
104
|
+
const smallFileStructure: Array<{ path: string; size: number; lineCount: number }> = [
|
|
105
|
+
{ path: 'src/index.ts', size: 1500, lineCount: 45 },
|
|
106
|
+
{ path: 'src/App.tsx', size: 3200, lineCount: 95 },
|
|
107
|
+
{ path: 'src/utils/helpers.ts', size: 800, lineCount: 25 },
|
|
108
|
+
{ path: 'package.json', size: 1200, lineCount: 45 },
|
|
107
109
|
];
|
|
108
110
|
|
|
109
111
|
let cachedSmallCityData: CityData | null = null;
|