@principal-ai/file-city-react 0.5.42 → 0.5.44
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/FileCity3D/FileCity3D.d.ts +70 -2
- package/dist/components/FileCity3D/FileCity3D.d.ts.map +1 -1
- package/dist/components/FileCity3D/FileCity3D.js +164 -54
- package/dist/components/FileCity3D/index.d.ts +1 -1
- package/dist/components/FileCity3D/index.d.ts.map +1 -1
- package/dist/components/FileCityExplorer/FileCityExplorer.d.ts.map +1 -1
- package/dist/components/FileCityExplorer/FileCityExplorer.js +1 -31
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/FileCity3D/FileCity3D.tsx +437 -137
- package/src/components/FileCity3D/index.ts +2 -0
- package/src/components/FileCityExplorer/FileCityExplorer.tsx +2 -30
- package/src/index.ts +1 -0
- package/src/stories/ElevatedScopePanels.stories.tsx +72 -27
- package/src/stories/FileCityExplorer.stories.tsx +2 -29
- package/src/stories/HighlightLayersFlatDebug.stories.tsx +319 -0
- package/src/stories/LeaderLineSnippetOverlay.stories.tsx +725 -137
- package/src/stories/LeaderLineSnippetOverlay3D.stories.tsx +1060 -0
|
@@ -27,6 +27,7 @@ export type {
|
|
|
27
27
|
HeightScaling,
|
|
28
28
|
FlatPattern,
|
|
29
29
|
ElevatedScopePanel,
|
|
30
|
+
SelectionStyle,
|
|
30
31
|
CityData,
|
|
31
32
|
CityBuilding,
|
|
32
33
|
CityDistrict,
|
|
@@ -35,4 +36,5 @@ export type {
|
|
|
35
36
|
TouchOneAction,
|
|
36
37
|
TouchTwoAction,
|
|
37
38
|
WheelAction,
|
|
39
|
+
OnCameraFrame,
|
|
38
40
|
} from './FileCity3D';
|
|
@@ -564,47 +564,17 @@ export const FileCityExplorer: React.FC<FileCityExplorerProps> = ({
|
|
|
564
564
|
const displayLabel = folderPath ? areaNameByCityPath.get(folderPath) : undefined;
|
|
565
565
|
return displayLabel ? { ...panel, displayLabel } : panel;
|
|
566
566
|
});
|
|
567
|
-
// Selection indicator: render a thin, slightly-larger panel underneath
|
|
568
|
-
// the selected folder's umbrella so an accent ring peeks out around its
|
|
569
|
-
// edges. Inserted *before* the umbrella in the list so the umbrella
|
|
570
|
-
// draws on top — only the inflated rim shows. If the folder is expanded
|
|
571
|
-
// (no umbrella in the panel list) findIndex returns -1 and no ring is
|
|
572
|
-
// drawn, which is exactly what we want.
|
|
573
|
-
if (selectedPanelFolder) {
|
|
574
|
-
const idx = panels.findIndex(p => p.id === `folder::${selectedPanelFolder}`);
|
|
575
|
-
if (idx >= 0) {
|
|
576
|
-
const target = panels[idx];
|
|
577
|
-
const inflate = 4;
|
|
578
|
-
const border: ElevatedScopePanel = {
|
|
579
|
-
id: `folder-border::${selectedPanelFolder}`,
|
|
580
|
-
color: theme.colors.warning,
|
|
581
|
-
height: (target.height ?? 4) - 2,
|
|
582
|
-
thickness: 1,
|
|
583
|
-
bounds: {
|
|
584
|
-
minX: target.bounds.minX - inflate,
|
|
585
|
-
maxX: target.bounds.maxX + inflate,
|
|
586
|
-
minZ: target.bounds.minZ - inflate,
|
|
587
|
-
maxZ: target.bounds.maxZ + inflate,
|
|
588
|
-
},
|
|
589
|
-
};
|
|
590
|
-
const next = [...panels];
|
|
591
|
-
next.splice(idx, 0, border);
|
|
592
|
-
return next;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
567
|
|
|
596
568
|
return panels.length > 0 ? panels : undefined;
|
|
597
569
|
}, [
|
|
598
570
|
activeTab,
|
|
599
571
|
cityData,
|
|
600
|
-
selectedPanelFolder,
|
|
601
572
|
treeModel,
|
|
602
573
|
folderTreeExpansion,
|
|
603
574
|
setFocusDirectoryIfUnpinned,
|
|
604
575
|
areaNameByCityPath,
|
|
605
576
|
folderIndex,
|
|
606
577
|
packageRootClamp,
|
|
607
|
-
theme,
|
|
608
578
|
]);
|
|
609
579
|
|
|
610
580
|
// Cmd-click on a building → surface the chain of expanded ancestor folders
|
|
@@ -829,6 +799,8 @@ export const FileCityExplorer: React.FC<FileCityExplorerProps> = ({
|
|
|
829
799
|
focusDirectory={focusDirectory}
|
|
830
800
|
highlightLayers={cityHighlightLayers}
|
|
831
801
|
elevatedScopePanels={cityElevatedPanels ?? folderElevatedPanels}
|
|
802
|
+
selectedPath={activeTab === 'files' ? selectedPanelFolder : null}
|
|
803
|
+
selectionStyle={{ color: theme.colors.warning }}
|
|
832
804
|
onBuildingClick={handleBuildingClick}
|
|
833
805
|
animation={{
|
|
834
806
|
startFlat: true,
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
1
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -189,7 +190,8 @@ export const RecoloredAndTranslucent: Story = {
|
|
|
189
190
|
};
|
|
190
191
|
|
|
191
192
|
// ---------------------------------------------------------------------------
|
|
192
|
-
// Selection ring
|
|
193
|
+
// Selection ring (now a first-class `selectedPath` prop on FileCity3D —
|
|
194
|
+
// kept here as a regression demo so the panel/ring composition stays visible).
|
|
193
195
|
// ---------------------------------------------------------------------------
|
|
194
196
|
|
|
195
197
|
const SELECTED_FOLDER = 'electron-app/src';
|
|
@@ -198,37 +200,17 @@ const SELECTION_RING_COLOR = '#fbbf24';
|
|
|
198
200
|
export const WithSelectionRing: Story = {
|
|
199
201
|
args: {
|
|
200
202
|
...baseArgs,
|
|
201
|
-
elevatedScopePanels: (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (idx < 0) return panels;
|
|
205
|
-
const target = panels[idx];
|
|
206
|
-
const inflate = 4;
|
|
207
|
-
const ring: ElevatedScopePanel = {
|
|
208
|
-
id: `folder-border::${SELECTED_FOLDER}`,
|
|
209
|
-
color: SELECTION_RING_COLOR,
|
|
210
|
-
height: (target.height ?? 4) - 2,
|
|
211
|
-
thickness: 1,
|
|
212
|
-
bounds: {
|
|
213
|
-
minX: target.bounds.minX - inflate,
|
|
214
|
-
maxX: target.bounds.maxX + inflate,
|
|
215
|
-
minZ: target.bounds.minZ - inflate,
|
|
216
|
-
maxZ: target.bounds.maxZ + inflate,
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
const next = [...panels];
|
|
220
|
-
next.splice(idx, 0, ring);
|
|
221
|
-
return next;
|
|
222
|
-
})(),
|
|
203
|
+
elevatedScopePanels: panelsFor(TOP_LEVEL),
|
|
204
|
+
selectedPath: SELECTED_FOLDER,
|
|
205
|
+
selectionStyle: { color: SELECTION_RING_COLOR },
|
|
223
206
|
},
|
|
224
207
|
parameters: {
|
|
225
208
|
docs: {
|
|
226
209
|
description: {
|
|
227
210
|
story:
|
|
228
|
-
'
|
|
229
|
-
'
|
|
230
|
-
'
|
|
231
|
-
'first so the umbrella draws on top of its centre.',
|
|
211
|
+
'`selectedPath` resolves to a district, so FileCity3D draws the ' +
|
|
212
|
+
'selection ring above the umbrella covering that district. ' +
|
|
213
|
+
'Replaces the older inflate-a-panel-underneath-the-umbrella trick.',
|
|
232
214
|
},
|
|
233
215
|
},
|
|
234
216
|
},
|
|
@@ -293,3 +275,66 @@ export const HandBuiltPanels: Story = {
|
|
|
293
275
|
},
|
|
294
276
|
},
|
|
295
277
|
};
|
|
278
|
+
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
// Cmd-click to dismiss (parent-owned dismiss flow)
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
function DismissOnCommandClickStory() {
|
|
284
|
+
const [panels, setPanels] = useState<ElevatedScopePanel[]>(() =>
|
|
285
|
+
panelsFor(TOP_LEVEL),
|
|
286
|
+
);
|
|
287
|
+
const [dismissingIds, setDismissingIds] = useState<ReadonlySet<string>>(
|
|
288
|
+
() => new Set(),
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const wired = panels.map(panel => ({
|
|
292
|
+
...panel,
|
|
293
|
+
onClick: (event: MouseEvent) => {
|
|
294
|
+
if (!event.metaKey) return;
|
|
295
|
+
setDismissingIds(prev => {
|
|
296
|
+
if (prev.has(panel.id)) return prev;
|
|
297
|
+
const next = new Set(prev);
|
|
298
|
+
next.add(panel.id);
|
|
299
|
+
return next;
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
}));
|
|
303
|
+
|
|
304
|
+
const handleDismissed = useCallback((id: string) => {
|
|
305
|
+
setPanels(prev => prev.filter(p => p.id !== id));
|
|
306
|
+
setDismissingIds(prev => {
|
|
307
|
+
if (!prev.has(id)) return prev;
|
|
308
|
+
const next = new Set(prev);
|
|
309
|
+
next.delete(id);
|
|
310
|
+
return next;
|
|
311
|
+
});
|
|
312
|
+
}, []);
|
|
313
|
+
|
|
314
|
+
return (
|
|
315
|
+
<FileCity3D
|
|
316
|
+
{...baseArgs}
|
|
317
|
+
elevatedScopePanels={wired}
|
|
318
|
+
dismissingPanelIds={dismissingIds}
|
|
319
|
+
onPanelDismissed={handleDismissed}
|
|
320
|
+
/>
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export const DismissOnCommandClick: Story = {
|
|
325
|
+
render: () => <DismissOnCommandClickStory />,
|
|
326
|
+
parameters: {
|
|
327
|
+
docs: {
|
|
328
|
+
description: {
|
|
329
|
+
story:
|
|
330
|
+
'⌘-click (or ctrl-click on non-Mac with `event.metaKey`) a panel ' +
|
|
331
|
+
'to lift it toward the camera and fade it out. The story owns ' +
|
|
332
|
+
'both the `panels` array and a `dismissingIds` set: clicking adds ' +
|
|
333
|
+
'the id to that set, `FileCity3D` plays the spring, and once it ' +
|
|
334
|
+
'settles `onPanelDismissed` fires so the story drops the panel ' +
|
|
335
|
+
'from both pieces of state. The component never owns the ' +
|
|
336
|
+
'truth — it just animates and notifies.',
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
};
|
|
@@ -1570,39 +1570,10 @@ const FileCityExplorerTemplate: React.FC = () => {
|
|
|
1570
1570
|
const displayLabel = folderPath ? areaNameByCityPath.get(folderPath) : undefined;
|
|
1571
1571
|
return displayLabel ? { ...panel, displayLabel } : panel;
|
|
1572
1572
|
});
|
|
1573
|
-
// Selection indicator: render a thin, slightly-larger panel underneath
|
|
1574
|
-
// the selected folder's umbrella so an accent ring peeks out around its
|
|
1575
|
-
// edges. Inserted *before* the umbrella in the list so the umbrella
|
|
1576
|
-
// draws on top — only the inflated rim shows. If the folder is expanded
|
|
1577
|
-
// (no umbrella in the panel list) findIndex returns -1 and no ring is
|
|
1578
|
-
// drawn, which is exactly what we want.
|
|
1579
|
-
if (selectedPanelFolder) {
|
|
1580
|
-
const idx = panels.findIndex(p => p.id === `folder::${selectedPanelFolder}`);
|
|
1581
|
-
if (idx >= 0) {
|
|
1582
|
-
const target = panels[idx];
|
|
1583
|
-
const inflate = 4;
|
|
1584
|
-
const border: ElevatedScopePanel = {
|
|
1585
|
-
id: `folder-border::${selectedPanelFolder}`,
|
|
1586
|
-
color: '#fbbf24',
|
|
1587
|
-
height: (target.height ?? 4) - 2,
|
|
1588
|
-
thickness: 1,
|
|
1589
|
-
bounds: {
|
|
1590
|
-
minX: target.bounds.minX - inflate,
|
|
1591
|
-
maxX: target.bounds.maxX + inflate,
|
|
1592
|
-
minZ: target.bounds.minZ - inflate,
|
|
1593
|
-
maxZ: target.bounds.maxZ + inflate,
|
|
1594
|
-
},
|
|
1595
|
-
};
|
|
1596
|
-
const next = [...panels];
|
|
1597
|
-
next.splice(idx, 0, border);
|
|
1598
|
-
return next;
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
1573
|
|
|
1602
1574
|
return panels.length > 0 ? panels : undefined;
|
|
1603
1575
|
}, [
|
|
1604
1576
|
activeTab,
|
|
1605
|
-
selectedPanelFolder,
|
|
1606
1577
|
treeModel,
|
|
1607
1578
|
folderTreeExpansion,
|
|
1608
1579
|
setFocusDirectoryIfUnpinned,
|
|
@@ -1829,6 +1800,8 @@ const FileCityExplorerTemplate: React.FC = () => {
|
|
|
1829
1800
|
focusDirectory={focusDirectory}
|
|
1830
1801
|
highlightLayers={cityHighlightLayers}
|
|
1831
1802
|
elevatedScopePanels={cityElevatedPanels ?? folderElevatedPanels}
|
|
1803
|
+
selectedPath={activeTab === 'files' ? selectedPanelFolder : null}
|
|
1804
|
+
selectionStyle={{ color: '#fbbf24' }}
|
|
1832
1805
|
onBuildingClick={handleBuildingClick}
|
|
1833
1806
|
animation={{
|
|
1834
1807
|
startFlat: true,
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { FileCity3D } from '../components/FileCity3D';
|
|
4
|
+
import type { CityData, HighlightLayer } from '../components/FileCity3D';
|
|
5
|
+
import { createFileColorHighlightLayers } from '../utils/fileColorHighlightLayers';
|
|
6
|
+
import authServerCityData from '../../../../assets/auth-server-city-data.json';
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: 'Debug/Highlight Layers (Flat)',
|
|
10
|
+
parameters: { layout: 'fullscreen' },
|
|
11
|
+
} satisfies Meta;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
const cityData = authServerCityData as CityData;
|
|
16
|
+
|
|
17
|
+
// Three known-existing paths in the auth-server fixture, picked so they
|
|
18
|
+
// represent different file types.
|
|
19
|
+
const TARGETS = {
|
|
20
|
+
ts: 'auth-server/src/lib/auth-provider.ts', // .ts → fileColor primary 'fill'
|
|
21
|
+
tsx: 'auth-server/src/app/page.tsx', // .tsx → fileColor primary 'fill', secondary 'border'
|
|
22
|
+
route: 'auth-server/src/app/api/auth/workos/callback/route.ts', // .ts
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const RED = '#ef4444';
|
|
26
|
+
const AMBER = '#f59e0b';
|
|
27
|
+
const GREEN = '#22c55e';
|
|
28
|
+
const NEUTRAL_BUILDING = '#475569'; // slate-600 — used in stories that want to isolate highlight rendering
|
|
29
|
+
|
|
30
|
+
const FLAT_ANIMATION = {
|
|
31
|
+
startFlat: true as const,
|
|
32
|
+
autoStartDelay: null,
|
|
33
|
+
staggerDelay: 0,
|
|
34
|
+
tension: 200,
|
|
35
|
+
friction: 24,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const Stage = ({ children }: { children: React.ReactNode }) => (
|
|
39
|
+
<div
|
|
40
|
+
style={{
|
|
41
|
+
width: '100vw',
|
|
42
|
+
height: '100vh',
|
|
43
|
+
backgroundColor: '#0f1419',
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// 1. Borders only, no fileColorLayers — the cleanest possible test.
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
export const BorderOnly_NoFileColors: StoryObj = {
|
|
54
|
+
name: '1. border only, no file colors',
|
|
55
|
+
render: () => {
|
|
56
|
+
const layers: HighlightLayer[] = [
|
|
57
|
+
{
|
|
58
|
+
id: 'red',
|
|
59
|
+
name: 'red',
|
|
60
|
+
enabled: true,
|
|
61
|
+
color: RED,
|
|
62
|
+
priority: 10,
|
|
63
|
+
borderWidth: 30,
|
|
64
|
+
items: [{ path: TARGETS.ts, type: 'file', renderStrategy: 'border' }],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'amber',
|
|
68
|
+
name: 'amber',
|
|
69
|
+
enabled: true,
|
|
70
|
+
color: AMBER,
|
|
71
|
+
priority: 11,
|
|
72
|
+
borderWidth: 30,
|
|
73
|
+
items: [{ path: TARGETS.tsx, type: 'file', renderStrategy: 'border' }],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'green',
|
|
77
|
+
name: 'green',
|
|
78
|
+
enabled: true,
|
|
79
|
+
color: GREEN,
|
|
80
|
+
priority: 12,
|
|
81
|
+
borderWidth: 30,
|
|
82
|
+
items: [{ path: TARGETS.route, type: 'file', renderStrategy: 'border' }],
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
return (
|
|
86
|
+
<Stage>
|
|
87
|
+
<FileCity3D
|
|
88
|
+
cityData={cityData}
|
|
89
|
+
width="100%"
|
|
90
|
+
height="100%"
|
|
91
|
+
isGrown={false}
|
|
92
|
+
animation={FLAT_ANIMATION}
|
|
93
|
+
highlightLayers={layers}
|
|
94
|
+
defaultBuildingColor={NEUTRAL_BUILDING}
|
|
95
|
+
isolationMode="none"
|
|
96
|
+
backgroundColor="#0f1419"
|
|
97
|
+
showControls={true}
|
|
98
|
+
/>
|
|
99
|
+
</Stage>
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// 2. Same as #1 but with fileColorLayers also set — does anything change?
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
export const BorderOnly_WithFileColors: StoryObj = {
|
|
108
|
+
name: '2. border + file colors',
|
|
109
|
+
render: () => {
|
|
110
|
+
const fileColorLayers = createFileColorHighlightLayers(cityData.buildings);
|
|
111
|
+
const layers: HighlightLayer[] = [
|
|
112
|
+
{
|
|
113
|
+
id: 'red',
|
|
114
|
+
name: 'red',
|
|
115
|
+
enabled: true,
|
|
116
|
+
color: RED,
|
|
117
|
+
priority: 1000,
|
|
118
|
+
borderWidth: 30,
|
|
119
|
+
items: [{ path: TARGETS.ts, type: 'file', renderStrategy: 'border' }],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 'amber',
|
|
123
|
+
name: 'amber',
|
|
124
|
+
enabled: true,
|
|
125
|
+
color: AMBER,
|
|
126
|
+
priority: 1000,
|
|
127
|
+
borderWidth: 30,
|
|
128
|
+
items: [{ path: TARGETS.tsx, type: 'file', renderStrategy: 'border' }],
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'green',
|
|
132
|
+
name: 'green',
|
|
133
|
+
enabled: true,
|
|
134
|
+
color: GREEN,
|
|
135
|
+
priority: 1000,
|
|
136
|
+
borderWidth: 30,
|
|
137
|
+
items: [{ path: TARGETS.route, type: 'file', renderStrategy: 'border' }],
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
return (
|
|
141
|
+
<Stage>
|
|
142
|
+
<FileCity3D
|
|
143
|
+
cityData={cityData}
|
|
144
|
+
width="100%"
|
|
145
|
+
height="100%"
|
|
146
|
+
isGrown={false}
|
|
147
|
+
animation={FLAT_ANIMATION}
|
|
148
|
+
fileColorLayers={fileColorLayers}
|
|
149
|
+
highlightLayers={layers}
|
|
150
|
+
isolationMode="none"
|
|
151
|
+
backgroundColor="#0f1419"
|
|
152
|
+
showControls={true}
|
|
153
|
+
/>
|
|
154
|
+
</Stage>
|
|
155
|
+
);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// 3. Fill strategy — sanity check that the layer system applies at all.
|
|
161
|
+
// If these buildings turn red/amber/green, the layer plumbing is fine
|
|
162
|
+
// and the issue is specific to BorderHighlights rendering.
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
export const Fill_NoFileColors: StoryObj = {
|
|
165
|
+
name: '3. fill only, no file colors',
|
|
166
|
+
render: () => {
|
|
167
|
+
const layers: HighlightLayer[] = [
|
|
168
|
+
{
|
|
169
|
+
id: 'red',
|
|
170
|
+
name: 'red',
|
|
171
|
+
enabled: true,
|
|
172
|
+
color: RED,
|
|
173
|
+
priority: 10,
|
|
174
|
+
items: [{ path: TARGETS.ts, type: 'file', renderStrategy: 'fill' }],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'amber',
|
|
178
|
+
name: 'amber',
|
|
179
|
+
enabled: true,
|
|
180
|
+
color: AMBER,
|
|
181
|
+
priority: 11,
|
|
182
|
+
items: [{ path: TARGETS.tsx, type: 'file', renderStrategy: 'fill' }],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'green',
|
|
186
|
+
name: 'green',
|
|
187
|
+
enabled: true,
|
|
188
|
+
color: GREEN,
|
|
189
|
+
priority: 12,
|
|
190
|
+
items: [{ path: TARGETS.route, type: 'file', renderStrategy: 'fill' }],
|
|
191
|
+
},
|
|
192
|
+
];
|
|
193
|
+
return (
|
|
194
|
+
<Stage>
|
|
195
|
+
<FileCity3D
|
|
196
|
+
cityData={cityData}
|
|
197
|
+
width="100%"
|
|
198
|
+
height="100%"
|
|
199
|
+
isGrown={false}
|
|
200
|
+
animation={FLAT_ANIMATION}
|
|
201
|
+
highlightLayers={layers}
|
|
202
|
+
defaultBuildingColor={NEUTRAL_BUILDING}
|
|
203
|
+
isolationMode="none"
|
|
204
|
+
backgroundColor="#0f1419"
|
|
205
|
+
showControls={true}
|
|
206
|
+
/>
|
|
207
|
+
</Stage>
|
|
208
|
+
);
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// 4. Same buildings as #1 but in 3D (grown). If borders show colored here
|
|
214
|
+
// but black in #1, the issue is specific to flat mode.
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
export const BorderOnly_Grown: StoryObj = {
|
|
217
|
+
name: '4. border only, 3D grown',
|
|
218
|
+
render: () => {
|
|
219
|
+
const layers: HighlightLayer[] = [
|
|
220
|
+
{
|
|
221
|
+
id: 'red',
|
|
222
|
+
name: 'red',
|
|
223
|
+
enabled: true,
|
|
224
|
+
color: RED,
|
|
225
|
+
priority: 10,
|
|
226
|
+
borderWidth: 30,
|
|
227
|
+
items: [{ path: TARGETS.ts, type: 'file', renderStrategy: 'border' }],
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: 'amber',
|
|
231
|
+
name: 'amber',
|
|
232
|
+
enabled: true,
|
|
233
|
+
color: AMBER,
|
|
234
|
+
priority: 11,
|
|
235
|
+
borderWidth: 30,
|
|
236
|
+
items: [{ path: TARGETS.tsx, type: 'file', renderStrategy: 'border' }],
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
id: 'green',
|
|
240
|
+
name: 'green',
|
|
241
|
+
enabled: true,
|
|
242
|
+
color: GREEN,
|
|
243
|
+
priority: 12,
|
|
244
|
+
borderWidth: 30,
|
|
245
|
+
items: [{ path: TARGETS.route, type: 'file', renderStrategy: 'border' }],
|
|
246
|
+
},
|
|
247
|
+
];
|
|
248
|
+
return (
|
|
249
|
+
<Stage>
|
|
250
|
+
<FileCity3D
|
|
251
|
+
cityData={cityData}
|
|
252
|
+
width="100%"
|
|
253
|
+
height="100%"
|
|
254
|
+
isGrown={true}
|
|
255
|
+
animation={{ ...FLAT_ANIMATION, autoStartDelay: 0 }}
|
|
256
|
+
highlightLayers={layers}
|
|
257
|
+
defaultBuildingColor={NEUTRAL_BUILDING}
|
|
258
|
+
isolationMode="none"
|
|
259
|
+
backgroundColor="#0f1419"
|
|
260
|
+
showControls={true}
|
|
261
|
+
/>
|
|
262
|
+
</Stage>
|
|
263
|
+
);
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
// 5. Sweep of borderWidths. Are any of them visible in flat mode?
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
export const BorderWidthSweep: StoryObj = {
|
|
271
|
+
name: '5. borderWidth sweep (4, 30, 100)',
|
|
272
|
+
render: () => {
|
|
273
|
+
const layers: HighlightLayer[] = [
|
|
274
|
+
{
|
|
275
|
+
id: 'bw-4',
|
|
276
|
+
name: 'bw 4',
|
|
277
|
+
enabled: true,
|
|
278
|
+
color: RED,
|
|
279
|
+
priority: 10,
|
|
280
|
+
borderWidth: 4,
|
|
281
|
+
items: [{ path: TARGETS.ts, type: 'file', renderStrategy: 'border' }],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: 'bw-30',
|
|
285
|
+
name: 'bw 30',
|
|
286
|
+
enabled: true,
|
|
287
|
+
color: AMBER,
|
|
288
|
+
priority: 11,
|
|
289
|
+
borderWidth: 30,
|
|
290
|
+
items: [{ path: TARGETS.tsx, type: 'file', renderStrategy: 'border' }],
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
id: 'bw-100',
|
|
294
|
+
name: 'bw 100',
|
|
295
|
+
enabled: true,
|
|
296
|
+
color: GREEN,
|
|
297
|
+
priority: 12,
|
|
298
|
+
borderWidth: 100,
|
|
299
|
+
items: [{ path: TARGETS.route, type: 'file', renderStrategy: 'border' }],
|
|
300
|
+
},
|
|
301
|
+
];
|
|
302
|
+
return (
|
|
303
|
+
<Stage>
|
|
304
|
+
<FileCity3D
|
|
305
|
+
cityData={cityData}
|
|
306
|
+
width="100%"
|
|
307
|
+
height="100%"
|
|
308
|
+
isGrown={false}
|
|
309
|
+
animation={FLAT_ANIMATION}
|
|
310
|
+
highlightLayers={layers}
|
|
311
|
+
defaultBuildingColor={NEUTRAL_BUILDING}
|
|
312
|
+
isolationMode="none"
|
|
313
|
+
backgroundColor="#0f1419"
|
|
314
|
+
showControls={true}
|
|
315
|
+
/>
|
|
316
|
+
</Stage>
|
|
317
|
+
);
|
|
318
|
+
},
|
|
319
|
+
};
|