@industry-theme/file-city-panel 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TourPlayer.d.ts +1 -1
- package/dist/components/TourPlayer.d.ts.map +1 -1
- package/dist/components/TourPlayerIntegration.d.ts +1 -1
- package/dist/components/TourPlayerIntegration.d.ts.map +1 -1
- package/dist/hooks/useTourPlayer.d.ts +1 -1
- package/dist/hooks/useTourPlayer.d.ts.map +1 -1
- package/dist/panels.bundle.js +230 -268
- package/dist/panels.bundle.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/types/IntroductionTour.d.ts +0 -108
- package/dist/types/IntroductionTour.d.ts.map +0 -1
- package/dist/utils/tourParser.d.ts +0 -65
- package/dist/utils/tourParser.d.ts.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { IntroductionTour, IntroductionTourStep } from '
|
|
2
|
+
import type { IntroductionTour, IntroductionTourStep } from '@principal-ai/file-city-builder';
|
|
3
3
|
import type { TextToSpeechAdapter, TourAudioContext } from '../types/TextToSpeech';
|
|
4
4
|
export interface TourPlayerProps {
|
|
5
5
|
/** The introduction tour to play */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourPlayer.d.ts","sourceRoot":"","sources":["../../src/components/TourPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAiBxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"TourPlayer.d.ts","sourceRoot":"","sources":["../../src/components/TourPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAiBxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGnF,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,IAAI,EAAE,gBAAgB,CAAC;IAEvB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,iCAAiC;IACjC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAEvE,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB,uDAAuD;IACvD,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAE1E,yCAAyC;IACzC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,qIAAqI;IACrI,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAE3D,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IAGtB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,mBAAmB,CAAC;IAEjC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC,yDAAyD;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,iEAAiE;IACjE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA4/BhD,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { PanelEventBus } from '@principal-ade/panel-framework-core';
|
|
3
|
-
import type { IntroductionTour } from '
|
|
3
|
+
import type { IntroductionTour } from '@principal-ai/file-city-builder';
|
|
4
4
|
export interface TourPlayerIntegrationProps {
|
|
5
5
|
/** The introduction tour */
|
|
6
6
|
tour: IntroductionTour;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourPlayerIntegration.d.ts","sourceRoot":"","sources":["../../src/components/TourPlayerIntegration.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiC,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAA8C,MAAM,
|
|
1
|
+
{"version":3,"file":"TourPlayerIntegration.d.ts","sourceRoot":"","sources":["../../src/components/TourPlayerIntegration.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiC,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAA8C,MAAM,iCAAiC,CAAC;AAGpH,MAAM,WAAW,0BAA0B;IACzC,4BAA4B;IAC5B,IAAI,EAAE,gBAAgB,CAAC;IAEvB,0DAA0D;IAC1D,MAAM,EAAE,aAAa,CAAC;IAEtB,yCAAyC;IACzC,OAAO,EAAE,OAAO,CAAC;IAEjB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAC;IAEnB,gIAAgI;IAChI,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;CAC5D;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA4LtE,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IntroductionTour, IntroductionTourStep } from '
|
|
1
|
+
import type { IntroductionTour, IntroductionTourStep } from '@principal-ai/file-city-builder';
|
|
2
2
|
export interface TourPlayerState {
|
|
3
3
|
/** Current step index */
|
|
4
4
|
currentStepIndex: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTourPlayer.d.ts","sourceRoot":"","sources":["../../src/hooks/useTourPlayer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"useTourPlayer.d.ts","sourceRoot":"","sources":["../../src/hooks/useTourPlayer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE9F,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IAEzB,mBAAmB;IACnB,WAAW,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAEzC,8BAA8B;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAElB,+BAA+B;IAC/B,SAAS,EAAE,OAAO,CAAC;IAEnB,gCAAgC;IAChC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAE5B,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;IAElB,qBAAqB;IACrB,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB,sBAAsB;IACtB,KAAK,EAAE,MAAM,IAAI,CAAC;IAElB,uBAAuB;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;IAEnB,sBAAsB;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IAErB,0BAA0B;IAC1B,YAAY,EAAE,MAAM,IAAI,CAAC;IAEzB,mCAAmC;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,qCAAqC;IACrC,YAAY,EAAE,MAAM,IAAI,CAAC;IAEzB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,wBAAwB;IACxB,KAAK,EAAE,gBAAgB,CAAC;IAExB,iCAAiC;IACjC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnE,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IAExB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,CAAC,eAAe,EAAE,iBAAiB,CAAC,CA0GtC"}
|
package/dist/panels.bundle.js
CHANGED
|
@@ -38567,16 +38567,244 @@ const files = {
|
|
|
38567
38567
|
defaultConfig,
|
|
38568
38568
|
includeUnmatched
|
|
38569
38569
|
};
|
|
38570
|
+
class TourValidationError extends Error {
|
|
38571
|
+
constructor(message, field, value) {
|
|
38572
|
+
super(message);
|
|
38573
|
+
this.field = field;
|
|
38574
|
+
this.value = value;
|
|
38575
|
+
this.name = "TourValidationError";
|
|
38576
|
+
}
|
|
38577
|
+
}
|
|
38578
|
+
function isValidHexColor(color2) {
|
|
38579
|
+
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color2);
|
|
38580
|
+
}
|
|
38581
|
+
function isValidVersion(version2) {
|
|
38582
|
+
return /^\d+\.\d+\.\d+$/.test(version2);
|
|
38583
|
+
}
|
|
38584
|
+
function isValidRelativePath(path) {
|
|
38585
|
+
return !path.startsWith("/");
|
|
38586
|
+
}
|
|
38587
|
+
function isValidKebabCase(id2) {
|
|
38588
|
+
return /^[a-z0-9-]+$/.test(id2);
|
|
38589
|
+
}
|
|
38590
|
+
function validateStep(step, index2) {
|
|
38591
|
+
const errors = [];
|
|
38592
|
+
if (!step.id || typeof step.id !== "string") {
|
|
38593
|
+
errors.push(new TourValidationError(`Step ${index2}: Missing or invalid 'id'`, "id", step.id));
|
|
38594
|
+
} else if (!isValidKebabCase(step.id)) {
|
|
38595
|
+
errors.push(new TourValidationError(`Step ${index2}: 'id' must be kebab-case (lowercase, numbers, hyphens only)`, "id", step.id));
|
|
38596
|
+
}
|
|
38597
|
+
if (!step.title || typeof step.title !== "string") {
|
|
38598
|
+
errors.push(new TourValidationError(`Step ${index2}: Missing or invalid 'title'`, "title", step.title));
|
|
38599
|
+
}
|
|
38600
|
+
if (!step.description || typeof step.description !== "string") {
|
|
38601
|
+
errors.push(new TourValidationError(`Step ${index2}: Missing or invalid 'description'`, "description", step.description));
|
|
38602
|
+
}
|
|
38603
|
+
if (step.estimatedTime !== void 0 && (typeof step.estimatedTime !== "number" || step.estimatedTime < 1)) {
|
|
38604
|
+
errors.push(new TourValidationError(`Step ${index2}: 'estimatedTime' must be a positive number`, "estimatedTime", step.estimatedTime));
|
|
38605
|
+
}
|
|
38606
|
+
if (step.focusDirectory !== void 0) {
|
|
38607
|
+
if (typeof step.focusDirectory !== "string") {
|
|
38608
|
+
errors.push(new TourValidationError(`Step ${index2}: 'focusDirectory' must be a string`, "focusDirectory", step.focusDirectory));
|
|
38609
|
+
} else if (!isValidRelativePath(step.focusDirectory)) {
|
|
38610
|
+
errors.push(new TourValidationError(`Step ${index2}: 'focusDirectory' must be a relative path (no leading slash)`, "focusDirectory", step.focusDirectory));
|
|
38611
|
+
}
|
|
38612
|
+
}
|
|
38613
|
+
if (step.autoAdvance && step.autoAdvanceDelay !== void 0) {
|
|
38614
|
+
if (typeof step.autoAdvanceDelay !== "number" || step.autoAdvanceDelay < 1e3) {
|
|
38615
|
+
errors.push(new TourValidationError(`Step ${index2}: 'autoAdvanceDelay' must be at least 1000ms when auto-advance is enabled`, "autoAdvanceDelay", step.autoAdvanceDelay));
|
|
38616
|
+
}
|
|
38617
|
+
}
|
|
38618
|
+
if (step.highlightLayers) {
|
|
38619
|
+
step.highlightLayers.forEach((layer, layerIndex) => {
|
|
38620
|
+
if (!layer.id || !isValidKebabCase(layer.id)) {
|
|
38621
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}: Invalid layer 'id' (must be kebab-case)`, `highlightLayers[${layerIndex}].id`, layer.id));
|
|
38622
|
+
}
|
|
38623
|
+
if (!layer.color || !isValidHexColor(layer.color)) {
|
|
38624
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}: Invalid hex color`, `highlightLayers[${layerIndex}].color`, layer.color));
|
|
38625
|
+
}
|
|
38626
|
+
if (layer.opacity !== void 0 && (layer.opacity < 0 || layer.opacity > 1)) {
|
|
38627
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}: 'opacity' must be between 0 and 1`, `highlightLayers[${layerIndex}].opacity`, layer.opacity));
|
|
38628
|
+
}
|
|
38629
|
+
if (layer.borderWidth !== void 0 && layer.borderWidth < 0) {
|
|
38630
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}: 'borderWidth' must be positive`, `highlightLayers[${layerIndex}].borderWidth`, layer.borderWidth));
|
|
38631
|
+
}
|
|
38632
|
+
if (!layer.items || layer.items.length === 0) {
|
|
38633
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}: 'items' array must not be empty`, `highlightLayers[${layerIndex}].items`, layer.items));
|
|
38634
|
+
} else {
|
|
38635
|
+
layer.items.forEach((item, itemIndex) => {
|
|
38636
|
+
if (!item.path || !isValidRelativePath(item.path)) {
|
|
38637
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}, Item ${itemIndex}: Invalid relative path`, `highlightLayers[${layerIndex}].items[${itemIndex}].path`, item.path));
|
|
38638
|
+
}
|
|
38639
|
+
if (!item.type || item.type !== "file" && item.type !== "directory") {
|
|
38640
|
+
errors.push(new TourValidationError(`Step ${index2}, Layer ${layerIndex}, Item ${itemIndex}: 'type' must be 'file' or 'directory'`, `highlightLayers[${layerIndex}].items[${itemIndex}].type`, item.type));
|
|
38641
|
+
}
|
|
38642
|
+
});
|
|
38643
|
+
}
|
|
38644
|
+
});
|
|
38645
|
+
}
|
|
38646
|
+
if (step.highlightFiles) {
|
|
38647
|
+
step.highlightFiles.forEach((filePath, fileIndex) => {
|
|
38648
|
+
if (!isValidRelativePath(filePath)) {
|
|
38649
|
+
errors.push(new TourValidationError(`Step ${index2}, highlightFiles[${fileIndex}]: Must be a relative path (no leading slash)`, `highlightFiles[${fileIndex}]`, filePath));
|
|
38650
|
+
}
|
|
38651
|
+
});
|
|
38652
|
+
}
|
|
38653
|
+
if (step.interactiveActions) {
|
|
38654
|
+
step.interactiveActions.forEach((action, actionIndex) => {
|
|
38655
|
+
const needsTarget = ["click-file", "hover-directory", "toggle-layer"].includes(action.type);
|
|
38656
|
+
if (needsTarget && !action.target) {
|
|
38657
|
+
errors.push(new TourValidationError(`Step ${index2}, Action ${actionIndex}: '${action.type}' requires a 'target'`, `interactiveActions[${actionIndex}].target`, action.target));
|
|
38658
|
+
}
|
|
38659
|
+
});
|
|
38660
|
+
}
|
|
38661
|
+
return errors;
|
|
38662
|
+
}
|
|
38663
|
+
function validateTour(tour) {
|
|
38664
|
+
const errors = [];
|
|
38665
|
+
if (!tour.id || typeof tour.id !== "string") {
|
|
38666
|
+
errors.push(new TourValidationError("Missing or invalid 'id'", "id", tour.id));
|
|
38667
|
+
} else if (!isValidKebabCase(tour.id)) {
|
|
38668
|
+
errors.push(new TourValidationError("Tour 'id' must be kebab-case (lowercase, numbers, hyphens only)", "id", tour.id));
|
|
38669
|
+
}
|
|
38670
|
+
if (!tour.title || typeof tour.title !== "string") {
|
|
38671
|
+
errors.push(new TourValidationError("Missing or invalid 'title'", "title", tour.title));
|
|
38672
|
+
}
|
|
38673
|
+
if (!tour.description || typeof tour.description !== "string") {
|
|
38674
|
+
errors.push(new TourValidationError("Missing or invalid 'description'", "description", tour.description));
|
|
38675
|
+
}
|
|
38676
|
+
if (!tour.version || !isValidVersion(tour.version)) {
|
|
38677
|
+
errors.push(new TourValidationError("Invalid 'version' - must be semantic version (e.g., '1.0.0')", "version", tour.version));
|
|
38678
|
+
}
|
|
38679
|
+
if (!tour.steps || !Array.isArray(tour.steps) || tour.steps.length === 0) {
|
|
38680
|
+
errors.push(new TourValidationError("'steps' array must contain at least one step", "steps", tour.steps));
|
|
38681
|
+
} else {
|
|
38682
|
+
tour.steps.forEach((step, index2) => {
|
|
38683
|
+
const stepErrors = validateStep(step, index2);
|
|
38684
|
+
errors.push(...stepErrors);
|
|
38685
|
+
});
|
|
38686
|
+
const stepIds = /* @__PURE__ */ new Set();
|
|
38687
|
+
tour.steps.forEach((step, index2) => {
|
|
38688
|
+
if (stepIds.has(step.id)) {
|
|
38689
|
+
errors.push(new TourValidationError(`Duplicate step ID '${step.id}' at index ${index2}`, "steps", step.id));
|
|
38690
|
+
}
|
|
38691
|
+
stepIds.add(step.id);
|
|
38692
|
+
});
|
|
38693
|
+
}
|
|
38694
|
+
if (tour.audience !== void 0 && typeof tour.audience !== "string") {
|
|
38695
|
+
errors.push(new TourValidationError(`Invalid 'audience' - must be a string`, "audience", tour.audience));
|
|
38696
|
+
}
|
|
38697
|
+
return errors;
|
|
38698
|
+
}
|
|
38699
|
+
function parseTour(jsonString) {
|
|
38700
|
+
try {
|
|
38701
|
+
const parsed = JSON.parse(jsonString);
|
|
38702
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
38703
|
+
return {
|
|
38704
|
+
success: false,
|
|
38705
|
+
errors: [new TourValidationError("Tour JSON must be an object")]
|
|
38706
|
+
};
|
|
38707
|
+
}
|
|
38708
|
+
const errors = validateTour(parsed);
|
|
38709
|
+
if (errors.length > 0) {
|
|
38710
|
+
return {
|
|
38711
|
+
success: false,
|
|
38712
|
+
errors
|
|
38713
|
+
};
|
|
38714
|
+
}
|
|
38715
|
+
return {
|
|
38716
|
+
success: true,
|
|
38717
|
+
tour: parsed
|
|
38718
|
+
};
|
|
38719
|
+
} catch (error) {
|
|
38720
|
+
return {
|
|
38721
|
+
success: false,
|
|
38722
|
+
errors: [
|
|
38723
|
+
new TourValidationError(`Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`)
|
|
38724
|
+
]
|
|
38725
|
+
};
|
|
38726
|
+
}
|
|
38727
|
+
}
|
|
38728
|
+
function parseTourOrThrow(jsonString) {
|
|
38729
|
+
var _a;
|
|
38730
|
+
const result = parseTour(jsonString);
|
|
38731
|
+
if (!result.success || !result.tour) {
|
|
38732
|
+
const errorMessages2 = ((_a = result.errors) == null ? void 0 : _a.map((e) => e.message).join("\n")) || "Unknown error";
|
|
38733
|
+
throw new TourValidationError(`Tour validation failed:
|
|
38734
|
+
${errorMessages2}`);
|
|
38735
|
+
}
|
|
38736
|
+
return result.tour;
|
|
38737
|
+
}
|
|
38738
|
+
function findTourFilePathInFileTree(fileTree) {
|
|
38739
|
+
const tourFiles = fileTree.allFiles.filter((file) => {
|
|
38740
|
+
const path = file.path;
|
|
38741
|
+
return path.endsWith(".tour.json") && !path.includes("/");
|
|
38742
|
+
});
|
|
38743
|
+
tourFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
38744
|
+
const tourFile = tourFiles[0];
|
|
38745
|
+
return tourFile ? tourFile.path : null;
|
|
38746
|
+
}
|
|
38747
|
+
function findAllTourFilesInFileTree(fileTree) {
|
|
38748
|
+
return fileTree.allFiles.filter((file) => file.path.endsWith(".tour.json")).map((file) => file.path).sort((a, b) => a.localeCompare(b));
|
|
38749
|
+
}
|
|
38750
|
+
async function loadTourFromFileTree(fileTree, readFile) {
|
|
38751
|
+
const tourFilePath = findTourFilePathInFileTree(fileTree);
|
|
38752
|
+
if (!tourFilePath) {
|
|
38753
|
+
return {
|
|
38754
|
+
success: false,
|
|
38755
|
+
errors: [new TourValidationError("No *.tour.json file found in repository root")]
|
|
38756
|
+
};
|
|
38757
|
+
}
|
|
38758
|
+
try {
|
|
38759
|
+
const tourContent = await readFile(tourFilePath);
|
|
38760
|
+
return parseTour(tourContent);
|
|
38761
|
+
} catch (error) {
|
|
38762
|
+
return {
|
|
38763
|
+
success: false,
|
|
38764
|
+
errors: [
|
|
38765
|
+
new TourValidationError(`Failed to read tour file: ${error instanceof Error ? error.message : "Unknown error"}`)
|
|
38766
|
+
]
|
|
38767
|
+
};
|
|
38768
|
+
}
|
|
38769
|
+
}
|
|
38770
|
+
async function loadAllToursFromFileTree(fileTree, readFile) {
|
|
38771
|
+
const tourPaths = findAllTourFilesInFileTree(fileTree);
|
|
38772
|
+
const results = await Promise.all(tourPaths.map(async (path) => {
|
|
38773
|
+
try {
|
|
38774
|
+
const content = await readFile(path);
|
|
38775
|
+
const result = parseTour(content);
|
|
38776
|
+
return { path, result };
|
|
38777
|
+
} catch (error) {
|
|
38778
|
+
return {
|
|
38779
|
+
path,
|
|
38780
|
+
result: {
|
|
38781
|
+
success: false,
|
|
38782
|
+
errors: [
|
|
38783
|
+
new TourValidationError(`Failed to read tour file: ${error instanceof Error ? error.message : "Unknown error"}`)
|
|
38784
|
+
]
|
|
38785
|
+
}
|
|
38786
|
+
};
|
|
38787
|
+
}
|
|
38788
|
+
}));
|
|
38789
|
+
return results;
|
|
38790
|
+
}
|
|
38570
38791
|
const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
38571
38792
|
__proto__: null,
|
|
38572
38793
|
CodeCityBuilderWithGrid,
|
|
38573
38794
|
CommonSorts,
|
|
38574
38795
|
GridLayoutManager,
|
|
38575
38796
|
MultiVersionCityBuilder,
|
|
38797
|
+
TourValidationError,
|
|
38576
38798
|
buildFileSystemTreeFromFileInfoList,
|
|
38577
38799
|
buildMultiVersionCity,
|
|
38578
38800
|
defaultFileColorConfig: files,
|
|
38579
|
-
|
|
38801
|
+
findAllTourFilesInFileTree,
|
|
38802
|
+
findTourFilePathInFileTree,
|
|
38803
|
+
getFilesFromGitHubTree,
|
|
38804
|
+
loadAllToursFromFileTree,
|
|
38805
|
+
loadTourFromFileTree,
|
|
38806
|
+
parseTour,
|
|
38807
|
+
parseTourOrThrow
|
|
38580
38808
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
38581
38809
|
const require$$6 = /* @__PURE__ */ getAugmentedNamespace(dist);
|
|
38582
38810
|
var fileColorOverrides = {};
|
|
@@ -53267,272 +53495,6 @@ function getLayersForColorMode(mode, buildings, qualityData, fileColorLayers, gi
|
|
|
53267
53495
|
}
|
|
53268
53496
|
}
|
|
53269
53497
|
}
|
|
53270
|
-
class TourValidationError extends Error {
|
|
53271
|
-
constructor(message, field, value) {
|
|
53272
|
-
super(message);
|
|
53273
|
-
this.field = field;
|
|
53274
|
-
this.value = value;
|
|
53275
|
-
this.name = "TourValidationError";
|
|
53276
|
-
}
|
|
53277
|
-
}
|
|
53278
|
-
function isValidHexColor(color2) {
|
|
53279
|
-
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color2);
|
|
53280
|
-
}
|
|
53281
|
-
function isValidVersion(version2) {
|
|
53282
|
-
return /^\d+\.\d+\.\d+$/.test(version2);
|
|
53283
|
-
}
|
|
53284
|
-
function isValidRelativePath(path) {
|
|
53285
|
-
return !path.startsWith("/");
|
|
53286
|
-
}
|
|
53287
|
-
function validateStep(step, index2) {
|
|
53288
|
-
const errors = [];
|
|
53289
|
-
if (!step.id || typeof step.id !== "string") {
|
|
53290
|
-
errors.push(new TourValidationError(`Step ${index2}: Missing or invalid 'id'`, "id", step.id));
|
|
53291
|
-
} else if (!/^[a-z0-9-]+$/.test(step.id)) {
|
|
53292
|
-
errors.push(
|
|
53293
|
-
new TourValidationError(
|
|
53294
|
-
`Step ${index2}: 'id' must be kebab-case (lowercase, numbers, hyphens only)`,
|
|
53295
|
-
"id",
|
|
53296
|
-
step.id
|
|
53297
|
-
)
|
|
53298
|
-
);
|
|
53299
|
-
}
|
|
53300
|
-
if (!step.title || typeof step.title !== "string") {
|
|
53301
|
-
errors.push(new TourValidationError(`Step ${index2}: Missing or invalid 'title'`, "title", step.title));
|
|
53302
|
-
}
|
|
53303
|
-
if (!step.description || typeof step.description !== "string") {
|
|
53304
|
-
errors.push(
|
|
53305
|
-
new TourValidationError(`Step ${index2}: Missing or invalid 'description'`, "description", step.description)
|
|
53306
|
-
);
|
|
53307
|
-
}
|
|
53308
|
-
if (step.estimatedTime !== void 0 && (typeof step.estimatedTime !== "number" || step.estimatedTime < 1)) {
|
|
53309
|
-
errors.push(
|
|
53310
|
-
new TourValidationError(
|
|
53311
|
-
`Step ${index2}: 'estimatedTime' must be a positive number`,
|
|
53312
|
-
"estimatedTime",
|
|
53313
|
-
step.estimatedTime
|
|
53314
|
-
)
|
|
53315
|
-
);
|
|
53316
|
-
}
|
|
53317
|
-
if (step.focusDirectory !== void 0) {
|
|
53318
|
-
if (typeof step.focusDirectory !== "string") {
|
|
53319
|
-
errors.push(
|
|
53320
|
-
new TourValidationError(
|
|
53321
|
-
`Step ${index2}: 'focusDirectory' must be a string`,
|
|
53322
|
-
"focusDirectory",
|
|
53323
|
-
step.focusDirectory
|
|
53324
|
-
)
|
|
53325
|
-
);
|
|
53326
|
-
} else if (!isValidRelativePath(step.focusDirectory)) {
|
|
53327
|
-
errors.push(
|
|
53328
|
-
new TourValidationError(
|
|
53329
|
-
`Step ${index2}: 'focusDirectory' must be a relative path (no leading slash)`,
|
|
53330
|
-
"focusDirectory",
|
|
53331
|
-
step.focusDirectory
|
|
53332
|
-
)
|
|
53333
|
-
);
|
|
53334
|
-
}
|
|
53335
|
-
}
|
|
53336
|
-
if (step.autoAdvance && step.autoAdvanceDelay !== void 0) {
|
|
53337
|
-
if (typeof step.autoAdvanceDelay !== "number" || step.autoAdvanceDelay < 1e3) {
|
|
53338
|
-
errors.push(
|
|
53339
|
-
new TourValidationError(
|
|
53340
|
-
`Step ${index2}: 'autoAdvanceDelay' must be at least 1000ms when auto-advance is enabled`,
|
|
53341
|
-
"autoAdvanceDelay",
|
|
53342
|
-
step.autoAdvanceDelay
|
|
53343
|
-
)
|
|
53344
|
-
);
|
|
53345
|
-
}
|
|
53346
|
-
}
|
|
53347
|
-
if (step.highlightLayers) {
|
|
53348
|
-
step.highlightLayers.forEach((layer, layerIndex) => {
|
|
53349
|
-
if (!layer.id || !/^[a-z0-9-]+$/.test(layer.id)) {
|
|
53350
|
-
errors.push(
|
|
53351
|
-
new TourValidationError(
|
|
53352
|
-
`Step ${index2}, Layer ${layerIndex}: Invalid layer 'id'`,
|
|
53353
|
-
`highlightLayers[${layerIndex}].id`,
|
|
53354
|
-
layer.id
|
|
53355
|
-
)
|
|
53356
|
-
);
|
|
53357
|
-
}
|
|
53358
|
-
if (!layer.color || !isValidHexColor(layer.color)) {
|
|
53359
|
-
errors.push(
|
|
53360
|
-
new TourValidationError(
|
|
53361
|
-
`Step ${index2}, Layer ${layerIndex}: Invalid hex color`,
|
|
53362
|
-
`highlightLayers[${layerIndex}].color`,
|
|
53363
|
-
layer.color
|
|
53364
|
-
)
|
|
53365
|
-
);
|
|
53366
|
-
}
|
|
53367
|
-
if (layer.opacity !== void 0 && (layer.opacity < 0 || layer.opacity > 1)) {
|
|
53368
|
-
errors.push(
|
|
53369
|
-
new TourValidationError(
|
|
53370
|
-
`Step ${index2}, Layer ${layerIndex}: 'opacity' must be between 0 and 1`,
|
|
53371
|
-
`highlightLayers[${layerIndex}].opacity`,
|
|
53372
|
-
layer.opacity
|
|
53373
|
-
)
|
|
53374
|
-
);
|
|
53375
|
-
}
|
|
53376
|
-
if (layer.borderWidth !== void 0 && layer.borderWidth < 0) {
|
|
53377
|
-
errors.push(
|
|
53378
|
-
new TourValidationError(
|
|
53379
|
-
`Step ${index2}, Layer ${layerIndex}: 'borderWidth' must be positive`,
|
|
53380
|
-
`highlightLayers[${layerIndex}].borderWidth`,
|
|
53381
|
-
layer.borderWidth
|
|
53382
|
-
)
|
|
53383
|
-
);
|
|
53384
|
-
}
|
|
53385
|
-
if (!layer.items || layer.items.length === 0) {
|
|
53386
|
-
errors.push(
|
|
53387
|
-
new TourValidationError(
|
|
53388
|
-
`Step ${index2}, Layer ${layerIndex}: 'items' array must not be empty`,
|
|
53389
|
-
`highlightLayers[${layerIndex}].items`,
|
|
53390
|
-
layer.items
|
|
53391
|
-
)
|
|
53392
|
-
);
|
|
53393
|
-
} else {
|
|
53394
|
-
layer.items.forEach((item, itemIndex) => {
|
|
53395
|
-
if (!item.path || !isValidRelativePath(item.path)) {
|
|
53396
|
-
errors.push(
|
|
53397
|
-
new TourValidationError(
|
|
53398
|
-
`Step ${index2}, Layer ${layerIndex}, Item ${itemIndex}: Invalid relative path`,
|
|
53399
|
-
`highlightLayers[${layerIndex}].items[${itemIndex}].path`,
|
|
53400
|
-
item.path
|
|
53401
|
-
)
|
|
53402
|
-
);
|
|
53403
|
-
}
|
|
53404
|
-
if (!item.type || item.type !== "file" && item.type !== "directory") {
|
|
53405
|
-
errors.push(
|
|
53406
|
-
new TourValidationError(
|
|
53407
|
-
`Step ${index2}, Layer ${layerIndex}, Item ${itemIndex}: 'type' must be 'file' or 'directory'`,
|
|
53408
|
-
`highlightLayers[${layerIndex}].items[${itemIndex}].type`,
|
|
53409
|
-
item.type
|
|
53410
|
-
)
|
|
53411
|
-
);
|
|
53412
|
-
}
|
|
53413
|
-
});
|
|
53414
|
-
}
|
|
53415
|
-
});
|
|
53416
|
-
}
|
|
53417
|
-
if (step.highlightFiles) {
|
|
53418
|
-
step.highlightFiles.forEach((filePath, fileIndex) => {
|
|
53419
|
-
if (!isValidRelativePath(filePath)) {
|
|
53420
|
-
errors.push(
|
|
53421
|
-
new TourValidationError(
|
|
53422
|
-
`Step ${index2}, highlightFiles[${fileIndex}]: Must be a relative path (no leading slash)`,
|
|
53423
|
-
`highlightFiles[${fileIndex}]`,
|
|
53424
|
-
filePath
|
|
53425
|
-
)
|
|
53426
|
-
);
|
|
53427
|
-
}
|
|
53428
|
-
});
|
|
53429
|
-
}
|
|
53430
|
-
if (step.interactiveActions) {
|
|
53431
|
-
step.interactiveActions.forEach((action, actionIndex) => {
|
|
53432
|
-
const needsTarget = ["click-file", "hover-directory", "toggle-layer"].includes(action.type);
|
|
53433
|
-
if (needsTarget && !action.target) {
|
|
53434
|
-
errors.push(
|
|
53435
|
-
new TourValidationError(
|
|
53436
|
-
`Step ${index2}, Action ${actionIndex}: '${action.type}' requires a 'target'`,
|
|
53437
|
-
`interactiveActions[${actionIndex}].target`,
|
|
53438
|
-
action.target
|
|
53439
|
-
)
|
|
53440
|
-
);
|
|
53441
|
-
}
|
|
53442
|
-
});
|
|
53443
|
-
}
|
|
53444
|
-
return errors;
|
|
53445
|
-
}
|
|
53446
|
-
function validateTour(tour) {
|
|
53447
|
-
const errors = [];
|
|
53448
|
-
if (!tour.id || typeof tour.id !== "string") {
|
|
53449
|
-
errors.push(new TourValidationError("Missing or invalid 'id'", "id", tour.id));
|
|
53450
|
-
} else if (!/^[a-z0-9-]+$/.test(tour.id)) {
|
|
53451
|
-
errors.push(
|
|
53452
|
-
new TourValidationError("Tour 'id' must be kebab-case (lowercase, numbers, hyphens only)", "id", tour.id)
|
|
53453
|
-
);
|
|
53454
|
-
}
|
|
53455
|
-
if (!tour.title || typeof tour.title !== "string") {
|
|
53456
|
-
errors.push(new TourValidationError("Missing or invalid 'title'", "title", tour.title));
|
|
53457
|
-
}
|
|
53458
|
-
if (!tour.description || typeof tour.description !== "string") {
|
|
53459
|
-
errors.push(new TourValidationError("Missing or invalid 'description'", "description", tour.description));
|
|
53460
|
-
}
|
|
53461
|
-
if (!tour.version || !isValidVersion(tour.version)) {
|
|
53462
|
-
errors.push(
|
|
53463
|
-
new TourValidationError(
|
|
53464
|
-
"Invalid 'version' - must be semantic version (e.g., '1.0.0')",
|
|
53465
|
-
"version",
|
|
53466
|
-
tour.version
|
|
53467
|
-
)
|
|
53468
|
-
);
|
|
53469
|
-
}
|
|
53470
|
-
if (!tour.steps || !Array.isArray(tour.steps) || tour.steps.length === 0) {
|
|
53471
|
-
errors.push(new TourValidationError("'steps' array must contain at least one step", "steps", tour.steps));
|
|
53472
|
-
} else {
|
|
53473
|
-
tour.steps.forEach((step, index2) => {
|
|
53474
|
-
const stepErrors = validateStep(step, index2);
|
|
53475
|
-
errors.push(...stepErrors);
|
|
53476
|
-
});
|
|
53477
|
-
const stepIds = /* @__PURE__ */ new Set();
|
|
53478
|
-
tour.steps.forEach((step, index2) => {
|
|
53479
|
-
if (stepIds.has(step.id)) {
|
|
53480
|
-
errors.push(new TourValidationError(`Duplicate step ID '${step.id}' at index ${index2}`, "steps", step.id));
|
|
53481
|
-
}
|
|
53482
|
-
stepIds.add(step.id);
|
|
53483
|
-
});
|
|
53484
|
-
}
|
|
53485
|
-
if (tour.audience !== void 0 && typeof tour.audience !== "string") {
|
|
53486
|
-
errors.push(
|
|
53487
|
-
new TourValidationError(
|
|
53488
|
-
`Invalid 'audience' - must be a string`,
|
|
53489
|
-
"audience",
|
|
53490
|
-
tour.audience
|
|
53491
|
-
)
|
|
53492
|
-
);
|
|
53493
|
-
}
|
|
53494
|
-
return errors;
|
|
53495
|
-
}
|
|
53496
|
-
function parseTour(jsonString) {
|
|
53497
|
-
try {
|
|
53498
|
-
const parsed = JSON.parse(jsonString);
|
|
53499
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
53500
|
-
return {
|
|
53501
|
-
success: false,
|
|
53502
|
-
errors: [new TourValidationError("Tour JSON must be an object")]
|
|
53503
|
-
};
|
|
53504
|
-
}
|
|
53505
|
-
const errors = validateTour(parsed);
|
|
53506
|
-
if (errors.length > 0) {
|
|
53507
|
-
return {
|
|
53508
|
-
success: false,
|
|
53509
|
-
errors
|
|
53510
|
-
};
|
|
53511
|
-
}
|
|
53512
|
-
return {
|
|
53513
|
-
success: true,
|
|
53514
|
-
tour: parsed
|
|
53515
|
-
};
|
|
53516
|
-
} catch (error) {
|
|
53517
|
-
return {
|
|
53518
|
-
success: false,
|
|
53519
|
-
errors: [
|
|
53520
|
-
new TourValidationError(
|
|
53521
|
-
`Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
53522
|
-
)
|
|
53523
|
-
]
|
|
53524
|
-
};
|
|
53525
|
-
}
|
|
53526
|
-
}
|
|
53527
|
-
function findTourFilePathInFileTree(fileTree) {
|
|
53528
|
-
const tourFiles = fileTree.allFiles.filter((file) => {
|
|
53529
|
-
const path = file.path;
|
|
53530
|
-
return path.endsWith(".tour.json") && !path.includes("/");
|
|
53531
|
-
});
|
|
53532
|
-
tourFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
53533
|
-
const tourFile = tourFiles[0];
|
|
53534
|
-
return tourFile ? tourFile.path : null;
|
|
53535
|
-
}
|
|
53536
53498
|
const GIT_STATUS_COLORS = {
|
|
53537
53499
|
staged: "#22c55e",
|
|
53538
53500
|
// Green
|
|
@@ -54735,7 +54697,7 @@ const CodeCityPanelContent = ({
|
|
|
54735
54697
|
}
|
|
54736
54698
|
)
|
|
54737
54699
|
] }) }),
|
|
54738
|
-
!showTourPlayer &&
|
|
54700
|
+
!showTourPlayer && tourData && /* @__PURE__ */ jsxs(
|
|
54739
54701
|
"button",
|
|
54740
54702
|
{
|
|
54741
54703
|
onClick: () => {
|