@principal-ai/file-city-react 0.4.4 → 0.4.6
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/CityViewWithReactFlow.d.ts.map +1 -1
- package/dist/components/CityViewWithReactFlow.js +2 -1
- package/dist/config/files.json +16 -0
- package/dist/render/client/drawLayeredBuildings.d.ts +1 -0
- package/dist/render/client/drawLayeredBuildings.d.ts.map +1 -1
- package/dist/render/client/drawLayeredBuildings.js +24 -46
- package/dist/stories/sample-data.d.ts.map +1 -1
- package/dist/stories/stress-test-data.d.ts.map +1 -1
- package/dist/stories/stress-test-data.js +4 -3
- package/dist/utils/fileColorHighlightLayers.d.ts +1 -0
- package/dist/utils/fileColorHighlightLayers.d.ts.map +1 -1
- package/dist/utils/fileColorHighlightLayers.js +23 -9
- package/dist/utils/lucideIconConverter.d.ts +31 -0
- package/dist/utils/lucideIconConverter.d.ts.map +1 -0
- package/dist/utils/lucideIconConverter.js +119 -0
- package/package.json +4 -2
- package/src/components/CityViewWithReactFlow.tsx +3 -1
- package/src/render/client/drawLayeredBuildings.ts +28 -57
- package/src/stories/AllFileTypes.stories.tsx +362 -0
- package/src/stories/ArchitectureMapHighlightLayers.stories.tsx +1 -1
- package/src/stories/CityViewWithReactFlow.stories.tsx +1 -0
- package/src/stories/StressTest.stories.tsx +0 -4
- package/src/stories/sample-data.ts +3 -13
- package/src/stories/stress-test-data.ts +6 -15
- package/src/utils/fileColorHighlightLayers.ts +27 -6
- package/src/utils/lucideIconConverter.tsx +138 -0
- package/src/config/files.json +0 -996
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { ArchitectureMapHighlightLayers } from '../components/ArchitectureMapHighlightLayers';
|
|
4
|
+
import { CodeCityBuilderWithGrid, buildFileSystemTreeFromFileInfoList } from '@principal-ai/file-city-builder';
|
|
5
|
+
import { createFileColorHighlightLayers } from '../utils/fileColorHighlightLayers';
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: 'Showcase/All File Types',
|
|
9
|
+
component: ArchitectureMapHighlightLayers,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'fullscreen',
|
|
12
|
+
},
|
|
13
|
+
decorators: [
|
|
14
|
+
Story => (
|
|
15
|
+
<div style={{ width: '100vw', height: '100vh', backgroundColor: '#1a1a1a' }}>
|
|
16
|
+
<Story />
|
|
17
|
+
</div>
|
|
18
|
+
),
|
|
19
|
+
],
|
|
20
|
+
} satisfies Meta<typeof ArchitectureMapHighlightLayers>;
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof meta>;
|
|
24
|
+
|
|
25
|
+
// Comprehensive list of file types with examples
|
|
26
|
+
const allFileTypes = [
|
|
27
|
+
// Frontend
|
|
28
|
+
{ path: 'frontend/typescript/index.ts', size: 1500 },
|
|
29
|
+
{ path: 'frontend/typescript/App.tsx', size: 3200 },
|
|
30
|
+
{ path: 'frontend/javascript/script.js', size: 1200 },
|
|
31
|
+
{ path: 'frontend/javascript/Component.jsx', size: 1800 },
|
|
32
|
+
{ path: 'frontend/html/index.html', size: 2000 },
|
|
33
|
+
{ path: 'frontend/css/styles.css', size: 1500 },
|
|
34
|
+
{ path: 'frontend/scss/main.scss', size: 1700 },
|
|
35
|
+
{ path: 'frontend/sass/theme.sass', size: 1600 },
|
|
36
|
+
{ path: 'frontend/less/layout.less', size: 1400 },
|
|
37
|
+
{ path: 'frontend/vue/Component.vue', size: 2200 },
|
|
38
|
+
{ path: 'frontend/svelte/Widget.svelte', size: 1900 },
|
|
39
|
+
|
|
40
|
+
// Backend
|
|
41
|
+
{ path: 'backend/python/server.py', size: 3500 },
|
|
42
|
+
{ path: 'backend/java/Application.java', size: 4200 },
|
|
43
|
+
{ path: 'backend/go/main.go', size: 2800 },
|
|
44
|
+
{ path: 'backend/rust/lib.rs', size: 3100 },
|
|
45
|
+
{ path: 'backend/php/index.php', size: 2400 },
|
|
46
|
+
{ path: 'backend/ruby/app.rb', size: 2100 },
|
|
47
|
+
{ path: 'backend/csharp/Program.cs', size: 2600 },
|
|
48
|
+
|
|
49
|
+
// Mobile
|
|
50
|
+
{ path: 'mobile/swift/ViewController.swift', size: 2900 },
|
|
51
|
+
{ path: 'mobile/kotlin/MainActivity.kt', size: 3200 },
|
|
52
|
+
{ path: 'mobile/dart/main.dart', size: 2500 },
|
|
53
|
+
{ path: 'mobile/objc/AppDelegate.m', size: 2800 },
|
|
54
|
+
{ path: 'mobile/objcpp/Bridge.mm', size: 2400 },
|
|
55
|
+
|
|
56
|
+
// Systems
|
|
57
|
+
{ path: 'systems/c/main.c', size: 2200 },
|
|
58
|
+
{ path: 'systems/cpp/engine.cpp', size: 3800 },
|
|
59
|
+
{ path: 'systems/headers/types.h', size: 1200 },
|
|
60
|
+
{ path: 'systems/zig/build.zig', size: 1800 },
|
|
61
|
+
{ path: 'systems/zig-config/build.zon', size: 900 },
|
|
62
|
+
|
|
63
|
+
// Testing - NEW with Lucide icons!
|
|
64
|
+
{ path: 'tests/typescript/auth.test.ts', size: 2400 },
|
|
65
|
+
{ path: 'tests/typescript/Login.test.tsx', size: 2800 },
|
|
66
|
+
{ path: 'tests/javascript/utils.test.js', size: 1900 },
|
|
67
|
+
{ path: 'tests/javascript/Button.test.jsx', size: 2100 },
|
|
68
|
+
{ path: 'tests/specs/api.spec.ts', size: 2600 },
|
|
69
|
+
{ path: 'tests/specs/Header.spec.tsx', size: 2300 },
|
|
70
|
+
{ path: 'tests/specs/validation.spec.js', size: 1800 },
|
|
71
|
+
{ path: 'tests/specs/Form.spec.jsx', size: 2000 },
|
|
72
|
+
{ path: 'tests/snapshots/component.snap', size: 3500 },
|
|
73
|
+
|
|
74
|
+
// Data & Config
|
|
75
|
+
{ path: 'config/data.json', size: 1200 },
|
|
76
|
+
{ path: 'config/settings.yaml', size: 1000 },
|
|
77
|
+
{ path: 'config/app.yml', size: 950 },
|
|
78
|
+
{ path: 'config/data.xml', size: 1800 },
|
|
79
|
+
{ path: 'config/Cargo.toml', size: 800 },
|
|
80
|
+
{ path: 'config/nix/default.nix', size: 1400 },
|
|
81
|
+
|
|
82
|
+
// Documentation
|
|
83
|
+
{ path: 'docs/README.md', size: 4200 },
|
|
84
|
+
{ path: 'docs/API.mdx', size: 3800 },
|
|
85
|
+
{ path: 'docs/notes.txt', size: 600 },
|
|
86
|
+
|
|
87
|
+
// Scripts
|
|
88
|
+
{ path: 'scripts/deploy.sh', size: 1500 },
|
|
89
|
+
{ path: 'scripts/setup.bash', size: 1300 },
|
|
90
|
+
{ path: 'scripts/env.zsh', size: 1100 },
|
|
91
|
+
{ path: 'scripts/utils.fish', size: 900 },
|
|
92
|
+
{ path: 'scripts/build.ps1', size: 1700 },
|
|
93
|
+
{ path: 'scripts/tasks.nu', size: 1200 },
|
|
94
|
+
{ path: 'scripts/vim/config.vim', size: 800 },
|
|
95
|
+
{ path: 'scripts/lua/init.lua', size: 1400 },
|
|
96
|
+
{ path: 'scripts/scheme/query.scm', size: 900 },
|
|
97
|
+
|
|
98
|
+
// Database
|
|
99
|
+
{ path: 'database/schema.sql', size: 3200 },
|
|
100
|
+
|
|
101
|
+
// Images
|
|
102
|
+
{ path: 'assets/images/logo.svg', size: 2400 },
|
|
103
|
+
{ path: 'assets/images/hero.png', size: 45000 },
|
|
104
|
+
{ path: 'assets/images/photo.jpg', size: 38000 },
|
|
105
|
+
{ path: 'assets/images/banner.jpeg', size: 42000 },
|
|
106
|
+
{ path: 'assets/images/animation.gif', size: 12000 },
|
|
107
|
+
{ path: 'assets/images/modern.webp', size: 28000 },
|
|
108
|
+
|
|
109
|
+
// Graphics
|
|
110
|
+
{ path: 'shaders/vertex.glsl', size: 1800 },
|
|
111
|
+
{ path: 'shaders/fragment.metal', size: 2100 },
|
|
112
|
+
|
|
113
|
+
// Assets
|
|
114
|
+
{ path: 'fonts/Inter-Regular.ttf', size: 156000 },
|
|
115
|
+
{ path: 'fonts/Inter-Bold.otf', size: 148000 },
|
|
116
|
+
{ path: 'fonts/Roboto-Regular.woff', size: 82000 },
|
|
117
|
+
{ path: 'fonts/Roboto-Bold.woff2', size: 76000 },
|
|
118
|
+
|
|
119
|
+
// Apple/iOS
|
|
120
|
+
{ path: 'ios/Interface.xib', size: 4200 },
|
|
121
|
+
{ path: 'ios/Info.plist', size: 1200 },
|
|
122
|
+
{ path: 'ios/App.entitlements', size: 800 },
|
|
123
|
+
|
|
124
|
+
// Other
|
|
125
|
+
{ path: 'analytics/analysis.r', size: 2800 },
|
|
126
|
+
{ path: 'data/visualization.canvas', size: 1500 },
|
|
127
|
+
{ path: 'special/LICENSE', size: 1100 },
|
|
128
|
+
|
|
129
|
+
// Lock files
|
|
130
|
+
{ path: 'package-lock.json', size: 256000 },
|
|
131
|
+
{ path: 'Cargo.lock', size: 45000 },
|
|
132
|
+
{ path: 'yarn.lock', size: 128000 },
|
|
133
|
+
|
|
134
|
+
// Config files (exact names)
|
|
135
|
+
{ path: '.gitignore', size: 600 },
|
|
136
|
+
{ path: '.dockerignore', size: 400 },
|
|
137
|
+
{ path: '.npmignore', size: 300 },
|
|
138
|
+
{ path: '.eslintignore', size: 250 },
|
|
139
|
+
{ path: '.prettierignore', size: 200 },
|
|
140
|
+
{ path: '.bashrc', size: 1800 },
|
|
141
|
+
{ path: '.zshrc', size: 2200 },
|
|
142
|
+
{ path: '.vimrc', size: 3500 },
|
|
143
|
+
{ path: '.npmrc', size: 400 },
|
|
144
|
+
{ path: '.eslintrc', size: 800 },
|
|
145
|
+
{ path: '.prettierrc', size: 300 },
|
|
146
|
+
{ path: '.babelrc', size: 500 },
|
|
147
|
+
|
|
148
|
+
// GTK
|
|
149
|
+
{ path: 'ui/window.blp', size: 2100 },
|
|
150
|
+
|
|
151
|
+
// Localization
|
|
152
|
+
{ path: 'locales/en.po', size: 4500 },
|
|
153
|
+
{ path: 'locales/template.pot', size: 3800 },
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
// Create city data from file types
|
|
157
|
+
function createAllFileTypesCityData() {
|
|
158
|
+
const fileInfos = allFileTypes.map(({ path, size }) => {
|
|
159
|
+
const lastSlash = path.lastIndexOf('/');
|
|
160
|
+
const name = lastSlash === -1 ? path : path.substring(lastSlash + 1);
|
|
161
|
+
const lastDot = name.lastIndexOf('.');
|
|
162
|
+
const extension = lastDot === -1 ? '' : name.substring(lastDot);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
name,
|
|
166
|
+
path,
|
|
167
|
+
relativePath: path,
|
|
168
|
+
size,
|
|
169
|
+
extension,
|
|
170
|
+
lastModified: new Date('2025-01-26'),
|
|
171
|
+
isDirectory: false,
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos);
|
|
176
|
+
const builder = new CodeCityBuilderWithGrid();
|
|
177
|
+
return builder.buildCityFromFileSystem(fileTree, '', {
|
|
178
|
+
paddingTop: 2,
|
|
179
|
+
paddingBottom: 2,
|
|
180
|
+
paddingLeft: 2,
|
|
181
|
+
paddingRight: 2,
|
|
182
|
+
paddingInner: 1,
|
|
183
|
+
paddingOuter: 3,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Story showing all file types with color coding
|
|
188
|
+
export const AllFileTypesWithColors: Story = {
|
|
189
|
+
render: function RenderAllFileTypes() {
|
|
190
|
+
const cityData = createAllFileTypesCityData();
|
|
191
|
+
const highlightLayers = createFileColorHighlightLayers(cityData.buildings);
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
|
|
195
|
+
<ArchitectureMapHighlightLayers
|
|
196
|
+
cityData={cityData}
|
|
197
|
+
highlightLayers={highlightLayers}
|
|
198
|
+
showLayerControls={true}
|
|
199
|
+
fullSize={true}
|
|
200
|
+
canvasBackgroundColor="#0a0a0a"
|
|
201
|
+
defaultBuildingColor="#36454F"
|
|
202
|
+
defaultDirectoryColor="#1a1a1a"
|
|
203
|
+
enableZoom={true}
|
|
204
|
+
buildingBorderRadius={2}
|
|
205
|
+
districtBorderRadius={4}
|
|
206
|
+
/>
|
|
207
|
+
<div
|
|
208
|
+
style={{
|
|
209
|
+
position: 'absolute',
|
|
210
|
+
top: 20,
|
|
211
|
+
right: 20,
|
|
212
|
+
backgroundColor: 'rgba(0, 0, 0, 0.85)',
|
|
213
|
+
padding: '16px',
|
|
214
|
+
borderRadius: '8px',
|
|
215
|
+
color: 'white',
|
|
216
|
+
fontFamily: 'monospace',
|
|
217
|
+
fontSize: '12px',
|
|
218
|
+
maxWidth: '300px',
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
<div style={{ fontWeight: 'bold', marginBottom: '8px', color: '#10b981' }}>
|
|
222
|
+
📁 All File Types Showcase
|
|
223
|
+
</div>
|
|
224
|
+
<div style={{ color: '#9ca3af', fontSize: '11px', lineHeight: '1.5' }}>
|
|
225
|
+
This story demonstrates all {allFileTypes.length} supported file types with their colors
|
|
226
|
+
and icons.
|
|
227
|
+
<br />
|
|
228
|
+
<br />
|
|
229
|
+
🧪 Test files (.test.*, .spec.*) now have Lucide icons!
|
|
230
|
+
<br />
|
|
231
|
+
<br />
|
|
232
|
+
Use the layer controls on the left to filter by file type.
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Story focusing on test files with icons
|
|
241
|
+
export const TestFilesWithIcons: Story = {
|
|
242
|
+
render: function RenderTestFiles() {
|
|
243
|
+
const testFiles = allFileTypes.filter(
|
|
244
|
+
f => f.path.includes('.test.') || f.path.includes('.spec.') || f.path.includes('.snap'),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const fileInfos = testFiles.map(({ path, size }) => {
|
|
248
|
+
const lastSlash = path.lastIndexOf('/');
|
|
249
|
+
const name = lastSlash === -1 ? path : path.substring(lastSlash + 1);
|
|
250
|
+
const lastDot = name.lastIndexOf('.');
|
|
251
|
+
const extension = lastDot === -1 ? '' : name.substring(lastDot);
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
name,
|
|
255
|
+
path,
|
|
256
|
+
relativePath: path,
|
|
257
|
+
size,
|
|
258
|
+
extension,
|
|
259
|
+
lastModified: new Date('2025-01-26'),
|
|
260
|
+
isDirectory: false,
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos);
|
|
265
|
+
const builder = new CodeCityBuilderWithGrid();
|
|
266
|
+
const cityData = builder.buildCityFromFileSystem(fileTree, '', {
|
|
267
|
+
paddingTop: 2,
|
|
268
|
+
paddingBottom: 2,
|
|
269
|
+
paddingLeft: 2,
|
|
270
|
+
paddingRight: 2,
|
|
271
|
+
paddingInner: 1,
|
|
272
|
+
paddingOuter: 3,
|
|
273
|
+
});
|
|
274
|
+
const highlightLayers = createFileColorHighlightLayers(cityData.buildings);
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
|
|
278
|
+
<ArchitectureMapHighlightLayers
|
|
279
|
+
cityData={cityData}
|
|
280
|
+
highlightLayers={highlightLayers}
|
|
281
|
+
showLayerControls={true}
|
|
282
|
+
fullSize={true}
|
|
283
|
+
canvasBackgroundColor="#0a0a0a"
|
|
284
|
+
defaultBuildingColor="#36454F"
|
|
285
|
+
defaultDirectoryColor="#1a1a1a"
|
|
286
|
+
enableZoom={true}
|
|
287
|
+
buildingBorderRadius={3}
|
|
288
|
+
/>
|
|
289
|
+
<div
|
|
290
|
+
style={{
|
|
291
|
+
position: 'absolute',
|
|
292
|
+
top: 20,
|
|
293
|
+
right: 20,
|
|
294
|
+
backgroundColor: 'rgba(0, 0, 0, 0.85)',
|
|
295
|
+
padding: '20px',
|
|
296
|
+
borderRadius: '8px',
|
|
297
|
+
color: 'white',
|
|
298
|
+
fontFamily: 'monospace',
|
|
299
|
+
fontSize: '12px',
|
|
300
|
+
maxWidth: '320px',
|
|
301
|
+
}}
|
|
302
|
+
>
|
|
303
|
+
<div style={{ fontWeight: 'bold', marginBottom: '12px', fontSize: '14px' }}>
|
|
304
|
+
🧪 Test Files with Lucide Icons
|
|
305
|
+
</div>
|
|
306
|
+
<div style={{ color: '#9ca3af', fontSize: '11px', lineHeight: '1.6', marginBottom: '12px' }}>
|
|
307
|
+
Test files now feature professional SVG icons from the Lucide library:
|
|
308
|
+
</div>
|
|
309
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
310
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
311
|
+
<div
|
|
312
|
+
style={{
|
|
313
|
+
width: '12px',
|
|
314
|
+
height: '12px',
|
|
315
|
+
backgroundColor: '#10b981',
|
|
316
|
+
borderRadius: '2px',
|
|
317
|
+
}}
|
|
318
|
+
/>
|
|
319
|
+
<span style={{ color: '#10b981' }}>TestTube icon</span>
|
|
320
|
+
<span style={{ color: '#6b7280' }}>.test.*</span>
|
|
321
|
+
</div>
|
|
322
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
323
|
+
<div
|
|
324
|
+
style={{
|
|
325
|
+
width: '12px',
|
|
326
|
+
height: '12px',
|
|
327
|
+
backgroundColor: '#059669',
|
|
328
|
+
borderRadius: '2px',
|
|
329
|
+
}}
|
|
330
|
+
/>
|
|
331
|
+
<span style={{ color: '#059669' }}>FlaskConical</span>
|
|
332
|
+
<span style={{ color: '#6b7280' }}>.spec.*</span>
|
|
333
|
+
</div>
|
|
334
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
335
|
+
<div
|
|
336
|
+
style={{
|
|
337
|
+
width: '12px',
|
|
338
|
+
height: '12px',
|
|
339
|
+
backgroundColor: '#9d4edd',
|
|
340
|
+
borderRadius: '2px',
|
|
341
|
+
}}
|
|
342
|
+
/>
|
|
343
|
+
<span style={{ color: '#9d4edd' }}>Snapshot</span>
|
|
344
|
+
<span style={{ color: '#6b7280' }}>.snap</span>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
<div
|
|
348
|
+
style={{
|
|
349
|
+
marginTop: '12px',
|
|
350
|
+
paddingTop: '12px',
|
|
351
|
+
borderTop: '1px solid #374151',
|
|
352
|
+
color: '#9ca3af',
|
|
353
|
+
fontSize: '10px',
|
|
354
|
+
}}
|
|
355
|
+
>
|
|
356
|
+
💡 Zoom in to see the icons clearly
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
},
|
|
362
|
+
};
|
|
@@ -17,11 +17,7 @@ function StressTestWrapper({
|
|
|
17
17
|
const [isAnimating, setIsAnimating] = useState(false);
|
|
18
18
|
|
|
19
19
|
const cityData = useMemo(() => {
|
|
20
|
-
console.log(`Generating city data for ${fileCount} files...`);
|
|
21
|
-
const start = performance.now();
|
|
22
20
|
const data = createStressTestCityData(fileCount, true);
|
|
23
|
-
const elapsed = performance.now() - start;
|
|
24
|
-
console.log(`Generated in ${elapsed.toFixed(2)}ms`);
|
|
25
21
|
return data;
|
|
26
22
|
}, [fileCount]);
|
|
27
23
|
|
|
@@ -3,17 +3,7 @@ import {
|
|
|
3
3
|
CodeCityBuilderWithGrid,
|
|
4
4
|
buildFileSystemTreeFromFileInfoList,
|
|
5
5
|
} from '@principal-ai/file-city-builder';
|
|
6
|
-
|
|
7
|
-
// File info structure for building file trees
|
|
8
|
-
interface FileInfo {
|
|
9
|
-
name: string;
|
|
10
|
-
path: string;
|
|
11
|
-
relativePath: string;
|
|
12
|
-
size: number;
|
|
13
|
-
extension: string;
|
|
14
|
-
lastModified: Date;
|
|
15
|
-
isDirectory: boolean;
|
|
16
|
-
}
|
|
6
|
+
import { FileInfo } from '@principal-ai/repository-abstraction';
|
|
17
7
|
|
|
18
8
|
// Sample file structure representing a typical project
|
|
19
9
|
const sampleFileStructure: Array<{ path: string; size: number }> = [
|
|
@@ -93,7 +83,7 @@ export function createSampleCityData(): CityData {
|
|
|
93
83
|
}
|
|
94
84
|
|
|
95
85
|
const fileInfos = createFileInfoList(sampleFileStructure);
|
|
96
|
-
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos
|
|
86
|
+
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos, 'sample-project');
|
|
97
87
|
const builder = new CodeCityBuilderWithGrid();
|
|
98
88
|
|
|
99
89
|
cachedCityData = builder.buildCityFromFileSystem(fileTree, '', {
|
|
@@ -125,7 +115,7 @@ export function createSmallSampleCityData(): CityData {
|
|
|
125
115
|
}
|
|
126
116
|
|
|
127
117
|
const fileInfos = createFileInfoList(smallFileStructure);
|
|
128
|
-
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos
|
|
118
|
+
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos, 'small-sample');
|
|
129
119
|
const builder = new CodeCityBuilderWithGrid();
|
|
130
120
|
|
|
131
121
|
cachedSmallCityData = builder.buildCityFromFileSystem(fileTree, '', {
|
|
@@ -3,23 +3,11 @@ import {
|
|
|
3
3
|
CodeCityBuilderWithGrid,
|
|
4
4
|
buildFileSystemTreeFromFileInfoList,
|
|
5
5
|
} from '@principal-ai/file-city-builder';
|
|
6
|
-
|
|
7
|
-
interface FileInfo {
|
|
8
|
-
name: string;
|
|
9
|
-
path: string;
|
|
10
|
-
relativePath: string;
|
|
11
|
-
size: number;
|
|
12
|
-
extension: string;
|
|
13
|
-
lastModified: Date;
|
|
14
|
-
isDirectory: boolean;
|
|
15
|
-
}
|
|
6
|
+
import { FileInfo } from '@principal-ai/repository-abstraction';
|
|
16
7
|
|
|
17
8
|
// Common file extensions for realistic distribution
|
|
18
9
|
const FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.css', '.json', '.md', '.test.ts', '.spec.tsx'];
|
|
19
10
|
|
|
20
|
-
// Top-level source directories
|
|
21
|
-
const TOP_LEVEL_DIRS = ['src', 'lib', 'packages', 'modules'];
|
|
22
|
-
|
|
23
11
|
// Second-level directories (domain areas)
|
|
24
12
|
const DOMAIN_DIRS = ['components', 'utils', 'services', 'hooks', 'types', 'helpers', 'core', 'api', 'features', 'pages'];
|
|
25
13
|
|
|
@@ -144,12 +132,15 @@ const stressTestCache = new Map<number, CityData>();
|
|
|
144
132
|
*/
|
|
145
133
|
export function createStressTestCityData(fileCount: number = 8000, useCache: boolean = true): CityData {
|
|
146
134
|
if (useCache && stressTestCache.has(fileCount)) {
|
|
147
|
-
|
|
135
|
+
const cached = stressTestCache.get(fileCount);
|
|
136
|
+
if (cached) {
|
|
137
|
+
return cached;
|
|
138
|
+
}
|
|
148
139
|
}
|
|
149
140
|
|
|
150
141
|
const filePaths = generateLargeFilePaths(fileCount);
|
|
151
142
|
const fileInfos = createFileInfoList(filePaths);
|
|
152
|
-
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos
|
|
143
|
+
const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos, `stress-test-${fileCount}`);
|
|
153
144
|
|
|
154
145
|
const builder = new CodeCityBuilderWithGrid();
|
|
155
146
|
const cityData = builder.buildCityFromFileSystem(fileTree, '', {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { defaultFileColorConfig } from '@principal-ai/file-city-builder';
|
|
2
2
|
import {
|
|
3
3
|
HighlightLayer,
|
|
4
4
|
LayerItem,
|
|
@@ -21,6 +21,7 @@ export interface ColorLayerConfig {
|
|
|
21
21
|
borderRadius?: number;
|
|
22
22
|
icon?: string;
|
|
23
23
|
iconSize?: number;
|
|
24
|
+
lucideIcon?: string;
|
|
24
25
|
};
|
|
25
26
|
customRender?: (
|
|
26
27
|
ctx: CanvasRenderingContext2D,
|
|
@@ -85,7 +86,7 @@ export function createFileColorHighlightLayers(
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
// Use provided config or fall back to default from files.json
|
|
88
|
-
const colorConfig = config || (
|
|
89
|
+
const colorConfig = config || (defaultFileColorConfig as FileSuffixColorConfig);
|
|
89
90
|
|
|
90
91
|
const { suffixConfigs, defaultConfig: defaultFileConfig, includeUnmatched = true } = colorConfig;
|
|
91
92
|
|
|
@@ -104,7 +105,6 @@ export function createFileColorHighlightLayers(
|
|
|
104
105
|
const filePath = file.path;
|
|
105
106
|
const lastSlash = filePath.lastIndexOf('/');
|
|
106
107
|
const fileName = lastSlash === -1 ? filePath : filePath.substring(lastSlash + 1);
|
|
107
|
-
const lastDot = fileName.lastIndexOf('.');
|
|
108
108
|
|
|
109
109
|
// Check for exact filename match first (e.g., LICENSE, Makefile)
|
|
110
110
|
if (suffixConfigs[fileName]) {
|
|
@@ -118,6 +118,7 @@ export function createFileColorHighlightLayers(
|
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
const lastDot = fileName.lastIndexOf('.');
|
|
121
122
|
if (lastDot === -1 || lastDot === fileName.length - 1) {
|
|
122
123
|
// No extension or ends with dot
|
|
123
124
|
if (includeUnmatched) {
|
|
@@ -126,7 +127,27 @@ export function createFileColorHighlightLayers(
|
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
// Check for compound extensions first (e.g., .test.ts, .spec.tsx, .d.ts)
|
|
131
|
+
// Look for patterns like .test.ts, .spec.js, etc.
|
|
132
|
+
let extension: string | null = null;
|
|
133
|
+
const lowerFileName = fileName.toLowerCase();
|
|
134
|
+
|
|
135
|
+
// Sort suffixes by length (longest first) to match compound extensions before simple ones
|
|
136
|
+
// e.g., .test.ts should be checked before .ts
|
|
137
|
+
const sortedSuffixes = Object.keys(suffixConfigs).sort((a, b) => b.length - a.length);
|
|
138
|
+
|
|
139
|
+
// Check if any suffix config matches as a suffix of the filename
|
|
140
|
+
for (const suffix of sortedSuffixes) {
|
|
141
|
+
if (lowerFileName.endsWith(suffix)) {
|
|
142
|
+
extension = suffix;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Fallback to simple extension if no compound match found
|
|
148
|
+
if (!extension) {
|
|
149
|
+
extension = fileName.substring(lastDot).toLowerCase();
|
|
150
|
+
}
|
|
130
151
|
|
|
131
152
|
if (suffixConfigs[extension]) {
|
|
132
153
|
if (!filesBySuffix.has(extension)) {
|
|
@@ -359,7 +380,7 @@ export function createFileColorHighlightLayers(
|
|
|
359
380
|
* This returns the configuration loaded from files.json.
|
|
360
381
|
*/
|
|
361
382
|
export function getDefaultFileColorConfig(): FileSuffixColorConfig {
|
|
362
|
-
return
|
|
383
|
+
return defaultFileColorConfig as FileSuffixColorConfig;
|
|
363
384
|
}
|
|
364
385
|
|
|
365
386
|
/**
|
|
@@ -370,7 +391,7 @@ export function getDefaultFileColorConfig(): FileSuffixColorConfig {
|
|
|
370
391
|
* @returns Record mapping file extensions to hex color strings
|
|
371
392
|
*/
|
|
372
393
|
export function getFileColorMapping(config?: FileSuffixColorConfig): Record<string, string> {
|
|
373
|
-
const colorConfig = config || (
|
|
394
|
+
const colorConfig = config || (defaultFileColorConfig as FileSuffixColorConfig);
|
|
374
395
|
return Object.entries(colorConfig.suffixConfigs).reduce((acc, [extension, suffixConfig]) => {
|
|
375
396
|
acc[extension] = suffixConfig.primary.color;
|
|
376
397
|
return acc;
|