@industry-theme/file-city-panel 0.5.60 → 0.5.61

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.
Files changed (27) hide show
  1. package/dist/index.d.ts +9 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/panels/FileCityTrailExplorerPanel/FileCityTrailExplorerPanel.d.ts +23 -0
  4. package/dist/panels/FileCityTrailExplorerPanel/FileCityTrailExplorerPanel.d.ts.map +1 -0
  5. package/dist/panels/FileCityTrailExplorerPanel/buildSequenceViewInputs.d.ts +29 -0
  6. package/dist/panels/FileCityTrailExplorerPanel/buildSequenceViewInputs.d.ts.map +1 -0
  7. package/dist/panels/FileCityTrailExplorerPanel/cameraFraming.d.ts +42 -0
  8. package/dist/panels/FileCityTrailExplorerPanel/cameraFraming.d.ts.map +1 -0
  9. package/dist/panels/FileCityTrailExplorerPanel/index.d.ts +2 -0
  10. package/dist/panels/FileCityTrailExplorerPanel/index.d.ts.map +1 -0
  11. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailDiffSnippetView.d.ts +45 -0
  12. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailDiffSnippetView.d.ts.map +1 -0
  13. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailLeaderLine.d.ts +39 -0
  14. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailLeaderLine.d.ts.map +1 -0
  15. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailMarkdownOverlay.d.ts +30 -0
  16. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailMarkdownOverlay.d.ts.map +1 -0
  17. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailSnippetView.d.ts +35 -0
  18. package/dist/panels/FileCityTrailExplorerPanel/overlays/TrailSnippetView.d.ts.map +1 -0
  19. package/dist/panels.bundle.js +1508 -250
  20. package/dist/panels.bundle.js.map +1 -1
  21. package/dist/types/FileCityTrailExplorerPanel.d.ts +83 -0
  22. package/dist/types/FileCityTrailExplorerPanel.d.ts.map +1 -0
  23. package/dist/types/Trail.d.ts +508 -0
  24. package/dist/types/Trail.d.ts.map +1 -0
  25. package/dist/types/index.d.ts +2 -0
  26. package/dist/types/index.d.ts.map +1 -1
  27. package/package.json +1 -1
@@ -253815,12 +253815,12 @@ const PierreFileView = ({
253815
253815
  File$2,
253816
253816
  {
253817
253817
  file: fileObject,
253818
- options: background ? buildPierreOptions$1(background) : pierreOptions$1,
253819
- style: pierreStyle$2
253818
+ options: background ? buildPierreOptions$2(background) : pierreOptions$2,
253819
+ style: pierreStyle$4
253820
253820
  }
253821
253821
  );
253822
253822
  };
253823
- const buildBackgroundCSS$1 = (color2) => `
253823
+ const buildBackgroundCSS$2 = (color2) => `
253824
253824
  :host {
253825
253825
  background: ${color2} !important;
253826
253826
  }
@@ -253835,19 +253835,19 @@ const buildBackgroundCSS$1 = (color2) => `
253835
253835
  background: ${color2} !important;
253836
253836
  }
253837
253837
  `;
253838
- const pierreOptions$1 = {
253838
+ const pierreOptions$2 = {
253839
253839
  disableFileHeader: true
253840
253840
  };
253841
- const buildPierreOptions$1 = (background) => ({
253841
+ const buildPierreOptions$2 = (background) => ({
253842
253842
  disableFileHeader: true,
253843
- unsafeCSS: buildBackgroundCSS$1(background)
253843
+ unsafeCSS: buildBackgroundCSS$2(background)
253844
253844
  });
253845
- const pierreStyle$2 = {
253845
+ const pierreStyle$4 = {
253846
253846
  display: "block"
253847
253847
  };
253848
- const MIN_WIDTH_PX$3 = 320;
253848
+ const MIN_WIDTH_PX$4 = 320;
253849
253849
  const MIN_LEFT_GAP_PX$2 = 80;
253850
- const RESIZE_HANDLE_WIDTH$3 = 6;
253850
+ const RESIZE_HANDLE_WIDTH$4 = 6;
253851
253851
  const FileOverlay = ({
253852
253852
  filePath,
253853
253853
  fileName,
@@ -253876,7 +253876,7 @@ const FileOverlay = ({
253876
253876
  setIsResizing(true);
253877
253877
  const onMove = (ev) => {
253878
253878
  const next2 = Math.max(
253879
- MIN_WIDTH_PX$3,
253879
+ MIN_WIDTH_PX$4,
253880
253880
  Math.min(parentRect.width - MIN_LEFT_GAP_PX$2, parentRect.right - ev.clientX)
253881
253881
  );
253882
253882
  setWidthPx(next2);
@@ -253926,8 +253926,8 @@ const FileOverlay = ({
253926
253926
  position: "absolute",
253927
253927
  top: 0,
253928
253928
  bottom: 0,
253929
- left: -RESIZE_HANDLE_WIDTH$3 / 2,
253930
- width: RESIZE_HANDLE_WIDTH$3,
253929
+ left: -RESIZE_HANDLE_WIDTH$4 / 2,
253930
+ width: RESIZE_HANDLE_WIDTH$4,
253931
253931
  cursor: "col-resize",
253932
253932
  zIndex: 1,
253933
253933
  background: isResizing ? `color-mix(in srgb, ${theme2.colors.primary} 40%, transparent)` : "transparent"
@@ -254911,7 +254911,7 @@ const PierreSnippetView = ({
254911
254911
  [slice, onOpenComposer]
254912
254912
  );
254913
254913
  const options = React.useMemo(() => {
254914
- const base2 = background ? buildPierreOptions(background) : pierreOptions;
254914
+ const base2 = background ? buildPierreOptions$1(background) : pierreOptions$1;
254915
254915
  return {
254916
254916
  ...base2,
254917
254917
  onPostRender,
@@ -254950,12 +254950,12 @@ const PierreSnippetView = ({
254950
254950
  lineAnnotations,
254951
254951
  renderAnnotation,
254952
254952
  selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
254953
- style: pierreStyle$1
254953
+ style: pierreStyle$3
254954
254954
  }
254955
254955
  )
254956
254956
  ] });
254957
254957
  };
254958
- const buildBackgroundCSS = (color2) => `
254958
+ const buildBackgroundCSS$1 = (color2) => `
254959
254959
  :host {
254960
254960
  background: ${color2} !important;
254961
254961
  }
@@ -254970,17 +254970,17 @@ const buildBackgroundCSS = (color2) => `
254970
254970
  background: ${color2} !important;
254971
254971
  }
254972
254972
  `;
254973
- const pierreOptions = {
254973
+ const pierreOptions$1 = {
254974
254974
  disableFileHeader: true
254975
254975
  };
254976
- const buildPierreOptions = (background) => ({
254976
+ const buildPierreOptions$1 = (background) => ({
254977
254977
  disableFileHeader: true,
254978
- unsafeCSS: buildBackgroundCSS(background)
254978
+ unsafeCSS: buildBackgroundCSS$1(background)
254979
254979
  });
254980
- const pierreStyle$1 = {
254980
+ const pierreStyle$3 = {
254981
254981
  display: "block"
254982
254982
  };
254983
- const sliceWindow = (oldContents, newContents, startLine, endLine, focusLine, contextLines) => {
254983
+ const sliceWindow$1 = (oldContents, newContents, startLine, endLine, focusLine, contextLines) => {
254984
254984
  if (startLine == null || endLine == null) {
254985
254985
  return {
254986
254986
  oldText: oldContents,
@@ -255019,7 +255019,7 @@ const PierreSnippetDiffView = ({
255019
255019
  }) => {
255020
255020
  const { theme: theme2 } = useTheme();
255021
255021
  const slice = React.useMemo(
255022
- () => sliceWindow(
255022
+ () => sliceWindow$1(
255023
255023
  oldContents,
255024
255024
  newContents,
255025
255025
  startLine,
@@ -255062,10 +255062,10 @@ const PierreSnippetDiffView = ({
255062
255062
  FileDiff$2,
255063
255063
  {
255064
255064
  fileDiff,
255065
- options: { ...pierreOptionsBase, diffStyle },
255065
+ options: { ...pierreOptionsBase$1, diffStyle },
255066
255066
  selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
255067
255067
  style: background ? {
255068
- ...pierreStyle,
255068
+ ...pierreStyle$2,
255069
255069
  // Pierre derives addition/deletion/context/separator surfaces
255070
255070
  // by `color-mix`ing from --diffs-bg, which is keyed off
255071
255071
  // --diffs-light-bg / --diffs-dark-bg. Overriding the source
@@ -255074,15 +255074,15 @@ const PierreSnippetDiffView = ({
255074
255074
  // anchored to our theme background.
255075
255075
  ["--diffs-light-bg"]: background,
255076
255076
  ["--diffs-dark-bg"]: background
255077
- } : pierreStyle
255077
+ } : pierreStyle$2
255078
255078
  }
255079
255079
  )
255080
255080
  ] });
255081
255081
  };
255082
- const pierreOptionsBase = {
255082
+ const pierreOptionsBase$1 = {
255083
255083
  disableFileHeader: true
255084
255084
  };
255085
- const pierreStyle = {
255085
+ const pierreStyle$2 = {
255086
255086
  display: "block"
255087
255087
  };
255088
255088
  const toUiNote = (n) => {
@@ -255101,12 +255101,12 @@ const toUiNote = (n) => {
255101
255101
  createdAt: new Date(n.createdAt).getTime()
255102
255102
  };
255103
255103
  };
255104
- const PANEL_WIDTH_PCT$2 = 38;
255105
- const FLOAT_INSET$2 = 16;
255106
- const TOP_INSET$2 = 72;
255107
- const MIN_WIDTH_PX$2 = 360;
255104
+ const PANEL_WIDTH_PCT$3 = 38;
255105
+ const FLOAT_INSET$3 = 16;
255106
+ const TOP_INSET$3 = 72;
255107
+ const MIN_WIDTH_PX$3 = 360;
255108
255108
  const MIN_LEFT_GAP_PX$1 = 80;
255109
- const RESIZE_HANDLE_WIDTH$2 = 6;
255109
+ const RESIZE_HANDLE_WIDTH$3 = 6;
255110
255110
  const SequenceEventDetailOverlay = React.forwardRef(function SequenceEventDetailOverlay2({
255111
255111
  event,
255112
255112
  absolutePath,
@@ -255254,15 +255254,15 @@ const SequenceEventDetailOverlay = React.forwardRef(function SequenceEventDetail
255254
255254
  },
255255
255255
  [deleteSequenceNote, payloadId]
255256
255256
  );
255257
- const detailWidthCss = widthPx != null ? `${widthPx}px` : `calc(${PANEL_WIDTH_PCT$2}% - ${FLOAT_INSET$2}px)`;
255257
+ const detailWidthCss = widthPx != null ? `${widthPx}px` : `calc(${PANEL_WIDTH_PCT$3}% - ${FLOAT_INSET$3}px)`;
255258
255258
  const NOTES_PANEL_WIDTH = 320;
255259
255259
  const NOTES_PANEL_GAP = 12;
255260
255260
  const notesPanelStyle = {
255261
255261
  position: "absolute",
255262
- top: TOP_INSET$2,
255263
- bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$2}px)`,
255262
+ top: TOP_INSET$3,
255263
+ bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$3}px)`,
255264
255264
  width: NOTES_PANEL_WIDTH,
255265
- right: `calc(${detailWidthCss} + ${FLOAT_INSET$2}px + ${NOTES_PANEL_GAP}px)`,
255265
+ right: `calc(${detailWidthCss} + ${FLOAT_INSET$3}px + ${NOTES_PANEL_GAP}px)`,
255266
255266
  // Above the markdown overlay (z 1900) so an open thread wins when the
255267
255267
  // snippet drawer is dragged wide enough that the notes panel reaches the
255268
255268
  // left side of the workspace. The leader-line dot (z 1901) anchors at the
@@ -255286,10 +255286,10 @@ const SequenceEventDetailOverlay = React.forwardRef(function SequenceEventDetail
255286
255286
  setIsResizing(true);
255287
255287
  const onMove = (ev) => {
255288
255288
  const next2 = Math.max(
255289
- MIN_WIDTH_PX$2,
255289
+ MIN_WIDTH_PX$3,
255290
255290
  Math.min(
255291
- parentRect.width - MIN_LEFT_GAP_PX$1 - FLOAT_INSET$2,
255292
- parentRect.right - FLOAT_INSET$2 - ev.clientX
255291
+ parentRect.width - MIN_LEFT_GAP_PX$1 - FLOAT_INSET$3,
255292
+ parentRect.right - FLOAT_INSET$3 - ev.clientX
255293
255293
  )
255294
255294
  );
255295
255295
  setWidthPx(next2);
@@ -255310,14 +255310,14 @@ const SequenceEventDetailOverlay = React.forwardRef(function SequenceEventDetail
255310
255310
  onAnimationEnd: () => setHasEntered(true),
255311
255311
  style: {
255312
255312
  position: "absolute",
255313
- top: TOP_INSET$2,
255314
- right: FLOAT_INSET$2,
255313
+ top: TOP_INSET$3,
255314
+ right: FLOAT_INSET$3,
255315
255315
  // Anchor the bottom edge (mirroring the markdown overlay) so the
255316
255316
  // panel has a *definite* height — otherwise transient placeholder
255317
255317
  // states like "Loading…" collapse the panel to the content size.
255318
- bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$2}px)`,
255319
- width: widthPx != null ? `${widthPx}px` : `calc(${PANEL_WIDTH_PCT$2}% - ${FLOAT_INSET$2}px)`,
255320
- minWidth: MIN_WIDTH_PX$2,
255318
+ bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$3}px)`,
255319
+ width: widthPx != null ? `${widthPx}px` : `calc(${PANEL_WIDTH_PCT$3}% - ${FLOAT_INSET$3}px)`,
255320
+ minWidth: MIN_WIDTH_PX$3,
255321
255321
  backgroundColor: theme2.colors.background,
255322
255322
  border: `1px solid ${theme2.colors.border}`,
255323
255323
  borderRadius: 12,
@@ -255347,8 +255347,8 @@ const SequenceEventDetailOverlay = React.forwardRef(function SequenceEventDetail
255347
255347
  position: "absolute",
255348
255348
  top: 0,
255349
255349
  bottom: 0,
255350
- left: -RESIZE_HANDLE_WIDTH$2 / 2,
255351
- width: RESIZE_HANDLE_WIDTH$2,
255350
+ left: -RESIZE_HANDLE_WIDTH$3 / 2,
255351
+ width: RESIZE_HANDLE_WIDTH$3,
255352
255352
  cursor: "col-resize",
255353
255353
  zIndex: 1,
255354
255354
  background: isResizing ? `color-mix(in srgb, ${theme2.colors.primary} 40%, transparent)` : "transparent"
@@ -255572,12 +255572,12 @@ const iconButtonStyle = (color2, disabled = false) => ({
255572
255572
  alignItems: "center",
255573
255573
  opacity: disabled ? 0.5 : 1
255574
255574
  });
255575
- const PANEL_WIDTH_PCT$1 = 38;
255576
- const FLOAT_INSET$1 = 16;
255577
- const TOP_INSET$1 = 72;
255578
- const MIN_WIDTH_PX$1 = 360;
255575
+ const PANEL_WIDTH_PCT$2 = 38;
255576
+ const FLOAT_INSET$2 = 16;
255577
+ const TOP_INSET$2 = 72;
255578
+ const MIN_WIDTH_PX$2 = 360;
255579
255579
  const MIN_LEFT_GAP_PX = 80;
255580
- const RESIZE_HANDLE_WIDTH$1 = 6;
255580
+ const RESIZE_HANDLE_WIDTH$2 = 6;
255581
255581
  const SequenceFilesOverlay = ({
255582
255582
  steps,
255583
255583
  totalEvents,
@@ -255608,10 +255608,10 @@ const SequenceFilesOverlay = ({
255608
255608
  setIsResizing(true);
255609
255609
  const onMove = (ev) => {
255610
255610
  const next2 = Math.max(
255611
- MIN_WIDTH_PX$1,
255611
+ MIN_WIDTH_PX$2,
255612
255612
  Math.min(
255613
- parentRect.width - MIN_LEFT_GAP_PX - FLOAT_INSET$1,
255614
- parentRect.right - FLOAT_INSET$1 - ev.clientX
255613
+ parentRect.width - MIN_LEFT_GAP_PX - FLOAT_INSET$2,
255614
+ parentRect.right - FLOAT_INSET$2 - ev.clientX
255615
255615
  )
255616
255616
  );
255617
255617
  setWidthPx(next2);
@@ -255631,11 +255631,11 @@ const SequenceFilesOverlay = ({
255631
255631
  onAnimationEnd: () => setHasEntered(true),
255632
255632
  style: {
255633
255633
  position: "absolute",
255634
- top: TOP_INSET$1,
255635
- right: FLOAT_INSET$1,
255636
- bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$1}px)`,
255637
- width: widthPx != null ? `${widthPx}px` : `calc(${PANEL_WIDTH_PCT$1}% - ${FLOAT_INSET$1}px)`,
255638
- minWidth: MIN_WIDTH_PX$1,
255634
+ top: TOP_INSET$2,
255635
+ right: FLOAT_INSET$2,
255636
+ bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$2}px)`,
255637
+ width: widthPx != null ? `${widthPx}px` : `calc(${PANEL_WIDTH_PCT$2}% - ${FLOAT_INSET$2}px)`,
255638
+ minWidth: MIN_WIDTH_PX$2,
255639
255639
  backgroundColor: theme2.colors.background,
255640
255640
  border: `1px solid ${theme2.colors.border}`,
255641
255641
  borderRadius: 12,
@@ -255678,8 +255678,8 @@ const SequenceFilesOverlay = ({
255678
255678
  position: "absolute",
255679
255679
  top: 0,
255680
255680
  bottom: 0,
255681
- left: -RESIZE_HANDLE_WIDTH$1 / 2,
255682
- width: RESIZE_HANDLE_WIDTH$1,
255681
+ left: -RESIZE_HANDLE_WIDTH$2 / 2,
255682
+ width: RESIZE_HANDLE_WIDTH$2,
255683
255683
  cursor: "col-resize",
255684
255684
  zIndex: 1,
255685
255685
  background: isResizing ? `color-mix(in srgb, ${theme2.colors.primary} 40%, transparent)` : "transparent"
@@ -256358,11 +256358,11 @@ const primaryButton = (theme2) => ({
256358
256358
  fontSize: theme2.fontSizes[0],
256359
256359
  fontWeight: 600
256360
256360
  });
256361
- const PANEL_WIDTH_PCT = 38;
256362
- const FLOAT_INSET = 16;
256363
- const TOP_INSET = 72;
256364
- const MIN_WIDTH_PX = 360;
256365
- const RESIZE_HANDLE_WIDTH = 6;
256361
+ const PANEL_WIDTH_PCT$1 = 38;
256362
+ const FLOAT_INSET$1 = 16;
256363
+ const TOP_INSET$1 = 72;
256364
+ const MIN_WIDTH_PX$1 = 360;
256365
+ const RESIZE_HANDLE_WIDTH$1 = 6;
256366
256366
  const SequenceMarkdownOverlay = ({
256367
256367
  eyebrow,
256368
256368
  title,
@@ -256449,9 +256449,9 @@ const SequenceMarkdownOverlay = ({
256449
256449
  if (!drag2) return;
256450
256450
  const parent = (_a = containerRef.current) == null ? void 0 : _a.parentElement;
256451
256451
  const parentWidth = (parent == null ? void 0 : parent.clientWidth) ?? window.innerWidth;
256452
- const maxWidth = Math.max(MIN_WIDTH_PX, parentWidth - FLOAT_INSET * 2);
256452
+ const maxWidth = Math.max(MIN_WIDTH_PX$1, parentWidth - FLOAT_INSET$1 * 2);
256453
256453
  const dx = e.clientX - drag2.startX;
256454
- const next2 = Math.min(maxWidth, Math.max(MIN_WIDTH_PX, drag2.startWidth + dx));
256454
+ const next2 = Math.min(maxWidth, Math.max(MIN_WIDTH_PX$1, drag2.startWidth + dx));
256455
256455
  setWidthPx(next2);
256456
256456
  },
256457
256457
  []
@@ -256475,16 +256475,16 @@ const SequenceMarkdownOverlay = ({
256475
256475
  onAnimationEnd: () => setHasEntered(true),
256476
256476
  style: {
256477
256477
  position: "absolute",
256478
- top: TOP_INSET,
256479
- left: FLOAT_INSET,
256478
+ top: TOP_INSET$1,
256479
+ left: FLOAT_INSET$1,
256480
256480
  // Anchor the bottom edge too so the column has a *definite* height —
256481
256481
  // `IndustryMarkdownSlide` renders with `height: 100%` and only
256482
256482
  // engages its internal scroll when the chain of ancestors hands it a
256483
256483
  // resolvable pixel height. A `maxHeight`-only cap on a content-sized
256484
256484
  // flex column doesn't qualify across browsers.
256485
- bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET}px)`,
256486
- width: widthPx != null ? widthPx : `calc(${PANEL_WIDTH_PCT}% - ${FLOAT_INSET}px)`,
256487
- minWidth: MIN_WIDTH_PX,
256485
+ bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET$1}px)`,
256486
+ width: widthPx != null ? widthPx : `calc(${PANEL_WIDTH_PCT$1}% - ${FLOAT_INSET$1}px)`,
256487
+ minWidth: MIN_WIDTH_PX$1,
256488
256488
  backgroundColor: theme2.colors.background,
256489
256489
  border: `1px solid ${theme2.colors.border}`,
256490
256490
  borderRadius: 12,
@@ -256704,7 +256704,7 @@ const SequenceMarkdownOverlay = ({
256704
256704
  top: 0,
256705
256705
  right: 0,
256706
256706
  bottom: 0,
256707
- width: RESIZE_HANDLE_WIDTH,
256707
+ width: RESIZE_HANDLE_WIDTH$1,
256708
256708
  cursor: "ew-resize",
256709
256709
  // Subtle painted line on hover/drag so users discover it without
256710
256710
  // bias-distracting the rest of the time.
@@ -257577,188 +257577,1419 @@ const Placeholder = ({ building }) => {
257577
257577
  }
257578
257578
  );
257579
257579
  };
257580
- const focusBuildingTool = {
257581
- name: "focus_building",
257582
- description: "Focuses the camera on a specific file (building) in the file city visualization",
257583
- inputs: {
257584
- type: "object",
257585
- properties: {
257586
- filePath: {
257587
- type: "string",
257588
- description: "Path to the file to focus on"
257589
- },
257590
- animate: {
257591
- type: "boolean",
257592
- description: "Whether to animate the camera transition"
257593
- }
257594
- },
257595
- required: ["filePath"]
257596
- },
257597
- outputs: {
257598
- type: "object",
257599
- properties: {
257600
- success: { type: "boolean" },
257601
- message: { type: "string" }
257602
- }
257603
- },
257604
- tags: ["navigation", "camera", "focus"],
257605
- tool_call_template: {
257606
- call_template_type: "panel_event",
257607
- event_type: "industry-theme.file-city-panel:focus-building"
257608
- }
257609
- };
257610
- const selectDistrictTool = {
257611
- name: "select_district",
257612
- description: "Selects and highlights a directory (district) in the file city visualization",
257613
- inputs: {
257614
- type: "object",
257615
- properties: {
257616
- directoryPath: {
257617
- type: "string",
257618
- description: "Path to the directory to select"
257619
- },
257620
- expandChildren: {
257621
- type: "boolean",
257622
- description: "Whether to expand and show child buildings"
257623
- }
257624
- },
257625
- required: ["directoryPath"]
257626
- },
257627
- outputs: {
257628
- type: "object",
257629
- properties: {
257630
- success: { type: "boolean" },
257631
- selectedDistrict: { type: "string" }
257580
+ function buildSequenceViewInputs(payload, view) {
257581
+ var _a;
257582
+ const markersById = /* @__PURE__ */ new Map();
257583
+ for (const m of payload.markers) markersById.set(m.id, m);
257584
+ const events2 = [];
257585
+ for (const ref of view.markers) {
257586
+ const marker = markersById.get(ref.markerId);
257587
+ if (!marker) {
257588
+ console.warn(
257589
+ `[trail] sequence view references unknown markerId: ${ref.markerId}`
257590
+ );
257591
+ continue;
257632
257592
  }
257633
- },
257634
- tags: ["selection", "district", "directory"],
257635
- tool_call_template: {
257636
- call_template_type: "panel_event",
257637
- event_type: "industry-theme.file-city-panel:select-district"
257593
+ events2.push({
257594
+ id: marker.id,
257595
+ name: ref.name,
257596
+ label: marker.label,
257597
+ participant: ref.participant,
257598
+ moveEvent: ref.moveEvent,
257599
+ type: ref.type,
257600
+ sourcePath: marker.sourcePath
257601
+ });
257638
257602
  }
257639
- };
257640
- const resetViewTool = {
257641
- name: "reset_view",
257642
- description: "Resets the file city view to the default camera position",
257643
- inputs: {
257644
- type: "object",
257645
- properties: {
257646
- animate: {
257647
- type: "boolean",
257648
- description: "Whether to animate the camera reset"
257649
- }
257650
- }
257651
- },
257652
- outputs: {
257653
- type: "object",
257654
- properties: {
257655
- success: { type: "boolean" }
257603
+ if (view.actors) {
257604
+ for (const actor of view.actors) {
257605
+ events2.push({
257606
+ id: `__actor:${actor.name}`,
257607
+ name: actor.name,
257608
+ label: actor.label
257609
+ });
257656
257610
  }
257657
- },
257658
- tags: ["navigation", "camera", "reset"],
257659
- tool_call_template: {
257660
- call_template_type: "panel_event",
257661
- event_type: "industry-theme.file-city-panel:reset-view"
257662
- }
257663
- };
257664
- const codeCityPanelTools = [
257665
- focusBuildingTool,
257666
- selectDistrictTool,
257667
- resetViewTool
257668
- ];
257669
- const codeCityPanelToolsMetadata = {
257670
- id: "industry-theme.file-city-panel",
257671
- name: "File City Panel",
257672
- description: "Tools provided by the file city visualization panel extension",
257673
- tools: codeCityPanelTools
257674
- };
257675
- const NpmIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#CB3837", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z" }) });
257676
- const YarnIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#2C8EBB", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.375 0 0 5.375 0 12s5.375 12 12 12 12-5.375 12-12S18.625 0 12 0zm.768 4.105c.183 0 .363.053.525.157.125.083.287.185.755 1.154.31-.088.468-.042.551-.019.204.056.366.19.463.375.477.917.542 2.553.334 3.605-.241 1.232-.755 2.029-1.131 2.576.324.329.778.899 1.117 1.825.278.774.31 1.478.273 2.015a5.51 5.51 0 0 0 .602-.329c.593-.366 1.487-.917 2.553-.931.714-.009 1.269.445 1.353 1.103a1.23 1.23 0 0 1-.945 1.362c-.649.158-.95.278-1.821.843-1.232.797-2.539 1.242-3.012 1.39a1.686 1.686 0 0 1-.704.343c-.737.181-3.266.315-3.466.315h-.046c-.783 0-1.214-.241-1.45-.491-.658.329-1.51.19-2.122-.134a1.078 1.078 0 0 1-.58-1.153 1.243 1.243 0 0 1-.153-.195c-.162-.25-.528-.936-.454-1.946.056-.723.556-1.367.88-1.71a5.522 5.522 0 0 1 .408-2.256c.306-.727.885-1.348 1.32-1.737-.32-.537-.644-1.367-.329-2.21.227-.602.412-.936.82-1.08h-.005c.199-.074.389-.153.486-.259a3.418 3.418 0 0 1 2.298-1.103c.037-.093.079-.185.125-.283.31-.658.639-1.029 1.024-1.168a.94.94 0 0 1 .328-.06z" }) });
257677
- const PnpmIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#F69220", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z" }) });
257678
- const BunIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#FBF0DF", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M12 22.596c6.628 0 12-4.338 12-9.688 0-3.318-2.057-6.248-5.219-7.986-1.286-.715-2.297-1.357-3.139-1.89C14.058 2.025 13.08 1.404 12 1.404c-1.097 0-2.334.785-3.966 1.821a49.92 49.92 0 0 1-2.816 1.697C2.057 6.66 0 9.59 0 12.908c0 5.35 5.372 9.687 12 9.687v.001Z" }) });
257679
- const PackageManagerIcon = ({
257680
- packageManager,
257681
- size = 16,
257682
- color: color2
257683
- }) => {
257684
- switch (packageManager) {
257685
- case "npm":
257686
- return /* @__PURE__ */ jsx(NpmIcon, { size });
257687
- case "yarn":
257688
- return /* @__PURE__ */ jsx(YarnIcon, { size });
257689
- case "pnpm":
257690
- return /* @__PURE__ */ jsx(PnpmIcon, { size });
257691
- case "bun":
257692
- return /* @__PURE__ */ jsx(BunIcon, { size });
257693
- default:
257694
- return /* @__PURE__ */ jsx(Package$1, { size, color: color2 });
257695
257611
  }
257696
- };
257697
- const ProjectInfoHeader = ({
257698
- project,
257699
- onOpen,
257700
- compact = false
257701
- }) => {
257612
+ return {
257613
+ events: events2,
257614
+ edges: view.edges,
257615
+ layoutOptions: {
257616
+ laneOrder: (_a = view.layout) == null ? void 0 : _a.laneOrder
257617
+ }
257618
+ };
257619
+ }
257620
+ const FOV_DEG = 50;
257621
+ const FOV_RAD = FOV_DEG * Math.PI / 180;
257622
+ const TAN_HALF_FOV = Math.tan(FOV_RAD / 2);
257623
+ const FIT_PADDING = 1.08;
257624
+ function computeCameraFraming(inputs) {
257625
+ const { canvasW, canvasH, cityBounds, leftInset, rightInset, topInset, bottomInset } = inputs;
257626
+ if (canvasW <= 0 || canvasH <= 0) return null;
257627
+ const citySize = Math.max(
257628
+ cityBounds.maxX - cityBounds.minX,
257629
+ cityBounds.maxZ - cityBounds.minZ
257630
+ );
257631
+ const effectiveAspect = Math.min(1, canvasW / canvasH);
257632
+ const baseline = citySize / (2 * TAN_HALF_FOV * effectiveAspect) * FIT_PADDING;
257633
+ const visW = canvasW - leftInset - rightInset;
257634
+ const visH = canvasH - topInset - bottomInset;
257635
+ if (visW <= 0 || visH <= 0) return null;
257636
+ const fraction = Math.min(visW / canvasW, visH / canvasH);
257637
+ const height = baseline / fraction;
257638
+ const vH = 2 * height * TAN_HALF_FOV;
257639
+ const vW = vH * (canvasW / canvasH);
257640
+ const dxPx = canvasW / 2 - (leftInset + (canvasW - rightInset)) / 2;
257641
+ const dyPx = canvasH / 2 - (topInset + (canvasH - bottomInset)) / 2;
257642
+ const targetX = dxPx * (vW / canvasW);
257643
+ const targetZ = dyPx * (vH / canvasH);
257644
+ return { targetX, targetZ, height };
257645
+ }
257646
+ const TrailLeaderLine = React.forwardRef(function TrailLeaderLine2({ containerRef, building, cityCenter, targetRef }, ref) {
257702
257647
  const { theme: theme2 } = useTheme();
257703
- const totalDeps = (project.dependencyCount || 0) + (project.devDependencyCount || 0);
257704
- const fontSizeSmall = theme2.fontSizes[0];
257705
- const fontSizeMedium = theme2.fontSizes[1];
257706
- const fontSizeLarge = theme2.fontSizes[2] || theme2.fontSizes[1];
257707
- return /* @__PURE__ */ jsxs(
257708
- "div",
257709
- {
257710
- style: {
257711
- display: "flex",
257712
- flexDirection: "column",
257713
- gap: compact ? 4 : 8,
257714
- padding: compact ? "8px 12px" : "12px 16px",
257715
- backgroundColor: theme2.colors.background,
257716
- borderBottom: `1px solid ${theme2.colors.border}`,
257717
- fontFamily: theme2.fonts.body,
257718
- minHeight: compact ? 48 : "auto"
257719
- },
257720
- children: [
257721
- /* @__PURE__ */ jsxs(
257722
- "div",
257723
- {
257724
- style: {
257725
- display: "flex",
257726
- alignItems: "center",
257727
- justifyContent: "space-between",
257728
- gap: 12
257729
- },
257730
- children: [
257731
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, flex: 1, minWidth: 0 }, children: [
257732
- project.packageManager && /* @__PURE__ */ jsx("div", { style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx(
257733
- PackageManagerIcon,
257734
- {
257735
- packageManager: project.packageManager,
257736
- size: compact ? 18 : 20,
257737
- color: theme2.colors.textSecondary
257738
- }
257739
- ) }),
257740
- /* @__PURE__ */ jsx(
257741
- "span",
257742
- {
257743
- style: {
257744
- fontSize: compact ? fontSizeMedium : fontSizeLarge,
257745
- fontWeight: 600,
257746
- color: theme2.colors.text,
257747
- overflow: "hidden",
257748
- textOverflow: "ellipsis",
257749
- whiteSpace: "nowrap"
257750
- },
257751
- title: project.name,
257752
- children: project.name
257753
- }
257754
- ),
257755
- project.version && /* @__PURE__ */ jsxs(
257756
- "span",
257757
- {
257758
- style: {
257759
- fontSize: fontSizeSmall,
257760
- color: theme2.colors.textSecondary,
257761
- backgroundColor: theme2.colors.backgroundLight,
257648
+ const color2 = theme2.colors.primary ?? "#22d3ee";
257649
+ const pathRef = React.useRef(null);
257650
+ const buildingMarkerRef = React.useRef(null);
257651
+ const nodeMarkerRef = React.useRef(null);
257652
+ const projectScratch = React.useRef(new THREE.Vector3());
257653
+ const buildingRef = React.useRef(building);
257654
+ const cityCenterRef = React.useRef(cityCenter);
257655
+ React.useEffect(() => {
257656
+ buildingRef.current = building;
257657
+ }, [building]);
257658
+ React.useEffect(() => {
257659
+ cityCenterRef.current = cityCenter;
257660
+ }, [cityCenter]);
257661
+ const hideAll = React.useCallback(() => {
257662
+ var _a, _b, _c;
257663
+ (_a = pathRef.current) == null ? void 0 : _a.setAttribute("opacity", "0");
257664
+ (_b = buildingMarkerRef.current) == null ? void 0 : _b.setAttribute("opacity", "0");
257665
+ (_c = nodeMarkerRef.current) == null ? void 0 : _c.setAttribute("opacity", "0");
257666
+ }, []);
257667
+ React.useEffect(() => {
257668
+ if (!building) hideAll();
257669
+ }, [building, hideAll]);
257670
+ const onCameraFrame = React.useCallback(
257671
+ (camera, size) => {
257672
+ const target = buildingRef.current;
257673
+ const center = cityCenterRef.current;
257674
+ const container = containerRef.current;
257675
+ const nodeEl = targetRef.current;
257676
+ if (!target || !center || !nodeEl || !container || size.width === 0) {
257677
+ hideAll();
257678
+ return;
257679
+ }
257680
+ const containerRect = container.getBoundingClientRect();
257681
+ const nodeRect = nodeEl.getBoundingClientRect();
257682
+ const canvasEl = container.querySelector("canvas");
257683
+ if (!canvasEl) {
257684
+ hideAll();
257685
+ return;
257686
+ }
257687
+ const canvasRect = canvasEl.getBoundingClientRect();
257688
+ const canvasLeft = canvasRect.left - containerRect.left;
257689
+ const canvasTop = canvasRect.top - containerRect.top;
257690
+ const v = projectScratch.current;
257691
+ v.set(
257692
+ target.position.x - center.x,
257693
+ 0,
257694
+ target.position.z - center.z
257695
+ ).project(camera);
257696
+ const behindCamera = v.z > 1;
257697
+ if (behindCamera) {
257698
+ hideAll();
257699
+ return;
257700
+ }
257701
+ const sx = canvasLeft + (v.x * 0.5 + 0.5) * size.width;
257702
+ const sy = canvasTop + (v.y * -0.5 + 0.5) * size.height;
257703
+ const HEADER_BAND_OFFSET = 22;
257704
+ const nodeCenterX = nodeRect.left + nodeRect.width / 2 - containerRect.left;
257705
+ const aimRight = nodeCenterX < sx;
257706
+ const bx = aimRight ? nodeRect.right - containerRect.left : nodeRect.left - containerRect.left;
257707
+ const by = nodeRect.top - containerRect.top + HEADER_BAND_OFFSET;
257708
+ const dxRaw = (bx - sx) * 0.5;
257709
+ const dxAbs = Math.max(80, Math.abs(dxRaw));
257710
+ const dx = dxRaw < 0 ? -dxAbs : dxAbs;
257711
+ const d = `M ${sx} ${sy} C ${sx + dx} ${sy}, ${bx - dx} ${by}, ${bx} ${by}`;
257712
+ const pathEl = pathRef.current;
257713
+ const buildingEl = buildingMarkerRef.current;
257714
+ const nodeMarkerEl = nodeMarkerRef.current;
257715
+ if (pathEl) {
257716
+ pathEl.setAttribute("d", d);
257717
+ pathEl.setAttribute("stroke", color2);
257718
+ pathEl.setAttribute("opacity", "0.85");
257719
+ }
257720
+ if (buildingEl) {
257721
+ buildingEl.setAttribute("x", String(sx - 3.5));
257722
+ buildingEl.setAttribute("y", String(sy - 3.5));
257723
+ buildingEl.setAttribute("fill", color2);
257724
+ buildingEl.setAttribute("opacity", "1");
257725
+ }
257726
+ if (nodeMarkerEl) {
257727
+ nodeMarkerEl.setAttribute("cx", String(bx));
257728
+ nodeMarkerEl.setAttribute("cy", String(by));
257729
+ nodeMarkerEl.setAttribute("fill", color2);
257730
+ nodeMarkerEl.setAttribute("opacity", "1");
257731
+ }
257732
+ },
257733
+ [containerRef, targetRef, hideAll, color2]
257734
+ );
257735
+ React.useImperativeHandle(ref, () => ({ onCameraFrame }), [onCameraFrame]);
257736
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
257737
+ /* @__PURE__ */ jsxs(
257738
+ "svg",
257739
+ {
257740
+ width: "100%",
257741
+ height: "100%",
257742
+ style: {
257743
+ position: "absolute",
257744
+ inset: 0,
257745
+ pointerEvents: "none",
257746
+ overflow: "visible",
257747
+ // Above the 3D canvas (auto z-index) but below the floating
257748
+ // overlays (z 1900), so the line only paints over the city.
257749
+ zIndex: 25
257750
+ },
257751
+ children: [
257752
+ /* @__PURE__ */ jsx(
257753
+ "path",
257754
+ {
257755
+ ref: pathRef,
257756
+ fill: "none",
257757
+ strokeWidth: 1.75,
257758
+ strokeDasharray: "5 4",
257759
+ opacity: 0
257760
+ }
257761
+ ),
257762
+ /* @__PURE__ */ jsx(
257763
+ "rect",
257764
+ {
257765
+ ref: buildingMarkerRef,
257766
+ width: 7,
257767
+ height: 7,
257768
+ stroke: "#0f1419",
257769
+ strokeWidth: 1.25,
257770
+ opacity: 0
257771
+ }
257772
+ )
257773
+ ]
257774
+ }
257775
+ ),
257776
+ /* @__PURE__ */ jsx(
257777
+ "svg",
257778
+ {
257779
+ width: "100%",
257780
+ height: "100%",
257781
+ style: {
257782
+ position: "absolute",
257783
+ inset: 0,
257784
+ pointerEvents: "none",
257785
+ overflow: "visible",
257786
+ zIndex: 1901
257787
+ },
257788
+ children: /* @__PURE__ */ jsx("circle", { ref: nodeMarkerRef, r: 3.5, opacity: 0 })
257789
+ }
257790
+ )
257791
+ ] });
257792
+ });
257793
+ const PANEL_WIDTH_PCT = 38;
257794
+ const FLOAT_INSET = 16;
257795
+ const TOP_INSET = 16;
257796
+ const MIN_WIDTH_PX = 360;
257797
+ const RESIZE_HANDLE_WIDTH = 6;
257798
+ const TrailMarkdownOverlay = ({
257799
+ eyebrow,
257800
+ title,
257801
+ markdown: markdown2,
257802
+ slideIdPrefix,
257803
+ bottomOffset,
257804
+ containerRef: externalContainerRef
257805
+ }) => {
257806
+ const { theme: theme2 } = useTheme();
257807
+ const body = markdown2.trim();
257808
+ const bottomOffsetCss = typeof bottomOffset === "number" ? `${bottomOffset}px` : bottomOffset;
257809
+ const [hasEntered, setHasEntered] = React.useState(false);
257810
+ const [widthPx, setWidthPx] = React.useState(null);
257811
+ const [isResizing, setIsResizing] = React.useState(false);
257812
+ const containerRef = React.useRef(null);
257813
+ const setContainerRef = React.useCallback(
257814
+ (node2) => {
257815
+ containerRef.current = node2;
257816
+ if (typeof externalContainerRef === "function") {
257817
+ externalContainerRef(node2);
257818
+ } else if (externalContainerRef) {
257819
+ externalContainerRef.current = node2;
257820
+ }
257821
+ },
257822
+ [externalContainerRef]
257823
+ );
257824
+ const dragStateRef = React.useRef(null);
257825
+ const handleResizePointerDown = React.useCallback(
257826
+ (e) => {
257827
+ if (e.button !== 0) return;
257828
+ const el = containerRef.current;
257829
+ if (!el) return;
257830
+ e.preventDefault();
257831
+ dragStateRef.current = {
257832
+ startX: e.clientX,
257833
+ startWidth: el.getBoundingClientRect().width
257834
+ };
257835
+ setIsResizing(true);
257836
+ e.currentTarget.setPointerCapture(e.pointerId);
257837
+ },
257838
+ []
257839
+ );
257840
+ const handleResizePointerMove = React.useCallback(
257841
+ (e) => {
257842
+ var _a;
257843
+ const drag2 = dragStateRef.current;
257844
+ if (!drag2) return;
257845
+ const parent = (_a = containerRef.current) == null ? void 0 : _a.parentElement;
257846
+ const parentWidth = (parent == null ? void 0 : parent.clientWidth) ?? window.innerWidth;
257847
+ const maxWidth = Math.max(MIN_WIDTH_PX, parentWidth - FLOAT_INSET * 2);
257848
+ const dx = e.clientX - drag2.startX;
257849
+ const next2 = Math.min(maxWidth, Math.max(MIN_WIDTH_PX, drag2.startWidth + dx));
257850
+ setWidthPx(next2);
257851
+ },
257852
+ []
257853
+ );
257854
+ const handleResizePointerUp = React.useCallback(
257855
+ (e) => {
257856
+ if (!dragStateRef.current) return;
257857
+ dragStateRef.current = null;
257858
+ setIsResizing(false);
257859
+ if (e.currentTarget.hasPointerCapture(e.pointerId)) {
257860
+ e.currentTarget.releasePointerCapture(e.pointerId);
257861
+ }
257862
+ },
257863
+ []
257864
+ );
257865
+ if (!body) return null;
257866
+ return /* @__PURE__ */ jsxs(
257867
+ "div",
257868
+ {
257869
+ ref: setContainerRef,
257870
+ onAnimationEnd: () => setHasEntered(true),
257871
+ style: {
257872
+ position: "absolute",
257873
+ top: TOP_INSET,
257874
+ left: FLOAT_INSET,
257875
+ bottom: `calc(${bottomOffsetCss} + ${FLOAT_INSET}px)`,
257876
+ width: widthPx != null ? widthPx : `calc(${PANEL_WIDTH_PCT}% - ${FLOAT_INSET}px)`,
257877
+ minWidth: MIN_WIDTH_PX,
257878
+ backgroundColor: theme2.colors.background,
257879
+ border: `1px solid ${theme2.colors.border}`,
257880
+ borderRadius: 12,
257881
+ overflow: "hidden",
257882
+ boxShadow: "0 12px 32px rgba(0, 0, 0, 0.28)",
257883
+ display: "flex",
257884
+ flexDirection: "column",
257885
+ zIndex: 1900,
257886
+ animation: hasEntered || isResizing ? void 0 : "trailMarkdownOverlaySlideIn 220ms ease-out",
257887
+ userSelect: isResizing ? "none" : void 0
257888
+ },
257889
+ children: [
257890
+ /* @__PURE__ */ jsx("style", { children: `
257891
+ @keyframes trailMarkdownOverlaySlideIn {
257892
+ from { transform: translateX(-100%); }
257893
+ to { transform: translateX(0); }
257894
+ }
257895
+ ` }),
257896
+ /* @__PURE__ */ jsxs(
257897
+ "div",
257898
+ {
257899
+ style: {
257900
+ padding: "10px 14px",
257901
+ borderBottom: `1px solid ${theme2.colors.border}`,
257902
+ display: "flex",
257903
+ flexDirection: "column",
257904
+ color: theme2.colors.text,
257905
+ fontFamily: theme2.fonts.body,
257906
+ flexShrink: 0,
257907
+ minWidth: 0
257908
+ },
257909
+ children: [
257910
+ /* @__PURE__ */ jsx(
257911
+ "span",
257912
+ {
257913
+ style: {
257914
+ fontSize: theme2.fontSizes[0],
257915
+ color: theme2.colors.textSecondary,
257916
+ letterSpacing: 0.4,
257917
+ textTransform: "uppercase"
257918
+ },
257919
+ children: eyebrow
257920
+ }
257921
+ ),
257922
+ /* @__PURE__ */ jsx(
257923
+ "span",
257924
+ {
257925
+ style: {
257926
+ fontSize: theme2.fontSizes[1],
257927
+ fontWeight: 600,
257928
+ overflow: "hidden",
257929
+ textOverflow: "ellipsis",
257930
+ whiteSpace: "nowrap"
257931
+ },
257932
+ title,
257933
+ children: title
257934
+ }
257935
+ )
257936
+ ]
257937
+ }
257938
+ ),
257939
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: 0, position: "relative" }, children: /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0 }, children: /* @__PURE__ */ jsx(
257940
+ IndustryMarkdownSlide,
257941
+ {
257942
+ content: body,
257943
+ slideIdPrefix,
257944
+ slideIndex: 0,
257945
+ isVisible: true,
257946
+ theme: theme2,
257947
+ transparentBackground: true,
257948
+ enableKeyboardScrolling: false
257949
+ }
257950
+ ) }) }),
257951
+ /* @__PURE__ */ jsx(
257952
+ "div",
257953
+ {
257954
+ role: "separator",
257955
+ "aria-orientation": "vertical",
257956
+ "aria-label": "Resize markdown panel",
257957
+ onPointerDown: handleResizePointerDown,
257958
+ onPointerMove: handleResizePointerMove,
257959
+ onPointerUp: handleResizePointerUp,
257960
+ onPointerCancel: handleResizePointerUp,
257961
+ style: {
257962
+ position: "absolute",
257963
+ top: 0,
257964
+ right: 0,
257965
+ bottom: 0,
257966
+ width: RESIZE_HANDLE_WIDTH,
257967
+ cursor: "ew-resize",
257968
+ backgroundColor: isResizing ? theme2.colors.accent : "transparent",
257969
+ transition: isResizing ? void 0 : "background-color 120ms ease",
257970
+ touchAction: "none"
257971
+ },
257972
+ onMouseEnter: (e) => {
257973
+ if (isResizing) return;
257974
+ e.currentTarget.style.backgroundColor = theme2.colors.border;
257975
+ },
257976
+ onMouseLeave: (e) => {
257977
+ if (isResizing) return;
257978
+ e.currentTarget.style.backgroundColor = "transparent";
257979
+ }
257980
+ }
257981
+ )
257982
+ ]
257983
+ }
257984
+ );
257985
+ };
257986
+ const TrailSnippetView = ({
257987
+ filePath,
257988
+ fileName,
257989
+ startLine,
257990
+ endLine,
257991
+ focusLine,
257992
+ contextLines = 2,
257993
+ readFile,
257994
+ background
257995
+ }) => {
257996
+ const { theme: theme2 } = useTheme();
257997
+ const [contents, setContents] = React.useState(null);
257998
+ const [error, setError] = React.useState(null);
257999
+ React.useEffect(() => {
258000
+ let cancelled = false;
258001
+ setContents(null);
258002
+ setError(null);
258003
+ readFile(filePath).then((content2) => {
258004
+ if (cancelled) return;
258005
+ setContents(content2);
258006
+ }).catch((err) => {
258007
+ if (cancelled) return;
258008
+ setError(err instanceof Error ? err.message : "Failed to read file");
258009
+ });
258010
+ return () => {
258011
+ cancelled = true;
258012
+ };
258013
+ }, [filePath, readFile]);
258014
+ const slice = React.useMemo(() => {
258015
+ if (contents == null) return null;
258016
+ const allLines = contents.split("\n");
258017
+ const total = allLines.length;
258018
+ const safeStart = Math.max(1, Math.min(startLine, total));
258019
+ const safeEnd = Math.max(safeStart, Math.min(endLine, total));
258020
+ const sliceStart = Math.max(1, safeStart - contextLines);
258021
+ const sliceEnd = Math.min(total, safeEnd + contextLines);
258022
+ return {
258023
+ contents: allLines.slice(sliceStart - 1, sliceEnd).join("\n"),
258024
+ sliceStart,
258025
+ sliceEnd,
258026
+ focusOffset: focusLine == null ? null : Math.max(1, focusLine - sliceStart + 1)
258027
+ };
258028
+ }, [contents, startLine, endLine, contextLines, focusLine]);
258029
+ const fileObject = React.useMemo(
258030
+ () => slice ? { name: fileName, contents: slice.contents } : null,
258031
+ [fileName, slice]
258032
+ );
258033
+ const lineNumberOffset = slice ? slice.sliceStart - 1 : 0;
258034
+ const onPostRender = React.useCallback(
258035
+ (fileContainer) => {
258036
+ if (lineNumberOffset === 0) return;
258037
+ const root2 = fileContainer.shadowRoot ?? fileContainer;
258038
+ const items = root2.querySelectorAll(
258039
+ "[data-column-number][data-line-index]"
258040
+ );
258041
+ items.forEach((el) => {
258042
+ const idxStr = el.dataset.lineIndex;
258043
+ if (idxStr == null) return;
258044
+ const idx = Number.parseInt(idxStr, 10);
258045
+ if (Number.isNaN(idx)) return;
258046
+ const display = String(idx + 1 + lineNumberOffset);
258047
+ const span = el.querySelector(
258048
+ "[data-line-number-content]"
258049
+ );
258050
+ if (span && span.textContent !== display) {
258051
+ span.textContent = display;
258052
+ }
258053
+ });
258054
+ },
258055
+ [lineNumberOffset]
258056
+ );
258057
+ const options = React.useMemo(() => {
258058
+ const base2 = background ? buildPierreOptions(background) : pierreOptions;
258059
+ return { ...base2, onPostRender };
258060
+ }, [background, onPostRender]);
258061
+ if (error) {
258062
+ return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.error }, children: error });
258063
+ }
258064
+ if (!fileObject || !slice) {
258065
+ return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.textSecondary }, children: "Loading…" });
258066
+ }
258067
+ const rangeLabel = slice.sliceStart === slice.sliceEnd ? `Line ${slice.sliceStart}` : `Lines ${slice.sliceStart}–${slice.sliceEnd}`;
258068
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", minHeight: 0 }, children: [
258069
+ /* @__PURE__ */ jsx(
258070
+ "div",
258071
+ {
258072
+ style: {
258073
+ padding: "4px 14px 6px",
258074
+ fontFamily: theme2.fonts.monospace,
258075
+ fontSize: theme2.fontSizes[0],
258076
+ color: theme2.colors.textSecondary,
258077
+ letterSpacing: 0.4,
258078
+ textTransform: "uppercase"
258079
+ },
258080
+ children: rangeLabel
258081
+ }
258082
+ ),
258083
+ /* @__PURE__ */ jsx(
258084
+ File$2,
258085
+ {
258086
+ file: fileObject,
258087
+ options,
258088
+ selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
258089
+ style: pierreStyle$1
258090
+ }
258091
+ )
258092
+ ] });
258093
+ };
258094
+ const buildBackgroundCSS = (color2) => `
258095
+ :host {
258096
+ background: ${color2} !important;
258097
+ }
258098
+ pre, code,
258099
+ [data-gutter], [data-content],
258100
+ [data-line], [data-column-number],
258101
+ [data-gutter-buffer], [data-line-annotation], [data-no-newline],
258102
+ [data-separator], [data-separator-wrapper] {
258103
+ background: ${color2} !important;
258104
+ }
258105
+ [data-line] span {
258106
+ background: ${color2} !important;
258107
+ }
258108
+ `;
258109
+ const pierreOptions = {
258110
+ disableFileHeader: true
258111
+ };
258112
+ const buildPierreOptions = (background) => ({
258113
+ disableFileHeader: true,
258114
+ unsafeCSS: buildBackgroundCSS(background)
258115
+ });
258116
+ const pierreStyle$1 = {
258117
+ display: "block"
258118
+ };
258119
+ const sliceWindow = (oldContents, newContents, startLine, endLine, focusLine, contextLines) => {
258120
+ if (startLine == null || endLine == null) {
258121
+ return {
258122
+ oldText: oldContents,
258123
+ newText: newContents,
258124
+ windowStart: 1,
258125
+ focusOffset: focusLine ?? null
258126
+ };
258127
+ }
258128
+ const oldLines = oldContents.split("\n");
258129
+ const newLines = newContents.split("\n");
258130
+ const totalNew = newLines.length;
258131
+ const totalOld = oldLines.length;
258132
+ const safeStart = Math.max(1, Math.min(startLine, totalNew));
258133
+ const safeEnd = Math.max(safeStart, Math.min(endLine, totalNew));
258134
+ const sliceStart = Math.max(1, safeStart - contextLines);
258135
+ const sliceEnd = Math.min(
258136
+ Math.max(totalOld, totalNew),
258137
+ safeEnd + contextLines
258138
+ );
258139
+ const sliceOldEnd = Math.min(totalOld, sliceEnd);
258140
+ const sliceNewEnd = Math.min(totalNew, sliceEnd);
258141
+ return {
258142
+ oldText: oldLines.slice(sliceStart - 1, sliceOldEnd).join("\n"),
258143
+ newText: newLines.slice(sliceStart - 1, sliceNewEnd).join("\n"),
258144
+ windowStart: sliceStart,
258145
+ focusOffset: focusLine == null ? null : Math.max(1, focusLine - sliceStart + 1)
258146
+ };
258147
+ };
258148
+ const TrailDiffSnippetView = ({
258149
+ filePath,
258150
+ fileName,
258151
+ oldContents,
258152
+ newContents,
258153
+ readFile,
258154
+ startLine,
258155
+ endLine,
258156
+ focusLine,
258157
+ contextLines = 2,
258158
+ background,
258159
+ diffStyle = "unified"
258160
+ }) => {
258161
+ const { theme: theme2 } = useTheme();
258162
+ const [resolvedNew, setResolvedNew] = React.useState(
258163
+ newContents ?? null
258164
+ );
258165
+ const [error, setError] = React.useState(null);
258166
+ React.useEffect(() => {
258167
+ if (newContents !== void 0) {
258168
+ setResolvedNew(newContents);
258169
+ setError(null);
258170
+ return;
258171
+ }
258172
+ let cancelled = false;
258173
+ setResolvedNew(null);
258174
+ setError(null);
258175
+ readFile(filePath).then((content2) => {
258176
+ if (cancelled) return;
258177
+ setResolvedNew(content2);
258178
+ }).catch((err) => {
258179
+ if (cancelled) return;
258180
+ setError(err instanceof Error ? err.message : "Failed to read file");
258181
+ });
258182
+ return () => {
258183
+ cancelled = true;
258184
+ };
258185
+ }, [filePath, newContents, readFile]);
258186
+ const slice = React.useMemo(
258187
+ () => resolvedNew == null ? null : sliceWindow(
258188
+ oldContents,
258189
+ resolvedNew,
258190
+ startLine,
258191
+ endLine,
258192
+ focusLine,
258193
+ contextLines
258194
+ ),
258195
+ [oldContents, resolvedNew, startLine, endLine, focusLine, contextLines]
258196
+ );
258197
+ const fileDiff = React.useMemo(() => {
258198
+ if (!slice) return null;
258199
+ try {
258200
+ return parseDiffFromFile(
258201
+ { name: fileName, contents: slice.oldText },
258202
+ { name: fileName, contents: slice.newText }
258203
+ );
258204
+ } catch {
258205
+ return null;
258206
+ }
258207
+ }, [fileName, slice]);
258208
+ if (error) {
258209
+ return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.error }, children: error });
258210
+ }
258211
+ if (!slice) {
258212
+ return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.textSecondary }, children: "Loading…" });
258213
+ }
258214
+ if (!fileDiff) {
258215
+ return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.error }, children: "Failed to compute diff" });
258216
+ }
258217
+ const rangeLabel = startLine != null && endLine != null ? startLine === endLine ? `Line ${startLine}` : `Lines ${startLine}–${endLine}` : null;
258218
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", minHeight: 0 }, children: [
258219
+ rangeLabel && /* @__PURE__ */ jsx(
258220
+ "div",
258221
+ {
258222
+ style: {
258223
+ padding: "4px 14px 6px",
258224
+ fontFamily: theme2.fonts.monospace,
258225
+ fontSize: theme2.fontSizes[0],
258226
+ color: theme2.colors.textSecondary,
258227
+ letterSpacing: 0.4,
258228
+ textTransform: "uppercase"
258229
+ },
258230
+ children: rangeLabel
258231
+ }
258232
+ ),
258233
+ /* @__PURE__ */ jsx(
258234
+ FileDiff$2,
258235
+ {
258236
+ fileDiff,
258237
+ options: { ...pierreOptionsBase, diffStyle },
258238
+ selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
258239
+ style: background ? {
258240
+ ...pierreStyle,
258241
+ // Pierre derives addition/deletion/context surfaces by
258242
+ // `color-mix`ing from --diffs-bg, which is keyed off
258243
+ // --diffs-light-bg / --diffs-dark-bg. Overriding the
258244
+ // source variables recolors the whole palette coherently.
258245
+ ["--diffs-light-bg"]: background,
258246
+ ["--diffs-dark-bg"]: background
258247
+ } : pierreStyle
258248
+ }
258249
+ )
258250
+ ] });
258251
+ };
258252
+ const pierreOptionsBase = {
258253
+ disableFileHeader: true
258254
+ };
258255
+ const pierreStyle = {
258256
+ display: "block"
258257
+ };
258258
+ const SEQUENCE_DRAWER_HEIGHT_PCT = 38;
258259
+ const SNIPPET_PANE_WIDTH_PX = 460;
258260
+ const HEADER_HEIGHT_PX = 48;
258261
+ const SNIPPET_PANE_BG = "#0b0f14";
258262
+ const FileCityTrailExplorerPanel = ({ context, actions }) => {
258263
+ var _a;
258264
+ const tree = context.fileTree.data;
258265
+ const lineCounts = ((_a = context.lineCounts.data) == null ? void 0 : _a.lineCounts) ?? null;
258266
+ const trail2 = context.trail.data;
258267
+ const repository = context.repository;
258268
+ const cityData = React.useMemo(
258269
+ () => tree ? buildCityDataFromContext({ fileTree: tree, lineCounts }) : null,
258270
+ [tree, lineCounts]
258271
+ );
258272
+ const [selectedMarkerId, setSelectedMarkerId] = React.useState(null);
258273
+ React.useEffect(() => {
258274
+ setSelectedMarkerId(null);
258275
+ }, [trail2 == null ? void 0 : trail2.id]);
258276
+ const markersForThisRepo = React.useMemo(() => {
258277
+ if (!trail2) return [];
258278
+ return filterMarkersForRepo(trail2, repository);
258279
+ }, [trail2, repository]);
258280
+ if (!trail2) {
258281
+ return /* @__PURE__ */ jsx(
258282
+ FileCityTrailExplorerEmptyState,
258283
+ {
258284
+ message: "No trail loaded.",
258285
+ cityData
258286
+ }
258287
+ );
258288
+ }
258289
+ const view = trail2.views[0];
258290
+ if (!view) {
258291
+ return /* @__PURE__ */ jsx(
258292
+ FileCityTrailExplorerEmptyState,
258293
+ {
258294
+ message: "Trail has no views.",
258295
+ cityData
258296
+ }
258297
+ );
258298
+ }
258299
+ if (view.kind !== "sequence") {
258300
+ return /* @__PURE__ */ jsx(
258301
+ FileCityTrailExplorerEmptyState,
258302
+ {
258303
+ message: `Unsupported view kind: ${view.kind}. v1 only renders kind:'sequence'.`,
258304
+ cityData
258305
+ }
258306
+ );
258307
+ }
258308
+ return /* @__PURE__ */ jsx(
258309
+ FileCityTrailSequenceLayout,
258310
+ {
258311
+ trail: trail2,
258312
+ view,
258313
+ markersForThisRepo,
258314
+ selectedMarkerId,
258315
+ onSelectMarker: setSelectedMarkerId,
258316
+ cityData,
258317
+ readFile: actions.readFile
258318
+ }
258319
+ );
258320
+ };
258321
+ const FileCityTrailSequenceLayout = ({
258322
+ trail: trail2,
258323
+ view,
258324
+ markersForThisRepo,
258325
+ selectedMarkerId,
258326
+ onSelectMarker,
258327
+ cityData,
258328
+ readFile
258329
+ }) => {
258330
+ var _a, _b;
258331
+ const selectedMarker = React.useMemo(() => {
258332
+ if (!selectedMarkerId) return null;
258333
+ return trail2.markers.find((m) => m.id === selectedMarkerId) ?? null;
258334
+ }, [trail2.markers, selectedMarkerId]);
258335
+ const markerBySourcePathForThisRepo = React.useMemo(() => {
258336
+ const map2 = /* @__PURE__ */ new Map();
258337
+ for (const m of markersForThisRepo) {
258338
+ if (m.sourcePath) map2.set(m.sourcePath, m);
258339
+ }
258340
+ return map2;
258341
+ }, [markersForThisRepo]);
258342
+ const handleBuildingClick = React.useCallback(
258343
+ (building) => {
258344
+ const marker = markerBySourcePathForThisRepo.get(building.path);
258345
+ if (!marker) return;
258346
+ onSelectMarker(selectedMarkerId === marker.id ? null : marker.id);
258347
+ },
258348
+ [markerBySourcePathForThisRepo, selectedMarkerId, onSelectMarker]
258349
+ );
258350
+ const containerRef = React.useRef(null);
258351
+ const snippetPaneRef = React.useRef(null);
258352
+ const leaderLineRef = React.useRef(null);
258353
+ const [markdownOverlayWidth, setMarkdownOverlayWidth] = React.useState(null);
258354
+ const [containerSize, setContainerSize] = React.useState(null);
258355
+ const selectedBuilding = React.useMemo(() => {
258356
+ if (!cityData || !(selectedMarker == null ? void 0 : selectedMarker.sourcePath)) return null;
258357
+ const path2 = selectedMarker.sourcePath;
258358
+ return cityData.buildings.find((b) => b.path === path2) ?? cityData.buildings.find((b) => b.path.endsWith(`/${path2}`)) ?? null;
258359
+ }, [cityData, selectedMarker]);
258360
+ const cityCenter = React.useMemo(() => {
258361
+ if (!cityData) return null;
258362
+ return {
258363
+ x: (cityData.bounds.minX + cityData.bounds.maxX) / 2,
258364
+ z: (cityData.bounds.minZ + cityData.bounds.maxZ) / 2
258365
+ };
258366
+ }, [cityData]);
258367
+ const onCameraFrame = React.useCallback(
258368
+ (camera, size) => {
258369
+ var _a2;
258370
+ (_a2 = leaderLineRef.current) == null ? void 0 : _a2.onCameraFrame(camera, size);
258371
+ },
258372
+ []
258373
+ );
258374
+ React.useEffect(() => {
258375
+ const el = containerRef.current;
258376
+ if (!el) return;
258377
+ const update = () => {
258378
+ const rect = el.getBoundingClientRect();
258379
+ setContainerSize({ width: rect.width, height: rect.height });
258380
+ };
258381
+ update();
258382
+ const observer = new ResizeObserver(update);
258383
+ observer.observe(el);
258384
+ return () => observer.disconnect();
258385
+ }, []);
258386
+ const [markdownOverlayEl, setMarkdownOverlayEl] = React.useState(null);
258387
+ React.useEffect(() => {
258388
+ if (!markdownOverlayEl) {
258389
+ setMarkdownOverlayWidth(null);
258390
+ return;
258391
+ }
258392
+ const update = () => setMarkdownOverlayWidth(markdownOverlayEl.getBoundingClientRect().width);
258393
+ update();
258394
+ const observer = new ResizeObserver(update);
258395
+ observer.observe(markdownOverlayEl);
258396
+ return () => observer.disconnect();
258397
+ }, [markdownOverlayEl]);
258398
+ const overlayMarkdown = ((_a = selectedMarker == null ? void 0 : selectedMarker.description) == null ? void 0 : _a.trim()) ? {
258399
+ eyebrow: "Marker",
258400
+ title: selectedMarker.label ?? selectedMarker.id,
258401
+ markdown: selectedMarker.description,
258402
+ slideIdPrefix: `trail-${trail2.id}-marker-${selectedMarker.id}`
258403
+ } : ((_b = trail2.summary) == null ? void 0 : _b.trim()) ? {
258404
+ eyebrow: "Trail",
258405
+ title: trail2.title,
258406
+ markdown: trail2.summary,
258407
+ slideIdPrefix: `trail-${trail2.id}-summary`
258408
+ } : null;
258409
+ const hasOverlayMarkdown = overlayMarkdown != null;
258410
+ const showSnippetPane = !!(selectedMarker == null ? void 0 : selectedMarker.snippet);
258411
+ React.useEffect(() => {
258412
+ if (!cityData || !containerSize) return;
258413
+ let cancelled = false;
258414
+ let waitId = null;
258415
+ const apply = () => {
258416
+ if (cancelled) return;
258417
+ if (hasOverlayMarkdown && markdownOverlayWidth == null) return;
258418
+ const FLOAT_INSET2 = 16;
258419
+ const leftInset = hasOverlayMarkdown ? FLOAT_INSET2 + (markdownOverlayWidth ?? 0) : 0;
258420
+ const snippetW = Math.min(
258421
+ SNIPPET_PANE_WIDTH_PX,
258422
+ containerSize.width / 2
258423
+ );
258424
+ const rightInset = showSnippetPane ? snippetW + FLOAT_INSET2 : 0;
258425
+ const topInset = FLOAT_INSET2;
258426
+ const bottomInset = SEQUENCE_DRAWER_HEIGHT_PCT / 100 * containerSize.height;
258427
+ const result = computeCameraFraming({
258428
+ canvasW: containerSize.width,
258429
+ canvasH: containerSize.height,
258430
+ cityBounds: cityData.bounds,
258431
+ leftInset,
258432
+ rightInset,
258433
+ topInset,
258434
+ bottomInset
258435
+ });
258436
+ if (!result) return;
258437
+ setCameraFlatView(result.targetX, result.targetZ, result.height, {
258438
+ duration: 400
258439
+ });
258440
+ };
258441
+ const handle2 = setTimeout(() => {
258442
+ if (getCameraPosition() != null) {
258443
+ apply();
258444
+ return;
258445
+ }
258446
+ let waited = 0;
258447
+ waitId = setInterval(() => {
258448
+ waited += 50;
258449
+ if (cancelled) return;
258450
+ if (getCameraPosition() != null) {
258451
+ if (waitId) clearInterval(waitId);
258452
+ waitId = null;
258453
+ apply();
258454
+ } else if (waited >= 3e3) {
258455
+ if (waitId) clearInterval(waitId);
258456
+ waitId = null;
258457
+ }
258458
+ }, 50);
258459
+ }, 350);
258460
+ return () => {
258461
+ cancelled = true;
258462
+ clearTimeout(handle2);
258463
+ if (waitId) clearInterval(waitId);
258464
+ };
258465
+ }, [
258466
+ cityData,
258467
+ containerSize,
258468
+ showSnippetPane,
258469
+ hasOverlayMarkdown,
258470
+ markdownOverlayWidth
258471
+ ]);
258472
+ return /* @__PURE__ */ jsxs(
258473
+ "div",
258474
+ {
258475
+ style: {
258476
+ position: "relative",
258477
+ width: "100%",
258478
+ height: "100%",
258479
+ display: "flex",
258480
+ flexDirection: "column",
258481
+ backgroundColor: "#0b0f14",
258482
+ color: "#e5e7eb"
258483
+ },
258484
+ children: [
258485
+ /* @__PURE__ */ jsx(TrailHeader, { trail: trail2, markerCount: markersForThisRepo.length }),
258486
+ /* @__PURE__ */ jsxs(
258487
+ "div",
258488
+ {
258489
+ ref: containerRef,
258490
+ style: {
258491
+ flex: 1,
258492
+ position: "relative",
258493
+ minHeight: 0,
258494
+ overflow: "hidden"
258495
+ },
258496
+ children: [
258497
+ cityData ? /* @__PURE__ */ jsx(
258498
+ FileCity3D,
258499
+ {
258500
+ cityData,
258501
+ width: "100%",
258502
+ height: "100%",
258503
+ selectedPath: (selectedMarker == null ? void 0 : selectedMarker.sourcePath) ?? null,
258504
+ onBuildingClick: handleBuildingClick,
258505
+ onCameraFrame,
258506
+ showControls: false,
258507
+ backgroundColor: "#0b0f14"
258508
+ }
258509
+ ) : /* @__PURE__ */ jsx(CityLoadingPlaceholder, {}),
258510
+ /* @__PURE__ */ jsx(
258511
+ TrailLeaderLine,
258512
+ {
258513
+ ref: leaderLineRef,
258514
+ containerRef,
258515
+ building: selectedBuilding,
258516
+ cityCenter,
258517
+ targetRef: snippetPaneRef
258518
+ }
258519
+ ),
258520
+ overlayMarkdown ? /* @__PURE__ */ jsx(
258521
+ TrailMarkdownOverlay,
258522
+ {
258523
+ eyebrow: overlayMarkdown.eyebrow,
258524
+ title: overlayMarkdown.title,
258525
+ markdown: overlayMarkdown.markdown,
258526
+ slideIdPrefix: overlayMarkdown.slideIdPrefix,
258527
+ bottomOffset: `${SEQUENCE_DRAWER_HEIGHT_PCT}%`,
258528
+ containerRef: setMarkdownOverlayEl
258529
+ }
258530
+ ) : null,
258531
+ /* @__PURE__ */ jsx(
258532
+ SequenceDrawer,
258533
+ {
258534
+ trail: trail2,
258535
+ view,
258536
+ selectedMarkerId,
258537
+ onSelectMarker
258538
+ }
258539
+ ),
258540
+ (selectedMarker == null ? void 0 : selectedMarker.snippet) ? /* @__PURE__ */ jsx(
258541
+ SnippetSidePane,
258542
+ {
258543
+ ref: snippetPaneRef,
258544
+ marker: selectedMarker,
258545
+ snippet: selectedMarker.snippet,
258546
+ readFile,
258547
+ onClose: () => onSelectMarker(null)
258548
+ }
258549
+ ) : null
258550
+ ]
258551
+ }
258552
+ )
258553
+ ]
258554
+ }
258555
+ );
258556
+ };
258557
+ const SequenceDrawer = ({
258558
+ trail: trail2,
258559
+ view,
258560
+ selectedMarkerId,
258561
+ onSelectMarker
258562
+ }) => {
258563
+ const inputs = React.useMemo(
258564
+ () => buildSequenceViewInputs(trail2, view),
258565
+ [trail2, view]
258566
+ );
258567
+ const handleNodeClick2 = React.useCallback(
258568
+ (nodeId) => {
258569
+ if (nodeId.startsWith("__actor:")) return;
258570
+ onSelectMarker(selectedMarkerId === nodeId ? null : nodeId);
258571
+ },
258572
+ [onSelectMarker, selectedMarkerId]
258573
+ );
258574
+ return /* @__PURE__ */ jsx(
258575
+ "div",
258576
+ {
258577
+ style: {
258578
+ position: "absolute",
258579
+ left: 0,
258580
+ right: 0,
258581
+ bottom: 0,
258582
+ height: `${SEQUENCE_DRAWER_HEIGHT_PCT}%`,
258583
+ backgroundColor: "rgba(11, 15, 20, 0.92)",
258584
+ borderTop: "1px solid #1f2937",
258585
+ zIndex: 10
258586
+ },
258587
+ children: /* @__PURE__ */ jsx(
258588
+ SequenceDiagramRenderer,
258589
+ {
258590
+ events: inputs.events,
258591
+ edges: inputs.edges,
258592
+ layoutOptions: inputs.layoutOptions,
258593
+ width: "100%",
258594
+ height: "100%",
258595
+ showControls: false,
258596
+ showBackground: false,
258597
+ stickyHeaders: true,
258598
+ selectedNodeId: selectedMarkerId ?? void 0,
258599
+ onNodeClick: handleNodeClick2
258600
+ }
258601
+ )
258602
+ }
258603
+ );
258604
+ };
258605
+ const SnippetSidePane = React.forwardRef(function SnippetSidePane2({ marker, snippet: snippet2, readFile, onClose }, ref) {
258606
+ if (!marker.sourcePath) {
258607
+ return /* @__PURE__ */ jsx(SidePaneFrame, { ref, marker, onClose, children: /* @__PURE__ */ jsx("div", { style: { fontSize: 11, opacity: 0.6, padding: 8 }, children: "Marker has no sourcePath; snippet cannot be rendered." }) });
258608
+ }
258609
+ const fileName = marker.sourcePath.split("/").pop() ?? marker.sourcePath;
258610
+ return /* @__PURE__ */ jsx(SidePaneFrame, { ref, marker, onClose, children: snippet2.kind === "slice" ? /* @__PURE__ */ jsx(
258611
+ TrailSnippetView,
258612
+ {
258613
+ filePath: marker.sourcePath,
258614
+ fileName,
258615
+ startLine: snippet2.startLine,
258616
+ endLine: snippet2.endLine,
258617
+ focusLine: snippet2.focusLine,
258618
+ contextLines: snippet2.contextLines,
258619
+ readFile,
258620
+ background: SNIPPET_PANE_BG
258621
+ }
258622
+ ) : /* @__PURE__ */ jsx(
258623
+ TrailDiffSnippetView,
258624
+ {
258625
+ filePath: marker.sourcePath,
258626
+ fileName,
258627
+ oldContents: snippet2.oldContents,
258628
+ newContents: snippet2.newContents,
258629
+ readFile,
258630
+ startLine: snippet2.startLine,
258631
+ endLine: snippet2.endLine,
258632
+ focusLine: snippet2.focusLine,
258633
+ contextLines: snippet2.contextLines,
258634
+ diffStyle: snippet2.diffStyle,
258635
+ background: SNIPPET_PANE_BG
258636
+ }
258637
+ ) });
258638
+ });
258639
+ const SidePaneFrame = React.forwardRef(
258640
+ function SidePaneFrame2({ marker, onClose, children: children2 }, ref) {
258641
+ return /* @__PURE__ */ jsxs(
258642
+ "div",
258643
+ {
258644
+ ref,
258645
+ style: {
258646
+ position: "absolute",
258647
+ top: 16,
258648
+ right: 16,
258649
+ bottom: `calc(${SEQUENCE_DRAWER_HEIGHT_PCT}% + 16px)`,
258650
+ width: SNIPPET_PANE_WIDTH_PX,
258651
+ maxWidth: "50%",
258652
+ backgroundColor: SNIPPET_PANE_BG,
258653
+ border: "1px solid #1f2937",
258654
+ borderRadius: 12,
258655
+ boxShadow: "-2px 0 12px rgba(0,0,0,0.35)",
258656
+ display: "flex",
258657
+ flexDirection: "column",
258658
+ overflow: "hidden",
258659
+ zIndex: 1900
258660
+ },
258661
+ children: [
258662
+ /* @__PURE__ */ jsxs(
258663
+ "div",
258664
+ {
258665
+ style: {
258666
+ display: "flex",
258667
+ alignItems: "flex-start",
258668
+ justifyContent: "space-between",
258669
+ gap: 8,
258670
+ padding: "10px 14px",
258671
+ borderBottom: "1px solid #1f2937",
258672
+ flexShrink: 0
258673
+ },
258674
+ children: [
258675
+ /* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
258676
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, fontWeight: 600 }, children: marker.label ?? marker.id }),
258677
+ marker.sourcePath ? /* @__PURE__ */ jsx(
258678
+ "div",
258679
+ {
258680
+ style: {
258681
+ fontSize: 11,
258682
+ opacity: 0.6,
258683
+ fontFamily: "ui-monospace, SFMono-Regular, monospace",
258684
+ marginTop: 2,
258685
+ wordBreak: "break-all"
258686
+ },
258687
+ children: marker.sourcePath
258688
+ }
258689
+ ) : null
258690
+ ] }),
258691
+ /* @__PURE__ */ jsx(
258692
+ "button",
258693
+ {
258694
+ onClick: onClose,
258695
+ style: {
258696
+ background: "transparent",
258697
+ color: "#e5e7eb",
258698
+ border: "1px solid #374151",
258699
+ borderRadius: 4,
258700
+ padding: "2px 8px",
258701
+ cursor: "pointer",
258702
+ fontSize: 11,
258703
+ flexShrink: 0
258704
+ },
258705
+ children: "Close"
258706
+ }
258707
+ )
258708
+ ]
258709
+ }
258710
+ ),
258711
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: 0, overflow: "auto" }, children: children2 })
258712
+ ]
258713
+ }
258714
+ );
258715
+ }
258716
+ );
258717
+ const TrailHeader = ({ trail: trail2, markerCount }) => {
258718
+ return /* @__PURE__ */ jsxs(
258719
+ "div",
258720
+ {
258721
+ style: {
258722
+ height: HEADER_HEIGHT_PX,
258723
+ padding: "8px 16px",
258724
+ borderBottom: "1px solid #1f2937",
258725
+ display: "flex",
258726
+ flexDirection: "column",
258727
+ justifyContent: "center",
258728
+ gap: 2,
258729
+ flexShrink: 0
258730
+ },
258731
+ children: [
258732
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 14, fontWeight: 600 }, children: trail2.title }),
258733
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 11, opacity: 0.6 }, children: [
258734
+ markerCount,
258735
+ " marker",
258736
+ markerCount === 1 ? "" : "s",
258737
+ " in this repo"
258738
+ ] })
258739
+ ]
258740
+ }
258741
+ );
258742
+ };
258743
+ const FileCityTrailExplorerEmptyState = ({
258744
+ message,
258745
+ cityData
258746
+ }) => {
258747
+ return /* @__PURE__ */ jsxs(
258748
+ "div",
258749
+ {
258750
+ style: {
258751
+ position: "relative",
258752
+ width: "100%",
258753
+ height: "100%",
258754
+ backgroundColor: "#0b0f14",
258755
+ color: "#e5e7eb"
258756
+ },
258757
+ children: [
258758
+ cityData ? /* @__PURE__ */ jsx(
258759
+ FileCity3D,
258760
+ {
258761
+ cityData,
258762
+ width: "100%",
258763
+ height: "100%",
258764
+ showControls: false,
258765
+ backgroundColor: "#0b0f14"
258766
+ }
258767
+ ) : null,
258768
+ /* @__PURE__ */ jsx(
258769
+ "div",
258770
+ {
258771
+ style: {
258772
+ position: "absolute",
258773
+ inset: 0,
258774
+ display: "flex",
258775
+ alignItems: "center",
258776
+ justifyContent: "center",
258777
+ padding: 16,
258778
+ backgroundColor: cityData ? "rgba(11, 15, 20, 0.6)" : void 0,
258779
+ opacity: 0.85,
258780
+ fontSize: 13
258781
+ },
258782
+ children: message
258783
+ }
258784
+ )
258785
+ ]
258786
+ }
258787
+ );
258788
+ };
258789
+ const CityLoadingPlaceholder = () => /* @__PURE__ */ jsx(
258790
+ "div",
258791
+ {
258792
+ style: {
258793
+ width: "100%",
258794
+ height: "100%",
258795
+ display: "flex",
258796
+ alignItems: "center",
258797
+ justifyContent: "center",
258798
+ opacity: 0.5,
258799
+ fontSize: 12
258800
+ },
258801
+ children: "Building the city…"
258802
+ }
258803
+ );
258804
+ function filterMarkersForRepo(trail2, repository) {
258805
+ const repos = trail2.repos ?? [];
258806
+ if (repos.length <= 1 || !repository) {
258807
+ return trail2.markers;
258808
+ }
258809
+ return trail2.markers.filter((m) => m.repo === repository.id);
258810
+ }
258811
+ const focusBuildingTool = {
258812
+ name: "focus_building",
258813
+ description: "Focuses the camera on a specific file (building) in the file city visualization",
258814
+ inputs: {
258815
+ type: "object",
258816
+ properties: {
258817
+ filePath: {
258818
+ type: "string",
258819
+ description: "Path to the file to focus on"
258820
+ },
258821
+ animate: {
258822
+ type: "boolean",
258823
+ description: "Whether to animate the camera transition"
258824
+ }
258825
+ },
258826
+ required: ["filePath"]
258827
+ },
258828
+ outputs: {
258829
+ type: "object",
258830
+ properties: {
258831
+ success: { type: "boolean" },
258832
+ message: { type: "string" }
258833
+ }
258834
+ },
258835
+ tags: ["navigation", "camera", "focus"],
258836
+ tool_call_template: {
258837
+ call_template_type: "panel_event",
258838
+ event_type: "industry-theme.file-city-panel:focus-building"
258839
+ }
258840
+ };
258841
+ const selectDistrictTool = {
258842
+ name: "select_district",
258843
+ description: "Selects and highlights a directory (district) in the file city visualization",
258844
+ inputs: {
258845
+ type: "object",
258846
+ properties: {
258847
+ directoryPath: {
258848
+ type: "string",
258849
+ description: "Path to the directory to select"
258850
+ },
258851
+ expandChildren: {
258852
+ type: "boolean",
258853
+ description: "Whether to expand and show child buildings"
258854
+ }
258855
+ },
258856
+ required: ["directoryPath"]
258857
+ },
258858
+ outputs: {
258859
+ type: "object",
258860
+ properties: {
258861
+ success: { type: "boolean" },
258862
+ selectedDistrict: { type: "string" }
258863
+ }
258864
+ },
258865
+ tags: ["selection", "district", "directory"],
258866
+ tool_call_template: {
258867
+ call_template_type: "panel_event",
258868
+ event_type: "industry-theme.file-city-panel:select-district"
258869
+ }
258870
+ };
258871
+ const resetViewTool = {
258872
+ name: "reset_view",
258873
+ description: "Resets the file city view to the default camera position",
258874
+ inputs: {
258875
+ type: "object",
258876
+ properties: {
258877
+ animate: {
258878
+ type: "boolean",
258879
+ description: "Whether to animate the camera reset"
258880
+ }
258881
+ }
258882
+ },
258883
+ outputs: {
258884
+ type: "object",
258885
+ properties: {
258886
+ success: { type: "boolean" }
258887
+ }
258888
+ },
258889
+ tags: ["navigation", "camera", "reset"],
258890
+ tool_call_template: {
258891
+ call_template_type: "panel_event",
258892
+ event_type: "industry-theme.file-city-panel:reset-view"
258893
+ }
258894
+ };
258895
+ const codeCityPanelTools = [
258896
+ focusBuildingTool,
258897
+ selectDistrictTool,
258898
+ resetViewTool
258899
+ ];
258900
+ const codeCityPanelToolsMetadata = {
258901
+ id: "industry-theme.file-city-panel",
258902
+ name: "File City Panel",
258903
+ description: "Tools provided by the file city visualization panel extension",
258904
+ tools: codeCityPanelTools
258905
+ };
258906
+ const NpmIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#CB3837", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z" }) });
258907
+ const YarnIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#2C8EBB", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.375 0 0 5.375 0 12s5.375 12 12 12 12-5.375 12-12S18.625 0 12 0zm.768 4.105c.183 0 .363.053.525.157.125.083.287.185.755 1.154.31-.088.468-.042.551-.019.204.056.366.19.463.375.477.917.542 2.553.334 3.605-.241 1.232-.755 2.029-1.131 2.576.324.329.778.899 1.117 1.825.278.774.31 1.478.273 2.015a5.51 5.51 0 0 0 .602-.329c.593-.366 1.487-.917 2.553-.931.714-.009 1.269.445 1.353 1.103a1.23 1.23 0 0 1-.945 1.362c-.649.158-.95.278-1.821.843-1.232.797-2.539 1.242-3.012 1.39a1.686 1.686 0 0 1-.704.343c-.737.181-3.266.315-3.466.315h-.046c-.783 0-1.214-.241-1.45-.491-.658.329-1.51.19-2.122-.134a1.078 1.078 0 0 1-.58-1.153 1.243 1.243 0 0 1-.153-.195c-.162-.25-.528-.936-.454-1.946.056-.723.556-1.367.88-1.71a5.522 5.522 0 0 1 .408-2.256c.306-.727.885-1.348 1.32-1.737-.32-.537-.644-1.367-.329-2.21.227-.602.412-.936.82-1.08h-.005c.199-.074.389-.153.486-.259a3.418 3.418 0 0 1 2.298-1.103c.037-.093.079-.185.125-.283.31-.658.639-1.029 1.024-1.168a.94.94 0 0 1 .328-.06z" }) });
258908
+ const PnpmIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#F69220", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z" }) });
258909
+ const BunIcon = ({ size }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "#FBF0DF", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M12 22.596c6.628 0 12-4.338 12-9.688 0-3.318-2.057-6.248-5.219-7.986-1.286-.715-2.297-1.357-3.139-1.89C14.058 2.025 13.08 1.404 12 1.404c-1.097 0-2.334.785-3.966 1.821a49.92 49.92 0 0 1-2.816 1.697C2.057 6.66 0 9.59 0 12.908c0 5.35 5.372 9.687 12 9.687v.001Z" }) });
258910
+ const PackageManagerIcon = ({
258911
+ packageManager,
258912
+ size = 16,
258913
+ color: color2
258914
+ }) => {
258915
+ switch (packageManager) {
258916
+ case "npm":
258917
+ return /* @__PURE__ */ jsx(NpmIcon, { size });
258918
+ case "yarn":
258919
+ return /* @__PURE__ */ jsx(YarnIcon, { size });
258920
+ case "pnpm":
258921
+ return /* @__PURE__ */ jsx(PnpmIcon, { size });
258922
+ case "bun":
258923
+ return /* @__PURE__ */ jsx(BunIcon, { size });
258924
+ default:
258925
+ return /* @__PURE__ */ jsx(Package$1, { size, color: color2 });
258926
+ }
258927
+ };
258928
+ const ProjectInfoHeader = ({
258929
+ project,
258930
+ onOpen,
258931
+ compact = false
258932
+ }) => {
258933
+ const { theme: theme2 } = useTheme();
258934
+ const totalDeps = (project.dependencyCount || 0) + (project.devDependencyCount || 0);
258935
+ const fontSizeSmall = theme2.fontSizes[0];
258936
+ const fontSizeMedium = theme2.fontSizes[1];
258937
+ const fontSizeLarge = theme2.fontSizes[2] || theme2.fontSizes[1];
258938
+ return /* @__PURE__ */ jsxs(
258939
+ "div",
258940
+ {
258941
+ style: {
258942
+ display: "flex",
258943
+ flexDirection: "column",
258944
+ gap: compact ? 4 : 8,
258945
+ padding: compact ? "8px 12px" : "12px 16px",
258946
+ backgroundColor: theme2.colors.background,
258947
+ borderBottom: `1px solid ${theme2.colors.border}`,
258948
+ fontFamily: theme2.fonts.body,
258949
+ minHeight: compact ? 48 : "auto"
258950
+ },
258951
+ children: [
258952
+ /* @__PURE__ */ jsxs(
258953
+ "div",
258954
+ {
258955
+ style: {
258956
+ display: "flex",
258957
+ alignItems: "center",
258958
+ justifyContent: "space-between",
258959
+ gap: 12
258960
+ },
258961
+ children: [
258962
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, flex: 1, minWidth: 0 }, children: [
258963
+ project.packageManager && /* @__PURE__ */ jsx("div", { style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx(
258964
+ PackageManagerIcon,
258965
+ {
258966
+ packageManager: project.packageManager,
258967
+ size: compact ? 18 : 20,
258968
+ color: theme2.colors.textSecondary
258969
+ }
258970
+ ) }),
258971
+ /* @__PURE__ */ jsx(
258972
+ "span",
258973
+ {
258974
+ style: {
258975
+ fontSize: compact ? fontSizeMedium : fontSizeLarge,
258976
+ fontWeight: 600,
258977
+ color: theme2.colors.text,
258978
+ overflow: "hidden",
258979
+ textOverflow: "ellipsis",
258980
+ whiteSpace: "nowrap"
258981
+ },
258982
+ title: project.name,
258983
+ children: project.name
258984
+ }
258985
+ ),
258986
+ project.version && /* @__PURE__ */ jsxs(
258987
+ "span",
258988
+ {
258989
+ style: {
258990
+ fontSize: fontSizeSmall,
258991
+ color: theme2.colors.textSecondary,
258992
+ backgroundColor: theme2.colors.backgroundLight,
257762
258993
  padding: "2px 6px",
257763
258994
  borderRadius: "4px",
257764
258995
  flexShrink: 0
@@ -258301,6 +259532,32 @@ const panels = [
258301
259532
  onUnmount: async (_context) => {
258302
259533
  console.log("File City Explorer Panel unmounting");
258303
259534
  }
259535
+ },
259536
+ {
259537
+ metadata: {
259538
+ id: "principal-ade.file-city-trail-explorer-panel",
259539
+ name: "File City Trail Explorer",
259540
+ icon: "🥾",
259541
+ version: "0.1.0",
259542
+ author: "Principal AI",
259543
+ description: "3D file-city visualization for trails — the new authored-walkthrough medium. See docs/TRAIL_RENAME.md.",
259544
+ // Required slice — the explorer cannot render without a tree. Other
259545
+ // slices declared on FileCityTrailExplorerPanelContext are
259546
+ // host-supplied with `data: null` when no trail is active.
259547
+ slices: ["fileTree"]
259548
+ },
259549
+ component: FileCityTrailExplorerPanel,
259550
+ onMount: async (context) => {
259551
+ var _a;
259552
+ console.log(
259553
+ "File City Trail Explorer Panel mounted",
259554
+ (_a = context.currentScope.repository) == null ? void 0 : _a.path
259555
+ );
259556
+ await context.refresh("repository", "fileTree");
259557
+ },
259558
+ onUnmount: async (_context) => {
259559
+ console.log("File City Trail Explorer Panel unmounting");
259560
+ }
258304
259561
  }
258305
259562
  ];
258306
259563
  const onPackageLoad = async () => {
@@ -258319,6 +259576,7 @@ export {
258319
259576
  FileCardList,
258320
259577
  FileCitySequenceExplorer,
258321
259578
  FileCitySequenceExplorerPanel,
259579
+ FileCityTrailExplorerPanel,
258322
259580
  GitChangesCardList,
258323
259581
  MockTTSAdapter,
258324
259582
  PrChangesCardList,