@principal-ai/file-city-react 0.5.0 → 0.5.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.
@@ -22,6 +22,7 @@ export interface ArchitectureMapHighlightLayersProps {
22
22
  className?: string;
23
23
  selectiveRender?: SelectiveRenderOptions;
24
24
  canvasBackgroundColor?: string;
25
+ maxCanvasSize?: number;
25
26
  hoverBorderColor?: string;
26
27
  disableOpacityDimming?: boolean;
27
28
  defaultDirectoryColor?: string;
@@ -60,7 +61,7 @@ export interface ArchitectureMapHighlightLayersProps {
60
61
  buildingBorderRadius?: number;
61
62
  districtBorderRadius?: number;
62
63
  }
63
- declare function ArchitectureMapHighlightLayersInner({ cityData, highlightLayers, onLayerToggle, focusDirectory, rootDirectoryName, onDirectorySelect, onFileClick, enableZoom, zoomToPath, onZoomComplete, zoomAnimationSpeed, allowZoomToPath, fullSize, showGrid, showFileNames, className, selectiveRender, canvasBackgroundColor, hoverBorderColor, disableOpacityDimming, defaultDirectoryColor, defaultBuildingColor, subdirectoryMode, showLayerControls, showFileTypeIcons, showDirectoryLabels, transform, // Default to no rotation
64
+ declare function ArchitectureMapHighlightLayersInner({ cityData, highlightLayers, onLayerToggle, focusDirectory, rootDirectoryName, onDirectorySelect, onFileClick, enableZoom, zoomToPath, onZoomComplete, zoomAnimationSpeed, allowZoomToPath, fullSize, showGrid, showFileNames, className, selectiveRender, canvasBackgroundColor, maxCanvasSize, hoverBorderColor, disableOpacityDimming, defaultDirectoryColor, defaultBuildingColor, subdirectoryMode, showLayerControls, showFileTypeIcons, showDirectoryLabels, transform, // Default to no rotation
64
65
  onHover, buildingBorderRadius, districtBorderRadius, }: ArchitectureMapHighlightLayersProps): React.JSX.Element;
65
66
  export declare const ArchitectureMapHighlightLayers: typeof ArchitectureMapHighlightLayersInner;
66
67
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"ArchitectureMapHighlightLayers.d.ts","sourceRoot":"","sources":["../../src/components/ArchitectureMapHighlightLayers.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ArchitectureMapHighlightLayers.d.ts","sourceRoot":"","sources":["../../src/components/ArchitectureMapHighlightLayers.tsx"],"names":[],"mappings":"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"}
@@ -179,7 +179,7 @@ class PathHierarchyLookup {
179
179
  return this.abstractedPaths.has(path);
180
180
  }
181
181
  }
182
- function ArchitectureMapHighlightLayersInner({ cityData, highlightLayers = [], onLayerToggle, focusDirectory = null, rootDirectoryName, onDirectorySelect, onFileClick, enableZoom = false, zoomToPath = null, onZoomComplete, zoomAnimationSpeed = 0.12, allowZoomToPath = true, fullSize = false, showGrid = false, showFileNames = false, className = '', selectiveRender, canvasBackgroundColor, hoverBorderColor, disableOpacityDimming = true, defaultDirectoryColor, defaultBuildingColor, subdirectoryMode, showLayerControls = false, showFileTypeIcons = true, showDirectoryLabels = true, transform = { rotation: 0 }, // Default to no rotation
182
+ function ArchitectureMapHighlightLayersInner({ cityData, highlightLayers = [], onLayerToggle, focusDirectory = null, rootDirectoryName, onDirectorySelect, onFileClick, enableZoom = false, zoomToPath = null, onZoomComplete, zoomAnimationSpeed = 0.12, allowZoomToPath = true, fullSize = false, showGrid = false, showFileNames = false, className = '', selectiveRender, canvasBackgroundColor, maxCanvasSize, hoverBorderColor, disableOpacityDimming = true, defaultDirectoryColor, defaultBuildingColor, subdirectoryMode, showLayerControls = false, showFileTypeIcons = true, showDirectoryLabels = true, transform = { rotation: 0 }, // Default to no rotation
183
183
  onHover, buildingBorderRadius = 0, districtBorderRadius = 0, }) {
184
184
  const { theme } = (0, industry_theme_1.useTheme)();
185
185
  // Use theme colors as defaults, with prop overrides
@@ -309,7 +309,10 @@ onHover, buildingBorderRadius = 0, districtBorderRadius = 0, }) {
309
309
  const calculateCanvasResolution = (fileCount, _cityBounds) => {
310
310
  const minSize = 400;
311
311
  const scaleFactor = Math.sqrt(fileCount / 5);
312
- const resolution = Math.max(minSize, minSize + scaleFactor * 300);
312
+ let resolution = Math.max(minSize, minSize + scaleFactor * 300);
313
+ if (maxCanvasSize !== undefined) {
314
+ resolution = Math.min(resolution, maxCanvasSize);
315
+ }
313
316
  return { width: resolution, height: resolution };
314
317
  };
315
318
  const [canvasSize, setCanvasSize] = (0, react_1.useState)(() => calculateCanvasResolution(cityData?.buildings?.length || 10, cityData?.bounds));
@@ -1153,14 +1156,46 @@ onHover, buildingBorderRadius = 0, districtBorderRadius = 0, }) {
1153
1156
  width: '100%',
1154
1157
  height: '100%',
1155
1158
  minHeight: '250px',
1156
- backgroundColor: theme.colors.backgroundSecondary,
1157
- borderRadius: `${theme.radii[2]}px`,
1158
- padding: `${theme.space[4]}px`,
1159
+ backgroundColor: resolvedCanvasBackgroundColor,
1160
+ borderRadius: fullSize ? 0 : `${theme.radii[2]}px`,
1159
1161
  display: 'flex',
1160
1162
  alignItems: 'center',
1161
1163
  justifyContent: 'center',
1164
+ position: 'relative',
1165
+ overflow: 'hidden',
1162
1166
  } },
1163
- react_1.default.createElement("div", { style: { color: theme.colors.textMuted, fontFamily: theme.fonts.body } }, "No city data available")));
1167
+ react_1.default.createElement("div", { style: {
1168
+ position: 'absolute',
1169
+ inset: 0,
1170
+ display: 'grid',
1171
+ gridTemplateColumns: 'repeat(auto-fit, minmax(80px, 1fr))',
1172
+ gridAutoRows: 'minmax(80px, 1fr)',
1173
+ gap: '20px',
1174
+ padding: '20px',
1175
+ } }, Array.from({ length: 200 }).map((_, i) => (react_1.default.createElement("div", { key: i, style: {
1176
+ backgroundColor: resolvedDefaultBuildingColor,
1177
+ borderRadius: buildingBorderRadius,
1178
+ opacity: 0.6 + (i % 3) * 0.2,
1179
+ } })))),
1180
+ react_1.default.createElement("div", { style: {
1181
+ position: 'absolute',
1182
+ top: '35%',
1183
+ left: '50%',
1184
+ transform: 'translate(-50%, -50%)',
1185
+ zIndex: 1,
1186
+ display: 'flex',
1187
+ alignItems: 'center',
1188
+ justifyContent: 'center',
1189
+ color: theme.colors.textMuted,
1190
+ fontFamily: theme.fonts.body,
1191
+ fontSize: `${theme.fontSizes[3]}px`,
1192
+ fontWeight: theme.fontWeights.medium,
1193
+ backgroundColor: resolvedCanvasBackgroundColor,
1194
+ borderRadius: `${theme.radii[2]}px`,
1195
+ padding: `${theme.space[4]}px ${theme.space[5]}px`,
1196
+ textAlign: 'center',
1197
+ minWidth: '300px',
1198
+ } }, "No city data available")));
1164
1199
  }
1165
1200
  return (react_1.default.createElement("div", { ref: containerRef, className: className, style: {
1166
1201
  position: 'relative',
@@ -1 +1 @@
1
- {"version":3,"file":"drawLayeredBuildings.d.ts","sourceRoot":"","sources":["../../../src/render/client/drawLayeredBuildings.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,mBAAmB,EACnB,cAAc,EACf,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAI1E,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC;AAE/D;;;GAGG;AACH,qBAAa,UAAU;IAErB,OAAO,CAAC,UAAU,CAA6E;IAE/F,OAAO,CAAC,cAAc,CAAuE;IAE7F,OAAO,CAAC,WAAW,CAA6E;gBAEpF,MAAM,EAAE,cAAc,EAAE;IAIpC,OAAO,CAAC,UAAU;IA0BlB;;;;OAIG;IACH,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAO,GAAG,UAAuB,GAC3C,KAAK,CAAC;QAAE,KAAK,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;CAuCrD;AA8BD,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,QAqBjB;AA0VD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,SAAS,EAAE,YAAY,EAAE,EACzB,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,KAAK,EAAE,MAAM,EAAE,wDAAwD;AACvE,MAAM,EAAE,cAAc,EAAE,EACxB,eAAe,CAAC,EAAE,YAAY,GAAG,IAAI,EACrC,QAAQ,CAAC,EAAE,OAAO,EAClB,qBAAqB,CAAC,EAAE,MAAM,EAC9B,YAAY,CAAC,EAAE;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,EACD,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,yDAAyD;AACxF,mBAAmB,GAAE,OAAc,EACnC,YAAY,GAAE,MAAU,EAAE,uDAAuD;AACjF,UAAU,CAAC,EAAE,UAAU,QAgQxB;AAGD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,SAAS,EAAE,YAAY,EAAE,EACzB,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,EAAE,EACxB,eAAe,CAAC,EAAE,YAAY,GAAG,IAAI,EACrC,oBAAoB,CAAC,EAAE,MAAM,EAC7B,aAAa,CAAC,EAAE,OAAO,EACvB,gBAAgB,CAAC,EAAE,MAAM,EACzB,qBAAqB,CAAC,EAAE,OAAO,EAC/B,iBAAiB,CAAC,EAAE,OAAO,EAC3B,YAAY,GAAE,MAAU,EAAE,2DAA2D;AACrF,UAAU,CAAC,EAAE,UAAU,EAAE,2CAA2C;AACpE,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,QA8J1C"}
1
+ {"version":3,"file":"drawLayeredBuildings.d.ts","sourceRoot":"","sources":["../../../src/render/client/drawLayeredBuildings.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,mBAAmB,EACnB,cAAc,EACf,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAI1E,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC;AAE/D;;;GAGG;AACH,qBAAa,UAAU;IAErB,OAAO,CAAC,UAAU,CAA6E;IAE/F,OAAO,CAAC,cAAc,CAAuE;IAE7F,OAAO,CAAC,WAAW,CAA6E;gBAEpF,MAAM,EAAE,cAAc,EAAE;IAIpC,OAAO,CAAC,UAAU;IA0BlB;;;;OAIG;IACH,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,OAAO,GAAG,UAAuB,GAC3C,KAAK,CAAC;QAAE,KAAK,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;CAuCrD;AA8BD,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,QAqBjB;AA0VD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,SAAS,EAAE,YAAY,EAAE,EACzB,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,KAAK,EAAE,MAAM,EAAE,wDAAwD;AACvE,MAAM,EAAE,cAAc,EAAE,EACxB,eAAe,CAAC,EAAE,YAAY,GAAG,IAAI,EACrC,QAAQ,CAAC,EAAE,OAAO,EAClB,qBAAqB,CAAC,EAAE,MAAM,EAC9B,YAAY,CAAC,EAAE;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,EACD,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,yDAAyD;AACxF,mBAAmB,GAAE,OAAc,EACnC,YAAY,GAAE,MAAU,EAAE,uDAAuD;AACjF,UAAU,CAAC,EAAE,UAAU,QAgQxB;AAGD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,SAAS,EAAE,YAAY,EAAE,EACzB,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,EAAE,EACxB,eAAe,CAAC,EAAE,YAAY,GAAG,IAAI,EACrC,oBAAoB,CAAC,EAAE,MAAM,EAC7B,aAAa,CAAC,EAAE,OAAO,EACvB,gBAAgB,CAAC,EAAE,MAAM,EACzB,qBAAqB,CAAC,EAAE,OAAO,EAC/B,iBAAiB,CAAC,EAAE,OAAO,EAC3B,YAAY,GAAE,MAAU,EAAE,2DAA2D;AACrF,UAAU,CAAC,EAAE,UAAU,EAAE,2CAA2C;AACpE,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,QA0K1C"}
@@ -655,12 +655,16 @@ iconMap) {
655
655
  // Draw file type icon if enabled and icon map is provided
656
656
  // Track icon size for positioning file name below
657
657
  let iconBottomY = pos.y;
658
+ let hasIcon = false;
658
659
  if (showFileTypeIcons && iconMap) {
659
660
  const iconConfig = (0, fileTypeIcons_1.getFileTypeIcon)(building.path, iconMap);
660
661
  if (iconConfig) {
662
+ hasIcon = true;
661
663
  // For wide buildings (wider than tall), shift icon up to make room for text below
664
+ // Only shift if text will actually be rendered
665
+ const willShowText = showFileNames && width > 100 && height > 30;
662
666
  const isWide = width > height;
663
- const iconYOffset = isWide ? -height * 0.15 : 0;
667
+ const iconYOffset = (willShowText && isWide) ? -height * 0.15 : 0;
664
668
  const iconY = pos.y + iconYOffset;
665
669
  (0, fileTypeIcons_1.drawFileTypeIcon)(ctx, iconConfig, pos.x, iconY, width, height);
666
670
  // Calculate where the icon ends vertically
@@ -691,13 +695,21 @@ iconMap) {
691
695
  const fontSize = Math.min(30, Math.max(10, Math.floor(Math.min(width, height) * 0.3)));
692
696
  ctx.font = `${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
693
697
  ctx.textAlign = 'center';
694
- ctx.textBaseline = 'top'; // Changed from 'middle' to 'top'
695
698
  const textMetrics = ctx.measureText(fileName);
696
699
  const textWidth = textMetrics.width;
697
700
  if (textWidth < width - 8) {
698
- // Add spacing between icon and text
699
- const spacing = 4;
700
- const textY = iconBottomY + spacing;
701
+ let textY;
702
+ if (hasIcon) {
703
+ // Position text below icon
704
+ ctx.textBaseline = 'top';
705
+ const spacing = 4;
706
+ textY = iconBottomY + spacing;
707
+ }
708
+ else {
709
+ // Center text vertically when no icon
710
+ ctx.textBaseline = 'middle';
711
+ textY = pos.y;
712
+ }
701
713
  // Text
702
714
  ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';
703
715
  ctx.fillText(fileName, pos.x, textY);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/file-city-react",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "React components for File City visualization",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -66,6 +66,7 @@ export interface ArchitectureMapHighlightLayersProps {
66
66
 
67
67
  // Canvas appearance
68
68
  canvasBackgroundColor?: string;
69
+ maxCanvasSize?: number; // Maximum canvas dimension in pixels (default: 6000, use ~2048 for mobile)
69
70
 
70
71
  // Additional styling options
71
72
  hoverBorderColor?: string;
@@ -305,6 +306,7 @@ function ArchitectureMapHighlightLayersInner({
305
306
  className = '',
306
307
  selectiveRender,
307
308
  canvasBackgroundColor,
309
+ maxCanvasSize,
308
310
  hoverBorderColor,
309
311
  disableOpacityDimming = true,
310
312
  defaultDirectoryColor,
@@ -476,7 +478,11 @@ function ArchitectureMapHighlightLayersInner({
476
478
  ) => {
477
479
  const minSize = 400;
478
480
  const scaleFactor = Math.sqrt(fileCount / 5);
479
- const resolution = Math.max(minSize, minSize + scaleFactor * 300);
481
+ let resolution = Math.max(minSize, minSize + scaleFactor * 300);
482
+
483
+ if (maxCanvasSize !== undefined) {
484
+ resolution = Math.min(resolution, maxCanvasSize);
485
+ }
480
486
 
481
487
  return { width: resolution, height: resolution };
482
488
  };
@@ -1624,15 +1630,61 @@ function ArchitectureMapHighlightLayersInner({
1624
1630
  width: '100%',
1625
1631
  height: '100%',
1626
1632
  minHeight: '250px',
1627
- backgroundColor: theme.colors.backgroundSecondary,
1628
- borderRadius: `${theme.radii[2]}px`,
1629
- padding: `${theme.space[4]}px`,
1633
+ backgroundColor: resolvedCanvasBackgroundColor,
1634
+ borderRadius: fullSize ? 0 : `${theme.radii[2]}px`,
1630
1635
  display: 'flex',
1631
1636
  alignItems: 'center',
1632
1637
  justifyContent: 'center',
1638
+ position: 'relative',
1639
+ overflow: 'hidden',
1633
1640
  }}
1634
1641
  >
1635
- <div style={{ color: theme.colors.textMuted, fontFamily: theme.fonts.body }}>
1642
+ {/* Decorative grid background with integrated text */}
1643
+ <div
1644
+ style={{
1645
+ position: 'absolute',
1646
+ inset: 0,
1647
+ display: 'grid',
1648
+ gridTemplateColumns: 'repeat(auto-fit, minmax(80px, 1fr))',
1649
+ gridAutoRows: 'minmax(80px, 1fr)',
1650
+ gap: '20px',
1651
+ padding: '20px',
1652
+ }}
1653
+ >
1654
+ {/* Generate grid squares to fill space */}
1655
+ {Array.from({ length: 200 }).map((_, i) => (
1656
+ <div
1657
+ key={i}
1658
+ style={{
1659
+ backgroundColor: resolvedDefaultBuildingColor,
1660
+ borderRadius: buildingBorderRadius,
1661
+ opacity: 0.6 + (i % 3) * 0.2,
1662
+ }}
1663
+ />
1664
+ ))}
1665
+ </div>
1666
+ {/* Text overlay centered */}
1667
+ <div
1668
+ style={{
1669
+ position: 'absolute',
1670
+ top: '35%',
1671
+ left: '50%',
1672
+ transform: 'translate(-50%, -50%)',
1673
+ zIndex: 1,
1674
+ display: 'flex',
1675
+ alignItems: 'center',
1676
+ justifyContent: 'center',
1677
+ color: theme.colors.textMuted,
1678
+ fontFamily: theme.fonts.body,
1679
+ fontSize: `${theme.fontSizes[3]}px`,
1680
+ fontWeight: theme.fontWeights.medium,
1681
+ backgroundColor: resolvedCanvasBackgroundColor,
1682
+ borderRadius: `${theme.radii[2]}px`,
1683
+ padding: `${theme.space[4]}px ${theme.space[5]}px`,
1684
+ textAlign: 'center',
1685
+ minWidth: '300px',
1686
+ }}
1687
+ >
1636
1688
  No city data available
1637
1689
  </div>
1638
1690
  </div>
@@ -894,12 +894,16 @@ export function drawLayeredBuildings(
894
894
  // Draw file type icon if enabled and icon map is provided
895
895
  // Track icon size for positioning file name below
896
896
  let iconBottomY = pos.y;
897
+ let hasIcon = false;
897
898
  if (showFileTypeIcons && iconMap) {
898
899
  const iconConfig = getFileTypeIcon(building.path, iconMap);
899
900
  if (iconConfig) {
901
+ hasIcon = true;
900
902
  // For wide buildings (wider than tall), shift icon up to make room for text below
903
+ // Only shift if text will actually be rendered
904
+ const willShowText = showFileNames && width > 100 && height > 30;
901
905
  const isWide = width > height;
902
- const iconYOffset = isWide ? -height * 0.15 : 0;
906
+ const iconYOffset = (willShowText && isWide) ? -height * 0.15 : 0;
903
907
  const iconY = pos.y + iconYOffset;
904
908
 
905
909
  drawFileTypeIcon(ctx, iconConfig, pos.x, iconY, width, height);
@@ -933,15 +937,23 @@ export function drawLayeredBuildings(
933
937
  const fontSize = Math.min(30, Math.max(10, Math.floor(Math.min(width, height) * 0.3)));
934
938
  ctx.font = `${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
935
939
  ctx.textAlign = 'center';
936
- ctx.textBaseline = 'top'; // Changed from 'middle' to 'top'
937
940
 
938
941
  const textMetrics = ctx.measureText(fileName);
939
942
  const textWidth = textMetrics.width;
940
943
 
941
944
  if (textWidth < width - 8) {
942
- // Add spacing between icon and text
943
- const spacing = 4;
944
- const textY = iconBottomY + spacing;
945
+ let textY: number;
946
+
947
+ if (hasIcon) {
948
+ // Position text below icon
949
+ ctx.textBaseline = 'top';
950
+ const spacing = 4;
951
+ textY = iconBottomY + spacing;
952
+ } else {
953
+ // Center text vertically when no icon
954
+ ctx.textBaseline = 'middle';
955
+ textY = pos.y;
956
+ }
945
957
 
946
958
  // Text
947
959
  ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';
@@ -11,7 +11,7 @@ const meta = {
11
11
  layout: 'fullscreen',
12
12
  },
13
13
  decorators: [
14
- Story => (
14
+ (Story: React.ComponentType) => (
15
15
  <div style={{ width: '100vw', height: '100vh', backgroundColor: '#1a1a1a' }}>
16
16
  <Story />
17
17
  </div>
@@ -199,7 +199,7 @@ function createAllFileTypesCityData() {
199
199
  };
200
200
  });
201
201
 
202
- const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos);
202
+ const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos, 'all-file-types');
203
203
  const builder = new CodeCityBuilderWithGrid();
204
204
  return builder.buildCityFromFileSystem(fileTree, '', {
205
205
  paddingTop: 2,
@@ -230,6 +230,8 @@ export const AllFileTypesWithColors: Story = {
230
230
  enableZoom={true}
231
231
  buildingBorderRadius={2}
232
232
  districtBorderRadius={4}
233
+ showFileTypeIcons={true}
234
+ showFileNames={true}
233
235
  />
234
236
  <div
235
237
  style={{
@@ -288,7 +290,7 @@ export const TestFilesWithIcons: Story = {
288
290
  };
289
291
  });
290
292
 
291
- const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos);
293
+ const fileTree = buildFileSystemTreeFromFileInfoList(fileInfos, 'test-files');
292
294
  const builder = new CodeCityBuilderWithGrid();
293
295
  const cityData = builder.buildCityFromFileSystem(fileTree, '', {
294
296
  paddingTop: 2,
@@ -50,7 +50,7 @@ const meta = {
50
50
  layout: 'fullscreen',
51
51
  },
52
52
  decorators: [
53
- Story => (
53
+ (Story: React.ComponentType) => (
54
54
  <div style={{ width: '100vw', height: '100vh' }}>
55
55
  <Story />
56
56
  </div>
@@ -12,7 +12,7 @@ const meta = {
12
12
  layout: 'fullscreen',
13
13
  },
14
14
  decorators: [
15
- Story => (
15
+ (Story: React.ComponentType) => (
16
16
  <div style={{ width: '100vw', height: '100vh', backgroundColor: '#1a1a1a' }}>
17
17
  <Story />
18
18
  </div>
@@ -200,7 +200,6 @@ export const WithAbstractionLayer: Story = {
200
200
  color: '#1e40af',
201
201
  priority: 0,
202
202
  items: [],
203
- // @ts-expect-error - abstraction layer specific properties
204
203
  abstractionLayer: true,
205
204
  abstractionConfig: {
206
205
  maxZoomLevel: 2.0,
@@ -208,7 +207,7 @@ export const WithAbstractionLayer: Story = {
208
207
  backgroundColor: '#1e40af',
209
208
  allowRootAbstraction: false,
210
209
  },
211
- },
210
+ } as HighlightLayer,
212
211
  ],
213
212
  fullSize: true,
214
213
  enableZoom: true,
@@ -311,6 +310,14 @@ export const WithBorderRadius: Story = {
311
310
  },
312
311
  };
313
312
 
313
+ // Story showing the loading/empty state when cityData is not available
314
+ export const LoadingState: Story = {
315
+ args: {
316
+ cityData: undefined,
317
+ fullSize: true,
318
+ },
319
+ };
320
+
314
321
  // Story with programmatic zoom only (no user interaction)
315
322
  // Demonstrates allowZoomToPath={true} with enableZoom={false}
316
323
  export const ProgrammaticZoomOnly: Story = {
@@ -11,7 +11,7 @@ const meta = {
11
11
  layout: 'fullscreen',
12
12
  },
13
13
  decorators: [
14
- Story => (
14
+ (Story: React.ComponentType) => (
15
15
  <div style={{ height: '100vh', width: '100vw' }}>
16
16
  <Story />
17
17
  </div>
@@ -353,7 +353,7 @@ const meta = {
353
353
  layout: 'fullscreen',
354
354
  },
355
355
  decorators: [
356
- Story => (
356
+ (Story: React.ComponentType) => (
357
357
  <div style={{ width: '100vw', height: '100vh' }}>
358
358
  <Story />
359
359
  </div>