@industry-theme/file-city-panel 0.5.70 → 0.5.72

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.
@@ -257703,7 +257703,7 @@ const TrailLeaderLine = React.forwardRef(function TrailLeaderLine2({ containerRe
257703
257703
  const HEADER_BAND_OFFSET = 22;
257704
257704
  const bx = nodeRect.left - containerRect.left;
257705
257705
  const by = nodeRect.top - containerRect.top + HEADER_BAND_OFFSET;
257706
- const ELBOW_GAP = 60;
257706
+ const ELBOW_GAP = 30;
257707
257707
  const CORNER_RADIUS = 14;
257708
257708
  const elbowX = Math.max(
257709
257709
  canvasLeft + 8,
@@ -257806,6 +257806,11 @@ const TrailLeaderLine = React.forwardRef(function TrailLeaderLine2({ containerRe
257806
257806
  )
257807
257807
  ] });
257808
257808
  });
257809
+ const CALLOUT_FADE_IN_MS = 350;
257810
+ const TITLE_TYPEWRITER_CPS = 28;
257811
+ const TITLE_TYPEWRITER_HOLD_MS = 500;
257812
+ const TITLE_INTER_HOLD_MS = 220;
257813
+ const TITLE_CARET = "▍";
257809
257814
  const fileBasename = (path2) => {
257810
257815
  const i = path2.lastIndexOf("/");
257811
257816
  return i >= 0 ? path2.slice(i + 1) : path2;
@@ -257817,10 +257822,18 @@ const fileDirname = (path2) => {
257817
257822
  const TrailFilePath = React.forwardRef(function TrailFilePath2({
257818
257823
  containerRef,
257819
257824
  buildings,
257825
+ markerTitles,
257820
257826
  cityCenter,
257821
257827
  animate: animate2 = true,
257828
+ currentStepIndex = null,
257822
257829
  stepMs = 1100,
257823
- dwellMs = 1400,
257830
+ // Dwell budget covers: fade-in (350ms) + initial hold (500ms) +
257831
+ // filename typewriter (~ name.length * 36ms at 28cps) + inter-hold
257832
+ // (220ms) + title typewriter (~ title.length * 36ms) + a digest
257833
+ // beat after typing finishes so the user can read the full
257834
+ // callout before the dot walks on. 3500ms leaves ~1.5s of digest
257835
+ // for typical 10-char filenames + 15-char titles.
257836
+ dwellMs = 3500,
257824
257837
  endHoldMs = 2200
257825
257838
  }, ref) {
257826
257839
  const { theme: theme2 } = useTheme();
@@ -257828,7 +257841,9 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
257828
257841
  const fontFamily = theme2.fonts.body;
257829
257842
  const calloutFontSize = String(theme2.fontSizes[1] ?? 14);
257830
257843
  const calloutFontWeight = String(theme2.fontWeights.semibold ?? 600);
257831
- const calloutLineDy = String(Math.round((theme2.fontSizes[1] ?? 14) * 1.45));
257844
+ const calloutBodyFontWeight = String(theme2.fontWeights.body ?? 400);
257845
+ const calloutLineDyPx = Math.round((theme2.fontSizes[1] ?? 14) * 1.45);
257846
+ const calloutLineDy = String(calloutLineDyPx);
257832
257847
  const surfaceColor = theme2.colors.backgroundSecondary ?? "#0f1419";
257833
257848
  const filenameColor = theme2.colors.text ?? "#f8fafc";
257834
257849
  const dirColor = theme2.colors.textMuted ?? "#94a3b8";
@@ -257840,14 +257855,24 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
257840
257855
  const animStartTsRef = React.useRef(
257841
257856
  typeof performance !== "undefined" ? performance.now() : 0
257842
257857
  );
257858
+ const hoverFrozenElapsedRef = React.useRef(null);
257859
+ const periodRef = React.useRef(0);
257843
257860
  const buildingsRef = React.useRef(buildings);
257861
+ const markerTitlesRef = React.useRef(markerTitles);
257844
257862
  const cityCenterRef = React.useRef(cityCenter);
257863
+ const currentStepIndexRef = React.useRef(currentStepIndex);
257845
257864
  React.useEffect(() => {
257846
257865
  buildingsRef.current = buildings;
257847
257866
  }, [buildings]);
257867
+ React.useEffect(() => {
257868
+ markerTitlesRef.current = markerTitles;
257869
+ }, [markerTitles]);
257848
257870
  React.useEffect(() => {
257849
257871
  cityCenterRef.current = cityCenter;
257850
257872
  }, [cityCenter]);
257873
+ React.useEffect(() => {
257874
+ currentStepIndexRef.current = currentStepIndex;
257875
+ }, [currentStepIndex]);
257851
257876
  const hideAll = React.useCallback(() => {
257852
257877
  const g2 = groupRef.current;
257853
257878
  if (!g2) return;
@@ -257861,6 +257886,7 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
257861
257886
  }, [animate2, buildings, dwellMs, stepMs, endHoldMs]);
257862
257887
  const onCameraFrame = React.useCallback(
257863
257888
  (camera, size) => {
257889
+ var _a, _b;
257864
257890
  const targets = buildingsRef.current;
257865
257891
  const center = cityCenterRef.current;
257866
257892
  const container = containerRef.current;
@@ -257892,12 +257918,18 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
257892
257918
  const N = points.length;
257893
257919
  const slotMs = dwellMs + stepMs;
257894
257920
  const period = N >= 2 ? (N - 1) * slotMs + dwellMs + endHoldMs : 0;
257921
+ periodRef.current = period;
257922
+ const rawFrozen = currentStepIndexRef.current;
257923
+ const frozenIndex = rawFrozen != null && rawFrozen >= 0 && rawFrozen < N ? rawFrozen : null;
257895
257924
  let revealedCount = animate2 ? 0 : N;
257896
257925
  let leadingTip = null;
257897
257926
  let traverseFrac = null;
257898
257927
  let dwellElapsed = 0;
257899
- if (animate2 && period > 0) {
257900
- const elapsed = ((typeof performance !== "undefined" ? performance.now() : Date.now()) - animStartTsRef.current) % period;
257928
+ if (frozenIndex != null) {
257929
+ revealedCount = frozenIndex + 1;
257930
+ dwellElapsed = CALLOUT_FADE_IN_MS;
257931
+ } else if (animate2 && period > 0) {
257932
+ const elapsed = hoverFrozenElapsedRef.current !== null ? hoverFrozenElapsedRef.current : ((typeof performance !== "undefined" ? performance.now() : Date.now()) - animStartTsRef.current) % period;
257901
257933
  const traversalsEnd = (N - 1) * slotMs;
257902
257934
  if (elapsed >= traversalsEnd) {
257903
257935
  revealedCount = N;
@@ -258011,38 +258043,79 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
258011
258043
  }
258012
258044
  }
258013
258045
  const SVG_NS = "http://www.w3.org/2000/svg";
258014
- const paintCallout = (textEl, bgEl, point2, path2, opacity) => {
258046
+ const paintCallout = (textEl, bgEl, point2, path2, title, opacity, nameRevealChars2, titleRevealChars2) => {
258015
258047
  if (!textEl || !bgEl) return;
258016
258048
  if (!point2 || !point2.visible || opacity <= 1e-3 || !path2) {
258017
258049
  textEl.setAttribute("opacity", "0");
258018
258050
  bgEl.setAttribute("opacity", "0");
258051
+ bgEl.setAttribute("pointer-events", "none");
258052
+ textEl.setAttribute("pointer-events", "none");
258019
258053
  return;
258020
258054
  }
258021
- if (textEl.children.length < 2) {
258022
- while (textEl.firstChild) textEl.removeChild(textEl.firstChild);
258023
- textEl.appendChild(document.createElementNS(SVG_NS, "tspan"));
258055
+ const interactive = opacity >= 0.6;
258056
+ bgEl.setAttribute(
258057
+ "pointer-events",
258058
+ interactive ? "auto" : "none"
258059
+ );
258060
+ textEl.setAttribute(
258061
+ "pointer-events",
258062
+ interactive ? "auto" : "none"
258063
+ );
258064
+ while (textEl.children.length < 3) {
258024
258065
  textEl.appendChild(document.createElementNS(SVG_NS, "tspan"));
258025
258066
  }
258026
- const nameTspan = textEl.children[0];
258027
- const pathTspan = textEl.children[1];
258067
+ while (textEl.children.length > 3) {
258068
+ textEl.removeChild(textEl.lastChild);
258069
+ }
258070
+ const pathTspan = textEl.children[0];
258071
+ const nameTspan = textEl.children[1];
258072
+ const titleTspan = textEl.children[2];
258028
258073
  const name2 = fileBasename(path2);
258029
258074
  const dir = fileDirname(path2);
258030
- const nameLineY = point2.y - 44;
258075
+ const trimmedTitle = (title == null ? void 0 : title.trim()) ?? "";
258076
+ const displayTitle = trimmedTitle && titleRevealChars2 !== null ? titleRevealChars2 < 0 ? "" : titleRevealChars2 >= trimmedTitle.length ? trimmedTitle : trimmedTitle.slice(0, titleRevealChars2) + TITLE_CARET : trimmedTitle;
258077
+ const displayName = nameRevealChars2 !== null ? nameRevealChars2 < 0 ? "" : nameRevealChars2 >= name2.length ? name2 : name2.slice(0, nameRevealChars2) + TITLE_CARET : name2;
258078
+ const lineCount = (dir ? 1 : 0) + 1 + (trimmedTitle ? 1 : 0);
258079
+ const BOTTOM_LINE_OFFSET = 24;
258080
+ const topLineY = point2.y - BOTTOM_LINE_OFFSET - (lineCount - 1) * calloutLineDyPx;
258031
258081
  textEl.setAttribute("text-anchor", "middle");
258032
258082
  textEl.setAttribute("font-family", fontFamily);
258033
258083
  textEl.setAttribute("opacity", String(opacity));
258034
- nameTspan.textContent = name2;
258035
- nameTspan.setAttribute("x", String(point2.x));
258036
- nameTspan.setAttribute("y", String(nameLineY));
258037
- nameTspan.setAttribute("fill", filenameColor);
258038
- nameTspan.setAttribute("font-size", calloutFontSize);
258039
- nameTspan.setAttribute("font-weight", calloutFontWeight);
258040
258084
  pathTspan.textContent = dir;
258085
+ pathTspan.setAttribute("text-anchor", "middle");
258041
258086
  pathTspan.setAttribute("x", String(point2.x));
258042
- pathTspan.setAttribute("dy", dir ? calloutLineDy : "0");
258043
- pathTspan.setAttribute("fill", dirColor);
258087
+ pathTspan.setAttribute("y", String(topLineY));
258088
+ pathTspan.removeAttribute("dy");
258089
+ pathTspan.setAttribute("fill", color2);
258044
258090
  pathTspan.setAttribute("font-size", calloutFontSize);
258045
258091
  pathTspan.setAttribute("font-weight", calloutFontWeight);
258092
+ nameTspan.textContent = name2;
258093
+ nameTspan.setAttribute("text-anchor", "start");
258094
+ nameTspan.removeAttribute("y");
258095
+ nameTspan.setAttribute("dy", dir ? calloutLineDy : "0");
258096
+ nameTspan.setAttribute(
258097
+ "fill",
258098
+ trimmedTitle ? dirColor : filenameColor
258099
+ );
258100
+ nameTspan.setAttribute("font-size", calloutFontSize);
258101
+ nameTspan.setAttribute(
258102
+ "font-weight",
258103
+ trimmedTitle ? calloutBodyFontWeight : calloutFontWeight
258104
+ );
258105
+ const nameWidth = typeof nameTspan.getComputedTextLength === "function" ? nameTspan.getComputedTextLength() : 0;
258106
+ nameTspan.setAttribute("x", String(point2.x - nameWidth / 2));
258107
+ titleTspan.textContent = trimmedTitle;
258108
+ titleTspan.setAttribute("text-anchor", "start");
258109
+ titleTspan.removeAttribute("y");
258110
+ titleTspan.setAttribute(
258111
+ "dy",
258112
+ trimmedTitle ? calloutLineDy : "0"
258113
+ );
258114
+ titleTspan.setAttribute("fill", filenameColor);
258115
+ titleTspan.setAttribute("font-size", calloutFontSize);
258116
+ titleTspan.setAttribute("font-weight", calloutFontWeight);
258117
+ const titleWidth = typeof titleTspan.getComputedTextLength === "function" ? titleTspan.getComputedTextLength() : 0;
258118
+ titleTspan.setAttribute("x", String(point2.x - titleWidth / 2));
258046
258119
  const bbox = textEl.getBBox();
258047
258120
  const padX = 14;
258048
258121
  const padY = 10;
@@ -258055,26 +258128,70 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
258055
258128
  bgEl.setAttribute("stroke", color2);
258056
258129
  bgEl.setAttribute("stroke-width", "1.5");
258057
258130
  bgEl.setAttribute("opacity", String(0.94 * opacity));
258131
+ if (displayName !== name2) {
258132
+ nameTspan.textContent = displayName;
258133
+ }
258134
+ if (displayTitle !== trimmedTitle) {
258135
+ titleTspan.textContent = displayTitle;
258136
+ }
258058
258137
  };
258059
- const fadeInMs = 350;
258060
258138
  let calloutOpacity = 0;
258061
- if (animate2 && lastIndex >= 0 && lastIndex < targets.length) {
258139
+ if (frozenIndex != null && lastIndex >= 0) {
258140
+ calloutOpacity = 1;
258141
+ } else if (animate2 && lastIndex >= 0 && lastIndex < targets.length) {
258062
258142
  if (traverseFrac !== null) {
258063
258143
  const eased = traverseFrac * traverseFrac * (3 - 2 * traverseFrac);
258064
258144
  calloutOpacity = 1 - eased;
258065
258145
  } else {
258066
- const t = Math.min(1, dwellElapsed / fadeInMs);
258146
+ const t = Math.min(1, dwellElapsed / CALLOUT_FADE_IN_MS);
258067
258147
  calloutOpacity = t * t * (3 - 2 * t);
258068
258148
  }
258069
258149
  } else if (!animate2 && lastIndex >= 0) {
258070
258150
  calloutOpacity = 1;
258071
258151
  }
258152
+ const activePath = lastIndex >= 0 ? targets[lastIndex].path : null;
258153
+ const activeName = activePath ? fileBasename(activePath) : "";
258154
+ const activeTitle = lastIndex >= 0 ? (((_a = markerTitlesRef.current) == null ? void 0 : _a[lastIndex]) ?? "").trim() : "";
258155
+ let nameRevealChars = null;
258156
+ let titleRevealChars = null;
258157
+ if (animate2 && frozenIndex == null && traverseFrac === null && lastIndex >= 0) {
258158
+ const charsPerMs = TITLE_TYPEWRITER_CPS / 1e3;
258159
+ const nameStart = CALLOUT_FADE_IN_MS + TITLE_TYPEWRITER_HOLD_MS;
258160
+ const nameDuration = activeName.length > 0 ? activeName.length / charsPerMs : 0;
258161
+ const nameDone = nameStart + nameDuration;
258162
+ const titleStart = nameDone + TITLE_INTER_HOLD_MS;
258163
+ if (activeName.length > 0) {
258164
+ if (dwellElapsed < nameStart) {
258165
+ nameRevealChars = 0;
258166
+ } else if (dwellElapsed < nameDone) {
258167
+ const typed = Math.floor(
258168
+ (dwellElapsed - nameStart) * charsPerMs
258169
+ );
258170
+ nameRevealChars = typed >= activeName.length ? null : Math.max(0, typed);
258171
+ } else {
258172
+ nameRevealChars = null;
258173
+ }
258174
+ }
258175
+ if (activeTitle.length > 0) {
258176
+ if (dwellElapsed < titleStart) {
258177
+ titleRevealChars = -1;
258178
+ } else {
258179
+ const typed = Math.floor(
258180
+ (dwellElapsed - titleStart) * charsPerMs
258181
+ );
258182
+ titleRevealChars = typed >= activeTitle.length ? null : Math.max(0, typed);
258183
+ }
258184
+ }
258185
+ }
258072
258186
  paintCallout(
258073
258187
  calloutTextRef.current,
258074
258188
  calloutBgRef.current,
258075
258189
  lastIndex >= 0 ? points[lastIndex] : null,
258076
- lastIndex >= 0 ? targets[lastIndex].path : null,
258077
- calloutOpacity
258190
+ activePath,
258191
+ lastIndex >= 0 ? ((_b = markerTitlesRef.current) == null ? void 0 : _b[lastIndex]) ?? null : null,
258192
+ calloutOpacity,
258193
+ nameRevealChars,
258194
+ titleRevealChars
258078
258195
  );
258079
258196
  g2.setAttribute("opacity", "1");
258080
258197
  },
@@ -258089,13 +258206,28 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
258089
258206
  fontFamily,
258090
258207
  calloutFontSize,
258091
258208
  calloutFontWeight,
258209
+ calloutBodyFontWeight,
258092
258210
  calloutLineDy,
258211
+ calloutLineDyPx,
258093
258212
  surfaceColor,
258094
258213
  filenameColor,
258095
258214
  dirColor
258096
258215
  ]
258097
258216
  );
258098
258217
  React.useImperativeHandle(ref, () => ({ onCameraFrame }), [onCameraFrame]);
258218
+ const handleCalloutEnter = React.useCallback(() => {
258219
+ if (hoverFrozenElapsedRef.current !== null) return;
258220
+ const period = periodRef.current;
258221
+ if (period <= 0) return;
258222
+ const now2 = typeof performance !== "undefined" ? performance.now() : Date.now();
258223
+ hoverFrozenElapsedRef.current = (now2 - animStartTsRef.current) % period;
258224
+ }, []);
258225
+ const handleCalloutLeave = React.useCallback(() => {
258226
+ if (hoverFrozenElapsedRef.current === null) return;
258227
+ const now2 = typeof performance !== "undefined" ? performance.now() : Date.now();
258228
+ animStartTsRef.current = now2 - hoverFrozenElapsedRef.current;
258229
+ hoverFrozenElapsedRef.current = null;
258230
+ }, []);
258099
258231
  return /* @__PURE__ */ jsxs(
258100
258232
  "svg",
258101
258233
  {
@@ -258113,8 +258245,26 @@ const TrailFilePath = React.forwardRef(function TrailFilePath2({
258113
258245
  children: [
258114
258246
  /* @__PURE__ */ jsx("g", { ref: groupRef, opacity: 0 }),
258115
258247
  /* @__PURE__ */ jsx("circle", { ref: leadDotRef, opacity: 0, pointerEvents: "none" }),
258116
- /* @__PURE__ */ jsx("rect", { ref: calloutBgRef, opacity: 0, pointerEvents: "none" }),
258117
- /* @__PURE__ */ jsx("text", { ref: calloutTextRef, opacity: 0, pointerEvents: "none" })
258248
+ /* @__PURE__ */ jsx(
258249
+ "rect",
258250
+ {
258251
+ ref: calloutBgRef,
258252
+ opacity: 0,
258253
+ pointerEvents: "auto",
258254
+ onMouseEnter: handleCalloutEnter,
258255
+ onMouseLeave: handleCalloutLeave
258256
+ }
258257
+ ),
258258
+ /* @__PURE__ */ jsx(
258259
+ "text",
258260
+ {
258261
+ ref: calloutTextRef,
258262
+ opacity: 0,
258263
+ pointerEvents: "auto",
258264
+ onMouseEnter: handleCalloutEnter,
258265
+ onMouseLeave: handleCalloutLeave
258266
+ }
258267
+ )
258118
258268
  ]
258119
258269
  }
258120
258270
  );
@@ -258126,6 +258276,7 @@ const RESIZE_HANDLE_WIDTH = 6;
258126
258276
  const TrailMarkdownOverlay = ({
258127
258277
  eyebrow,
258128
258278
  title,
258279
+ subtitle,
258129
258280
  markdown: markdown2,
258130
258281
  slideIdPrefix,
258131
258282
  bottomOffset,
@@ -258233,7 +258384,7 @@ const TrailMarkdownOverlay = ({
258233
258384
  to { transform: translateX(0); }
258234
258385
  }
258235
258386
  ` }),
258236
- eyebrow || title ? /* @__PURE__ */ jsxs(
258387
+ eyebrow || title || subtitle ? /* @__PURE__ */ jsxs(
258237
258388
  "div",
258238
258389
  {
258239
258390
  style: {
@@ -258272,6 +258423,22 @@ const TrailMarkdownOverlay = ({
258272
258423
  title,
258273
258424
  children: title
258274
258425
  }
258426
+ ) : null,
258427
+ subtitle ? /* @__PURE__ */ jsx(
258428
+ "span",
258429
+ {
258430
+ style: {
258431
+ fontSize: theme2.fontSizes[0],
258432
+ color: theme2.colors.textSecondary,
258433
+ fontFamily: theme2.fonts.monospace,
258434
+ overflow: "hidden",
258435
+ textOverflow: "ellipsis",
258436
+ whiteSpace: "nowrap",
258437
+ marginTop: 2
258438
+ },
258439
+ title: subtitle,
258440
+ children: subtitle
258441
+ }
258275
258442
  ) : null
258276
258443
  ]
258277
258444
  }
@@ -258675,32 +258842,15 @@ const TrailSnippetView = ({
258675
258842
  if (!fileObject || !slice) {
258676
258843
  return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.textSecondary }, children: "Loading…" });
258677
258844
  }
258678
- const rangeLabel = slice.sliceStart === slice.sliceEnd ? `Line ${slice.sliceStart}` : `Lines ${slice.sliceStart}–${slice.sliceEnd}`;
258679
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", minHeight: 0 }, children: [
258680
- /* @__PURE__ */ jsx(
258681
- "div",
258682
- {
258683
- style: {
258684
- padding: "4px 14px 6px",
258685
- fontFamily: theme2.fonts.monospace,
258686
- fontSize: theme2.fontSizes[0],
258687
- color: theme2.colors.textSecondary,
258688
- letterSpacing: 0.4,
258689
- textTransform: "uppercase"
258690
- },
258691
- children: rangeLabel
258692
- }
258693
- ),
258694
- /* @__PURE__ */ jsx(
258695
- File$2,
258696
- {
258697
- file: fileObject,
258698
- options,
258699
- selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
258700
- style: pierreStyle$1
258701
- }
258702
- )
258703
- ] });
258845
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", minHeight: 0 }, children: /* @__PURE__ */ jsx(
258846
+ File$2,
258847
+ {
258848
+ file: fileObject,
258849
+ options,
258850
+ selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
258851
+ style: pierreStyle$1
258852
+ }
258853
+ ) });
258704
258854
  };
258705
258855
  const buildBackgroundCSS = (color2) => `
258706
258856
  :host {
@@ -258825,40 +258975,23 @@ const TrailDiffSnippetView = ({
258825
258975
  if (!fileDiff) {
258826
258976
  return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: theme2.colors.error }, children: "Failed to compute diff" });
258827
258977
  }
258828
- const rangeLabel = startLine != null && endLine != null ? startLine === endLine ? `Line ${startLine}` : `Lines ${startLine}–${endLine}` : null;
258829
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", minHeight: 0 }, children: [
258830
- rangeLabel && /* @__PURE__ */ jsx(
258831
- "div",
258832
- {
258833
- style: {
258834
- padding: "4px 14px 6px",
258835
- fontFamily: theme2.fonts.monospace,
258836
- fontSize: theme2.fontSizes[0],
258837
- color: theme2.colors.textSecondary,
258838
- letterSpacing: 0.4,
258839
- textTransform: "uppercase"
258840
- },
258841
- children: rangeLabel
258842
- }
258843
- ),
258844
- /* @__PURE__ */ jsx(
258845
- FileDiff$2,
258846
- {
258847
- fileDiff,
258848
- options: { ...pierreOptionsBase, diffStyle },
258849
- selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
258850
- style: background ? {
258851
- ...pierreStyle,
258852
- // Pierre derives addition/deletion/context surfaces by
258853
- // `color-mix`ing from --diffs-bg, which is keyed off
258854
- // --diffs-light-bg / --diffs-dark-bg. Overriding the
258855
- // source variables recolors the whole palette coherently.
258856
- ["--diffs-light-bg"]: background,
258857
- ["--diffs-dark-bg"]: background
258858
- } : pierreStyle
258859
- }
258860
- )
258861
- ] });
258978
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", minHeight: 0 }, children: /* @__PURE__ */ jsx(
258979
+ FileDiff$2,
258980
+ {
258981
+ fileDiff,
258982
+ options: { ...pierreOptionsBase, diffStyle },
258983
+ selectedLines: slice.focusOffset != null ? { start: slice.focusOffset, end: slice.focusOffset } : void 0,
258984
+ style: background ? {
258985
+ ...pierreStyle,
258986
+ // Pierre derives addition/deletion/context surfaces by
258987
+ // `color-mix`ing from --diffs-bg, which is keyed off
258988
+ // --diffs-light-bg / --diffs-dark-bg. Overriding the
258989
+ // source variables recolors the whole palette coherently.
258990
+ ["--diffs-light-bg"]: background,
258991
+ ["--diffs-dark-bg"]: background
258992
+ } : pierreStyle
258993
+ }
258994
+ ) });
258862
258995
  };
258863
258996
  const pierreOptionsBase = {
258864
258997
  disableFileHeader: true
@@ -258867,10 +259000,11 @@ const pierreStyle = {
258867
259000
  display: "block"
258868
259001
  };
258869
259002
  const SEQUENCE_DRAWER_HEIGHT_PCT = 45;
258870
- const SNIPPET_PANE_WIDTH_PX = 460;
259003
+ const SNIPPET_PANE_RIGHT_GUTTER_PX = 16;
259004
+ const SNIPPET_PANE_LEADER_BUFFER_PX = 60;
258871
259005
  const PANEL_TRANSITION_MS = 280;
258872
259006
  const THREE_D_TOGGLE_DISABLED = true;
258873
- const FileCityTrailExplorerPanel = ({ context, actions }) => {
259007
+ const FileCityTrailExplorerPanel = ({ context, actions, defaultViewMode, defaultShowSequenceDrawer }) => {
258874
259008
  var _a;
258875
259009
  const tree = context.fileTree.data;
258876
259010
  const lineCounts = ((_a = context.lineCounts.data) == null ? void 0 : _a.lineCounts) ?? null;
@@ -258926,7 +259060,9 @@ const FileCityTrailExplorerPanel = ({ context, actions }) => {
258926
259060
  onSelectMarker: setSelectedMarkerId,
258927
259061
  cityData,
258928
259062
  hasLineCounts: lineCounts != null && Object.keys(lineCounts).length > 0,
258929
- readFile: actions.readFile
259063
+ readFile: actions.readFile,
259064
+ defaultViewMode,
259065
+ defaultShowSequenceDrawer
258930
259066
  }
258931
259067
  );
258932
259068
  };
@@ -258938,7 +259074,9 @@ const FileCityTrailSequenceLayout = ({
258938
259074
  onSelectMarker,
258939
259075
  cityData,
258940
259076
  hasLineCounts,
258941
- readFile
259077
+ readFile,
259078
+ defaultViewMode = "city",
259079
+ defaultShowSequenceDrawer = true
258942
259080
  }) => {
258943
259081
  var _a, _b;
258944
259082
  const { theme: theme2 } = useTheme();
@@ -258949,8 +259087,12 @@ const FileCityTrailSequenceLayout = ({
258949
259087
  return;
258950
259088
  }, [hasLineCounts]);
258951
259089
  const effectiveShow3D = false;
258952
- const [viewMode, setViewMode] = React.useState("city");
258953
- const [showSequenceDrawer, setShowSequenceDrawer] = React.useState(true);
259090
+ const [viewMode, setViewMode] = React.useState(
259091
+ defaultViewMode
259092
+ );
259093
+ const [showSequenceDrawer, setShowSequenceDrawer] = React.useState(
259094
+ defaultShowSequenceDrawer
259095
+ );
258954
259096
  const [drawerHeightOverridePct, setDrawerHeightOverridePct] = React.useState(null);
258955
259097
  const [isResizingDrawer, setIsResizingDrawer] = React.useState(false);
258956
259098
  const drawerHeightPct = !showSequenceDrawer ? 0 : drawerHeightOverridePct ?? SEQUENCE_DRAWER_HEIGHT_PCT;
@@ -258958,20 +259100,24 @@ const FileCityTrailSequenceLayout = ({
258958
259100
  if (!selectedMarkerId) return null;
258959
259101
  return trail2.markers.find((m) => m.id === selectedMarkerId) ?? null;
258960
259102
  }, [trail2.markers, selectedMarkerId]);
258961
- const markerBySourcePathForThisRepo = React.useMemo(() => {
259103
+ const markerByBuildingPath = React.useMemo(() => {
258962
259104
  const map2 = /* @__PURE__ */ new Map();
259105
+ if (!cityData) return map2;
258963
259106
  for (const m of markersForThisRepo) {
258964
- if (m.sourcePath) map2.set(m.sourcePath, m);
259107
+ const cityPath = markerCityPath(m, trail2);
259108
+ if (!cityPath) continue;
259109
+ const b = cityData.buildings.find((cb) => cb.path === cityPath) ?? cityData.buildings.find((cb) => cb.path.endsWith(`/${cityPath}`));
259110
+ if (b) map2.set(b.path, m);
258965
259111
  }
258966
259112
  return map2;
258967
- }, [markersForThisRepo]);
259113
+ }, [markersForThisRepo, cityData, trail2]);
258968
259114
  const handleBuildingClick = React.useCallback(
258969
259115
  (building) => {
258970
- const marker = markerBySourcePathForThisRepo.get(building.path);
259116
+ const marker = markerByBuildingPath.get(building.path);
258971
259117
  if (!marker) return;
258972
259118
  onSelectMarker(selectedMarkerId === marker.id ? null : marker.id);
258973
259119
  },
258974
- [markerBySourcePathForThisRepo, selectedMarkerId, onSelectMarker]
259120
+ [markerByBuildingPath, selectedMarkerId, onSelectMarker]
258975
259121
  );
258976
259122
  const stepperIndex = React.useMemo(() => {
258977
259123
  if (!selectedMarkerId) return -1;
@@ -259007,37 +259153,39 @@ const FileCityTrailSequenceLayout = ({
259007
259153
  const firstMarkerByPath = /* @__PURE__ */ new Map();
259008
259154
  const order2 = [];
259009
259155
  for (const m of markersForThisRepo) {
259010
- if (!m.sourcePath) continue;
259011
- const existing = counts.get(m.sourcePath) ?? 0;
259012
- counts.set(m.sourcePath, existing + 1);
259013
- if (!firstMarkerByPath.has(m.sourcePath)) {
259014
- firstMarkerByPath.set(m.sourcePath, m.id);
259015
- order2.push(m.sourcePath);
259016
- }
259017
- }
259018
- return order2.map((sourcePath) => ({
259019
- sourcePath,
259020
- markerCount: counts.get(sourcePath) ?? 0,
259021
- isActive: (selectedMarker == null ? void 0 : selectedMarker.sourcePath) === sourcePath,
259156
+ const cityPath = markerCityPath(m, trail2);
259157
+ if (!cityPath) continue;
259158
+ const existing = counts.get(cityPath) ?? 0;
259159
+ counts.set(cityPath, existing + 1);
259160
+ if (!firstMarkerByPath.has(cityPath)) {
259161
+ firstMarkerByPath.set(cityPath, m.id);
259162
+ order2.push(cityPath);
259163
+ }
259164
+ }
259165
+ const selectedCityPath = selectedMarker ? markerCityPath(selectedMarker, trail2) : null;
259166
+ return order2.map((cityPath) => ({
259167
+ sourcePath: cityPath,
259168
+ markerCount: counts.get(cityPath) ?? 0,
259169
+ isActive: selectedCityPath === cityPath,
259022
259170
  onClick: () => {
259023
- const markerId = firstMarkerByPath.get(sourcePath);
259171
+ const markerId = firstMarkerByPath.get(cityPath);
259024
259172
  if (markerId) onSelectMarker(markerId);
259025
259173
  },
259026
259174
  onHoverChange: setHoveredFilePath
259027
259175
  }));
259028
- }, [markersForThisRepo, selectedMarker, onSelectMarker]);
259176
+ }, [markersForThisRepo, selectedMarker, onSelectMarker, trail2]);
259029
259177
  const trailFilesHighlightLayers = React.useMemo(() => {
259030
259178
  if (!cityData) return null;
259031
- const sourcePaths = markersForThisRepo.map((m) => m.sourcePath).filter((p2) => typeof p2 === "string" && p2.length > 0);
259032
- if (sourcePaths.length === 0) return null;
259179
+ const cityPaths = markersForThisRepo.map((m) => markerCityPath(m, trail2)).filter((p2) => typeof p2 === "string" && p2.length > 0);
259180
+ if (cityPaths.length === 0) return null;
259033
259181
  const buildingByPath = new Map(cityData.buildings.map((b) => [b.path, b]));
259034
259182
  const byColor = /* @__PURE__ */ new Map();
259035
259183
  const seen = /* @__PURE__ */ new Set();
259036
- for (const sourcePath of sourcePaths) {
259037
- if (seen.has(sourcePath)) continue;
259038
- const building = buildingByPath.get(sourcePath) ?? cityData.buildings.find((b) => b.path.endsWith(`/${sourcePath}`));
259184
+ for (const cityPath of cityPaths) {
259185
+ if (seen.has(cityPath)) continue;
259186
+ const building = buildingByPath.get(cityPath) ?? cityData.buildings.find((b) => b.path.endsWith(`/${cityPath}`));
259039
259187
  if (!building) continue;
259040
- seen.add(sourcePath);
259188
+ seen.add(cityPath);
259041
259189
  const color2 = building.color ?? getFileColor(building.path);
259042
259190
  if (!color2) continue;
259043
259191
  const list2 = byColor.get(color2) ?? [];
@@ -259059,7 +259207,7 @@ const FileCityTrailSequenceLayout = ({
259059
259207
  renderStrategy: "fill"
259060
259208
  }))
259061
259209
  }));
259062
- }, [markersForThisRepo, cityData]);
259210
+ }, [markersForThisRepo, cityData, trail2]);
259063
259211
  const trailFilesActive = trailFilesHighlightLayers !== null && trailFilesHighlightLayers.length > 0;
259064
259212
  const hoveredFileHighlightLayer = React.useMemo(() => {
259065
259213
  if (!hoveredFilePath || !cityData) return null;
@@ -259084,12 +259232,49 @@ const FileCityTrailSequenceLayout = ({
259084
259232
  ]
259085
259233
  };
259086
259234
  }, [hoveredFilePath, cityData, theme2.colors.accent]);
259235
+ const districtTintLayers = React.useMemo(() => {
259236
+ if (!cityData) return null;
259237
+ const repos = trail2.repos ?? [];
259238
+ if (repos.length <= 1) return null;
259239
+ const palette = ["#3b82f6", "#a855f7", "#f97316", "#10b981", "#eab308"];
259240
+ const layers = [];
259241
+ repos.forEach((repo, i) => {
259242
+ const prefix = `${repo.name}/`;
259243
+ const paths = [];
259244
+ for (const b of cityData.buildings) {
259245
+ if (b.path === repo.name || b.path.startsWith(prefix)) {
259246
+ paths.push(b.path);
259247
+ } else if (b.path.includes(`/${prefix}`)) {
259248
+ paths.push(b.path);
259249
+ }
259250
+ }
259251
+ if (paths.length === 0) return;
259252
+ layers.push({
259253
+ // The layer-system id is internal — using the PURL here is fine
259254
+ // (and uniquely scopes by canonical identity even if two repos
259255
+ // happened to share a `name`).
259256
+ id: `district-${repo.id}`,
259257
+ name: `District: ${repo.name}`,
259258
+ enabled: true,
259259
+ color: palette[i % palette.length],
259260
+ opacity: 0.18,
259261
+ priority: 10,
259262
+ items: paths.map((path2) => ({
259263
+ path: path2,
259264
+ type: "file",
259265
+ renderStrategy: "fill"
259266
+ }))
259267
+ });
259268
+ });
259269
+ return layers.length > 0 ? layers : null;
259270
+ }, [cityData, trail2.repos]);
259087
259271
  const cityHighlightLayers = React.useMemo(() => {
259088
259272
  const layers = [];
259273
+ if (districtTintLayers) layers.push(...districtTintLayers);
259089
259274
  if (trailFilesHighlightLayers) layers.push(...trailFilesHighlightLayers);
259090
259275
  if (hoveredFileHighlightLayer) layers.push(hoveredFileHighlightLayer);
259091
259276
  return layers.length > 0 ? layers : void 0;
259092
- }, [trailFilesHighlightLayers, hoveredFileHighlightLayer]);
259277
+ }, [districtTintLayers, trailFilesHighlightLayers, hoveredFileHighlightLayer]);
259093
259278
  const containerRef = React.useRef(null);
259094
259279
  const snippetPaneRef = React.useRef(null);
259095
259280
  const leaderLineRef = React.useRef(null);
@@ -259106,10 +259291,11 @@ const FileCityTrailSequenceLayout = ({
259106
259291
  const [snippetPaneWidth, setSnippetPaneWidth] = React.useState(null);
259107
259292
  const [containerSize, setContainerSize] = React.useState(null);
259108
259293
  const selectedBuilding = React.useMemo(() => {
259109
- if (!cityData || !(selectedMarker == null ? void 0 : selectedMarker.sourcePath)) return null;
259110
- const path2 = selectedMarker.sourcePath;
259294
+ if (!cityData || !selectedMarker) return null;
259295
+ const path2 = markerCityPath(selectedMarker, trail2);
259296
+ if (!path2) return null;
259111
259297
  return cityData.buildings.find((b) => b.path === path2) ?? cityData.buildings.find((b) => b.path.endsWith(`/${path2}`)) ?? null;
259112
- }, [cityData, selectedMarker]);
259298
+ }, [cityData, selectedMarker, trail2]);
259113
259299
  const cityCenter = React.useMemo(() => {
259114
259300
  if (!cityData) return null;
259115
259301
  return {
@@ -259117,17 +259303,42 @@ const FileCityTrailSequenceLayout = ({
259117
259303
  z: (cityData.bounds.minZ + cityData.bounds.maxZ) / 2
259118
259304
  };
259119
259305
  }, [cityData]);
259120
- const trailPathBuildings = React.useMemo(() => {
259121
- if (!cityData || markersForThisRepo.length === 0) return [];
259122
- const buildingByPath = new Map(cityData.buildings.map((b) => [b.path, b]));
259123
- const out = [];
259306
+ const { trailPathBuildings, trailPathTitles, trailPathMarkerIds } = React.useMemo(() => {
259307
+ var _a2;
259308
+ if (!cityData || markersForThisRepo.length === 0) {
259309
+ return {
259310
+ trailPathBuildings: [],
259311
+ trailPathTitles: [],
259312
+ trailPathMarkerIds: []
259313
+ };
259314
+ }
259315
+ const buildingByPath = new Map(
259316
+ cityData.buildings.map((b) => [b.path, b])
259317
+ );
259318
+ const buildings = [];
259319
+ const titles = [];
259320
+ const markerIds = [];
259124
259321
  for (const m of markersForThisRepo) {
259125
- if (!m.sourcePath) continue;
259126
- const b = buildingByPath.get(m.sourcePath) ?? cityData.buildings.find((cb) => cb.path.endsWith(`/${m.sourcePath}`));
259127
- if (b) out.push(b);
259322
+ const cityPath = markerCityPath(m, trail2);
259323
+ if (!cityPath) continue;
259324
+ const b = buildingByPath.get(cityPath) ?? cityData.buildings.find((cb) => cb.path.endsWith(`/${cityPath}`));
259325
+ if (b) {
259326
+ buildings.push(b);
259327
+ titles.push(((_a2 = m.label) == null ? void 0 : _a2.trim()) || null);
259328
+ markerIds.push(m.id);
259329
+ }
259128
259330
  }
259129
- return out;
259130
- }, [cityData, markersForThisRepo]);
259331
+ return {
259332
+ trailPathBuildings: buildings,
259333
+ trailPathTitles: titles,
259334
+ trailPathMarkerIds: markerIds
259335
+ };
259336
+ }, [cityData, markersForThisRepo, trail2]);
259337
+ const trailPathCurrentStepIndex = React.useMemo(() => {
259338
+ if (!selectedMarkerId) return null;
259339
+ const idx = trailPathMarkerIds.indexOf(selectedMarkerId);
259340
+ return idx >= 0 ? idx : null;
259341
+ }, [selectedMarkerId, trailPathMarkerIds]);
259131
259342
  const onCameraFrame = React.useCallback(
259132
259343
  (camera, size) => {
259133
259344
  var _a2, _b2;
@@ -259172,13 +259383,18 @@ const FileCityTrailSequenceLayout = ({
259172
259383
  return () => observer.disconnect();
259173
259384
  }, [snippetPaneEl]);
259174
259385
  const overlayMarkdown = ((_a = selectedMarker == null ? void 0 : selectedMarker.description) == null ? void 0 : _a.trim()) ? {
259175
- eyebrow: "Marker",
259386
+ eyebrow: null,
259176
259387
  title: selectedMarker.label ?? selectedMarker.id,
259388
+ // File path under the title — the panel header already names
259389
+ // the trail, so swapping the "Marker" eyebrow for the marker's
259390
+ // sourcePath gives the user the more useful piece of context.
259391
+ subtitle: selectedMarker.sourcePath ?? null,
259177
259392
  markdown: selectedMarker.description,
259178
259393
  slideIdPrefix: `trail-${trail2.id}-marker-${selectedMarker.id}`
259179
259394
  } : ((_b = trail2.summary) == null ? void 0 : _b.trim()) ? {
259180
259395
  eyebrow: null,
259181
259396
  title: null,
259397
+ subtitle: null,
259182
259398
  markdown: trail2.summary,
259183
259399
  slideIdPrefix: `trail-${trail2.id}-summary`
259184
259400
  } : null;
@@ -259262,6 +259478,7 @@ const FileCityTrailSequenceLayout = ({
259262
259478
  {
259263
259479
  trail: trail2,
259264
259480
  markerCount: markersForThisRepo.length,
259481
+ activeMarkerIndex: stepperIndex,
259265
259482
  show3D: effectiveShow3D,
259266
259483
  onToggle3D: () => setShow3D((v) => !v),
259267
259484
  hideToggle: THREE_D_TOGGLE_DISABLED,
@@ -259274,13 +259491,16 @@ const FileCityTrailSequenceLayout = ({
259274
259491
  // Drawer-open is the default start state, so it no longer
259275
259492
  // counts as "non-idle". Exit is offered only when the user
259276
259493
  // has drilled into something the start view doesn't show.
259277
- selectedMarkerId != null || snippetExpanded || viewMode !== "city"
259494
+ // The "idle" view-mode is the host-supplied default — when
259495
+ // the host opens the panel in 'doc', staying in 'doc' is
259496
+ // idle and switching to 'city' is the non-idle drill-in.
259497
+ selectedMarkerId != null || snippetExpanded || viewMode !== defaultViewMode
259278
259498
  ),
259279
259499
  onExitTrail: () => {
259280
259500
  onSelectMarker(null);
259281
259501
  setDrawerHeightOverridePct(null);
259282
259502
  setSnippetExpanded(false);
259283
- setViewMode("city");
259503
+ setViewMode(defaultViewMode);
259284
259504
  },
259285
259505
  viewMode,
259286
259506
  onSetViewMode: setViewMode
@@ -259312,7 +259532,7 @@ const FileCityTrailSequenceLayout = ({
259312
259532
  cityData,
259313
259533
  width: "100%",
259314
259534
  height: "100%",
259315
- selectedPath: (selectedMarker == null ? void 0 : selectedMarker.sourcePath) ?? null,
259535
+ selectedPath: selectedMarker ? markerCityPath(selectedMarker, trail2) : null,
259316
259536
  onBuildingClick: handleBuildingClick,
259317
259537
  onCameraFrame,
259318
259538
  showControls: false,
@@ -259329,6 +259549,8 @@ const FileCityTrailSequenceLayout = ({
259329
259549
  ref: filePathRef,
259330
259550
  containerRef,
259331
259551
  buildings: trailPathBuildings,
259552
+ markerTitles: trailPathTitles,
259553
+ currentStepIndex: trailPathCurrentStepIndex,
259332
259554
  cityCenter
259333
259555
  }
259334
259556
  ),
@@ -259347,6 +259569,7 @@ const FileCityTrailSequenceLayout = ({
259347
259569
  {
259348
259570
  eyebrow: overlayMarkdown.eyebrow,
259349
259571
  title: overlayMarkdown.title,
259572
+ subtitle: overlayMarkdown.subtitle,
259350
259573
  markdown: overlayMarkdown.markdown,
259351
259574
  slideIdPrefix: overlayMarkdown.slideIdPrefix,
259352
259575
  bottomOffset: `${drawerHeightPct}%`,
@@ -259388,7 +259611,8 @@ const FileCityTrailSequenceLayout = ({
259388
259611
  drawerHeightPct,
259389
259612
  disableBottomTransition: isResizingDrawer,
259390
259613
  expanded: snippetExpanded,
259391
- onToggleExpanded: () => setSnippetExpanded((v) => !v)
259614
+ onToggleExpanded: () => setSnippetExpanded((v) => !v),
259615
+ markdownOverlayWidth
259392
259616
  }
259393
259617
  ) : null
259394
259618
  ]
@@ -259555,7 +259779,8 @@ const SnippetSidePane = React.forwardRef(function SnippetSidePane2({
259555
259779
  drawerHeightPct,
259556
259780
  disableBottomTransition,
259557
259781
  expanded,
259558
- onToggleExpanded
259782
+ onToggleExpanded,
259783
+ markdownOverlayWidth
259559
259784
  }, ref) {
259560
259785
  const { theme: theme2 } = useTheme();
259561
259786
  if (!marker.sourcePath) {
@@ -259569,6 +259794,7 @@ const SnippetSidePane = React.forwardRef(function SnippetSidePane2({
259569
259794
  disableBottomTransition,
259570
259795
  expanded,
259571
259796
  onToggleExpanded,
259797
+ markdownOverlayWidth,
259572
259798
  children: /* @__PURE__ */ jsx(
259573
259799
  "div",
259574
259800
  {
@@ -259594,6 +259820,7 @@ const SnippetSidePane = React.forwardRef(function SnippetSidePane2({
259594
259820
  disableBottomTransition,
259595
259821
  expanded,
259596
259822
  onToggleExpanded,
259823
+ markdownOverlayWidth,
259597
259824
  children: snippet2.kind === "slice" ? /* @__PURE__ */ jsx(
259598
259825
  TrailSnippetView,
259599
259826
  {
@@ -259635,10 +259862,12 @@ const SidePaneFrame = React.forwardRef(
259635
259862
  drawerHeightPct,
259636
259863
  disableBottomTransition,
259637
259864
  expanded,
259638
- onToggleExpanded
259865
+ onToggleExpanded,
259866
+ markdownOverlayWidth
259639
259867
  }, ref) {
259640
259868
  const { theme: theme2 } = useTheme();
259641
259869
  const [widthPx, setWidthPx] = React.useState(null);
259870
+ const defaultLeftInset = (markdownOverlayWidth ?? 0) + SNIPPET_PANE_LEADER_BUFFER_PX;
259642
259871
  const [isResizing, setIsResizing] = React.useState(false);
259643
259872
  const innerRef = React.useRef(null);
259644
259873
  const setInnerRef = React.useCallback(
@@ -259677,7 +259906,7 @@ const SidePaneFrame = React.forwardRef(
259677
259906
  const parentWidth = (parent == null ? void 0 : parent.clientWidth) ?? window.innerWidth;
259678
259907
  const maxWidth = Math.max(
259679
259908
  SNIPPET_PANE_MIN_WIDTH_PX,
259680
- parentWidth - 32
259909
+ parentWidth - defaultLeftInset - SNIPPET_PANE_RIGHT_GUTTER_PX
259681
259910
  );
259682
259911
  const dx = e.clientX - drag2.startX;
259683
259912
  const next2 = Math.min(
@@ -259686,7 +259915,7 @@ const SidePaneFrame = React.forwardRef(
259686
259915
  );
259687
259916
  setWidthPx(next2);
259688
259917
  },
259689
- []
259918
+ [defaultLeftInset]
259690
259919
  );
259691
259920
  const handleResizePointerUp = React.useCallback(
259692
259921
  (e) => {
@@ -259706,9 +259935,15 @@ const SidePaneFrame = React.forwardRef(
259706
259935
  style: {
259707
259936
  position: "absolute",
259708
259937
  top: 16,
259709
- right: 16,
259938
+ right: SNIPPET_PANE_RIGHT_GUTTER_PX,
259710
259939
  bottom: expanded ? `calc(${drawerHeightPct}% + 16px)` : "50%",
259711
- width: widthPx ?? SNIPPET_PANE_WIDTH_PX,
259940
+ // Auto-fill the right column when the user hasn't dragged an
259941
+ // explicit width: anchor to the markdown overlay's right edge
259942
+ // (plus a leader-line buffer) and the city container's right
259943
+ // gutter. Once `widthPx` is set, switch to an explicit width
259944
+ // and let `right` keep the right anchor.
259945
+ left: widthPx == null ? defaultLeftInset : void 0,
259946
+ width: widthPx ?? void 0,
259712
259947
  minWidth: SNIPPET_PANE_MIN_WIDTH_PX,
259713
259948
  backgroundColor: theme2.colors.background,
259714
259949
  border: `1px solid ${theme2.colors.border}`,
@@ -259771,33 +260006,77 @@ const SidePaneFrame = React.forwardRef(
259771
260006
  flexShrink: 0
259772
260007
  },
259773
260008
  children: [
259774
- /* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
259775
- /* @__PURE__ */ jsx(
259776
- "div",
259777
- {
259778
- style: {
259779
- fontFamily: theme2.fonts.heading,
259780
- fontSize: theme2.fontSizes[0],
259781
- fontWeight: theme2.fontWeights.semibold,
259782
- color: theme2.colors.text
259783
- },
259784
- children: marker.label ?? marker.id
259785
- }
259786
- ),
259787
- marker.sourcePath ? /* @__PURE__ */ jsx(
259788
- "div",
259789
- {
259790
- style: {
259791
- fontSize: theme2.fontSizes[0],
259792
- color: theme2.colors.textSecondary,
259793
- fontFamily: theme2.fonts.monospace,
259794
- marginTop: 2,
259795
- wordBreak: "break-all"
259796
- },
259797
- children: marker.sourcePath
259798
- }
259799
- ) : null
259800
- ] }),
260009
+ /* @__PURE__ */ jsx("div", { style: { minWidth: 0, flex: 1 }, children: (() => {
260010
+ const path2 = marker.sourcePath ?? "";
260011
+ const slashIdx = path2.lastIndexOf("/");
260012
+ const filename = slashIdx >= 0 ? path2.slice(slashIdx + 1) : path2;
260013
+ const directory = slashIdx >= 0 ? path2.slice(0, slashIdx + 1) : null;
260014
+ const snippet2 = marker.snippet;
260015
+ const rangeLabel = snippet2 ? snippet2.startLine === snippet2.endLine ? `${snippet2.startLine}` : `${snippet2.startLine}–${snippet2.endLine}` : null;
260016
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
260017
+ /* @__PURE__ */ jsxs(
260018
+ "div",
260019
+ {
260020
+ style: {
260021
+ display: "flex",
260022
+ alignItems: "baseline",
260023
+ gap: 8,
260024
+ minWidth: 0
260025
+ },
260026
+ children: [
260027
+ /* @__PURE__ */ jsx(
260028
+ "div",
260029
+ {
260030
+ style: {
260031
+ fontFamily: theme2.fonts.monospace,
260032
+ fontSize: theme2.fontSizes[1],
260033
+ fontWeight: theme2.fontWeights.semibold,
260034
+ color: theme2.colors.text,
260035
+ overflow: "hidden",
260036
+ textOverflow: "ellipsis",
260037
+ whiteSpace: "nowrap",
260038
+ minWidth: 0,
260039
+ flexShrink: 1
260040
+ },
260041
+ title: path2 || void 0,
260042
+ children: filename || marker.id
260043
+ }
260044
+ ),
260045
+ rangeLabel ? /* @__PURE__ */ jsx(
260046
+ "div",
260047
+ {
260048
+ style: {
260049
+ fontFamily: theme2.fonts.monospace,
260050
+ fontSize: theme2.fontSizes[0],
260051
+ color: theme2.colors.textSecondary,
260052
+ letterSpacing: 0.4,
260053
+ textTransform: "uppercase",
260054
+ flexShrink: 0
260055
+ },
260056
+ children: rangeLabel
260057
+ }
260058
+ ) : null
260059
+ ]
260060
+ }
260061
+ ),
260062
+ directory ? /* @__PURE__ */ jsx(
260063
+ "div",
260064
+ {
260065
+ style: {
260066
+ fontSize: theme2.fontSizes[0],
260067
+ color: theme2.colors.textSecondary,
260068
+ fontFamily: theme2.fonts.monospace,
260069
+ marginTop: 2,
260070
+ overflow: "hidden",
260071
+ textOverflow: "ellipsis",
260072
+ whiteSpace: "nowrap"
260073
+ },
260074
+ title: directory,
260075
+ children: directory
260076
+ }
260077
+ ) : null
260078
+ ] });
260079
+ })() }),
259801
260080
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, flexShrink: 0 }, children: [
259802
260081
  /* @__PURE__ */ jsx(
259803
260082
  "button",
@@ -260094,6 +260373,7 @@ const TrailDocumentCard = ({
260094
260373
  const TrailHeader = ({
260095
260374
  trail: trail2,
260096
260375
  markerCount,
260376
+ activeMarkerIndex,
260097
260377
  show3D,
260098
260378
  onToggle3D,
260099
260379
  hideToggle = false,
@@ -260173,20 +260453,34 @@ const TrailHeader = ({
260173
260453
  children: trail2.title
260174
260454
  }
260175
260455
  ),
260176
- /* @__PURE__ */ jsxs(
260456
+ /* @__PURE__ */ jsx(
260177
260457
  "div",
260178
260458
  {
260459
+ "aria-label": `${markerCount} marker${markerCount === 1 ? "" : "s"} in this repo`,
260179
260460
  style: {
260180
- fontFamily: theme2.fonts.body,
260181
- fontSize: theme2.fontSizes[0],
260182
- color: theme2.colors.textSecondary
260461
+ display: "flex",
260462
+ alignItems: "center",
260463
+ height: theme2.fontSizes[0]
260183
260464
  },
260184
- children: [
260185
- markerCount,
260186
- " marker",
260187
- markerCount === 1 ? "" : "s",
260188
- " in this repo"
260189
- ]
260465
+ children: Array.from({ length: markerCount }).map((_, i) => {
260466
+ const isActive = i === activeMarkerIndex;
260467
+ return /* @__PURE__ */ jsx(
260468
+ "span",
260469
+ {
260470
+ style: {
260471
+ width: 6,
260472
+ height: 6,
260473
+ borderRadius: "50%",
260474
+ background: isActive ? theme2.colors.accent : theme2.colors.textSecondary,
260475
+ // Group dots in fives for at-a-glance countability — a
260476
+ // wider gap before every 5th index (after the first)
260477
+ // creates visual columns of 5 like tally marks.
260478
+ marginLeft: i === 0 ? 0 : i % 5 === 0 ? 11 : 5
260479
+ }
260480
+ },
260481
+ i
260482
+ );
260483
+ })
260190
260484
  }
260191
260485
  )
260192
260486
  ]
@@ -260341,6 +260635,15 @@ function filterMarkersForRepo(trail2, repository) {
260341
260635
  }
260342
260636
  return trail2.markers.filter((m) => m.repo === repository.id);
260343
260637
  }
260638
+ function markerCityPath(marker, trail2) {
260639
+ if (!marker.sourcePath) return null;
260640
+ const repos = trail2.repos ?? [];
260641
+ if (repos.length <= 1) return marker.sourcePath;
260642
+ if (!marker.repo) return null;
260643
+ const repo = repos.find((r2) => r2.id === marker.repo);
260644
+ if (!repo) return null;
260645
+ return `${repo.name}/${marker.sourcePath}`;
260646
+ }
260344
260647
  const focusBuildingTool = {
260345
260648
  name: "focus_building",
260346
260649
  description: "Focuses the camera on a specific file (building) in the file city visualization",