worldorbit 2.5.11 → 2.5.13
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/unpkg/worldorbit-core.min.js +5 -5
- package/dist/unpkg/worldorbit-markdown.min.js +20 -20
- package/dist/unpkg/worldorbit-viewer.min.js +29 -29
- package/dist/unpkg/worldorbit.js +38 -15
- package/dist/unpkg/worldorbit.min.js +36 -36
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.d.ts +11 -0
- package/packages/core/dist/atlas-edit.js +210 -0
- package/packages/core/dist/diagnostics.d.ts +10 -0
- package/packages/core/dist/diagnostics.js +109 -0
- package/packages/core/dist/draft-parse.d.ts +3 -0
- package/packages/core/dist/draft-parse.js +642 -0
- package/packages/core/dist/draft.d.ts +15 -0
- package/packages/core/dist/draft.js +343 -0
- package/packages/core/dist/errors.d.ts +7 -0
- package/packages/core/dist/errors.js +16 -0
- package/packages/core/dist/format.d.ts +4 -0
- package/packages/core/dist/format.js +364 -0
- package/packages/core/dist/index.d.ts +28 -0
- package/packages/core/dist/index.js +44 -0
- package/packages/core/dist/load.d.ts +4 -0
- package/packages/core/dist/load.js +130 -0
- package/packages/core/dist/markdown.d.ts +2 -0
- package/packages/core/dist/markdown.js +37 -0
- package/packages/core/dist/normalize.d.ts +2 -0
- package/packages/core/dist/normalize.js +304 -0
- package/packages/core/dist/parse.d.ts +2 -0
- package/packages/core/dist/parse.js +133 -0
- package/packages/core/dist/scene.d.ts +3 -0
- package/packages/core/dist/scene.js +1512 -0
- package/packages/core/dist/schema.d.ts +8 -0
- package/packages/core/dist/schema.js +298 -0
- package/packages/core/dist/tokenize.d.ts +4 -0
- package/packages/core/dist/tokenize.js +68 -0
- package/packages/core/dist/types.d.ts +382 -0
- package/packages/core/dist/types.js +1 -0
- package/packages/core/dist/validate.d.ts +2 -0
- package/packages/core/dist/validate.js +56 -0
- package/packages/editor/dist/editor.js +493 -121
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cloneAtlasDocument, createEmptyAtlasDocument, formatDocument, getAtlasDocumentNode, loadWorldOrbitSourceWithDiagnostics, materializeAtlasDocument, removeAtlasDocumentNode, resolveAtlasDiagnostics, rotatePoint, upgradeDocumentToV2, validateAtlasDocumentWithDiagnostics, } from "@worldorbit/core";
|
|
2
2
|
import { renderWorldOrbitBlock } from "@worldorbit/markdown";
|
|
3
3
|
import { createInteractiveViewer, } from "@worldorbit/viewer";
|
|
4
|
-
import { invertViewerPoint } from "@worldorbit/viewer/viewer-state";
|
|
4
|
+
import { getViewerVisibleBounds, invertViewerPoint } from "@worldorbit/viewer/viewer-state";
|
|
5
5
|
const STYLE_ID = "worldorbit-editor-style";
|
|
6
6
|
const SOURCE_INPUT_DEBOUNCE_MS = 120;
|
|
7
7
|
const PREVIEW_BATCH_DELAY_MS = 16;
|
|
@@ -61,6 +61,96 @@ const OBJECT_UNIT_FIELDS = [
|
|
|
61
61
|
"cycle",
|
|
62
62
|
];
|
|
63
63
|
const OBJECT_NUMBER_FIELDS = ["albedo"];
|
|
64
|
+
const FIELD_HELP = {
|
|
65
|
+
"defaults-view": {
|
|
66
|
+
description: "Sets the default camera projection for the atlas.",
|
|
67
|
+
references: ["Topdown = map-like", "Isometric = angled overview"],
|
|
68
|
+
},
|
|
69
|
+
"defaults-scale": {
|
|
70
|
+
description: "Chooses the overall spacing/style preset used by the renderer.",
|
|
71
|
+
references: ["diagram = tighter", "presentation = roomier"],
|
|
72
|
+
},
|
|
73
|
+
"defaults-units": {
|
|
74
|
+
description: "Stores a document-wide note about the unit style you want to use.",
|
|
75
|
+
references: ["Example: metric", "Example: lore-standard"],
|
|
76
|
+
},
|
|
77
|
+
"viewpoint-projection": {
|
|
78
|
+
description: "Overrides the projection for this saved viewpoint.",
|
|
79
|
+
references: ["Topdown = flat orbital map", "Isometric = angled scene"],
|
|
80
|
+
},
|
|
81
|
+
"viewpoint-zoom": {
|
|
82
|
+
description: "Controls how closely this viewpoint frames the system.",
|
|
83
|
+
references: ["1 = scene fit", "2+ = close-up"],
|
|
84
|
+
},
|
|
85
|
+
"viewpoint-rotation": {
|
|
86
|
+
description: "Rotates the saved camera angle in degrees.",
|
|
87
|
+
references: ["90deg = quarter turn", "180deg = flip"],
|
|
88
|
+
},
|
|
89
|
+
"placement-target": {
|
|
90
|
+
description: "Names the body or reference this object is attached to.",
|
|
91
|
+
references: ["orbit Primary", "surface Homeworld", "at Naar:L4"],
|
|
92
|
+
},
|
|
93
|
+
"placement-free": {
|
|
94
|
+
description: "Stores a free-placement offset or a descriptive label for loose placement.",
|
|
95
|
+
references: ["8au = far from the star", '"outer system" = descriptive note'],
|
|
96
|
+
},
|
|
97
|
+
"placement-distance": {
|
|
98
|
+
description: "Mean orbit distance from the target body.",
|
|
99
|
+
references: ["1 au = Earth-Sun distance", "384400km = Earth-Moon distance"],
|
|
100
|
+
},
|
|
101
|
+
"placement-semiMajor": {
|
|
102
|
+
description: "Semi-major axis of an orbit, used for elliptical orbits.",
|
|
103
|
+
references: ["1 au = Earth-Sun distance", "Use this instead of distance when orbit shape matters"],
|
|
104
|
+
},
|
|
105
|
+
"placement-eccentricity": {
|
|
106
|
+
description: "Controls how stretched the orbit is. Lower is rounder.",
|
|
107
|
+
references: ["0 = circular orbit", "0.1 = mildly elliptical"],
|
|
108
|
+
},
|
|
109
|
+
"placement-period": {
|
|
110
|
+
description: "How long one orbit takes.",
|
|
111
|
+
references: ["1 y = one Earth year", "27.3d = Moon around Earth"],
|
|
112
|
+
},
|
|
113
|
+
"placement-angle": {
|
|
114
|
+
description: "Rotates the orbit ellipse within the scene.",
|
|
115
|
+
references: ["0deg = default orientation", "90deg = quarter turn"],
|
|
116
|
+
},
|
|
117
|
+
"placement-inclination": {
|
|
118
|
+
description: "Tilts the orbit relative to the main orbital plane.",
|
|
119
|
+
references: ["0deg = same plane", "5deg = slight tilt"],
|
|
120
|
+
},
|
|
121
|
+
"placement-phase": {
|
|
122
|
+
description: "Starting position of the object along its orbit.",
|
|
123
|
+
references: ["0deg = start position", "180deg = opposite side"],
|
|
124
|
+
},
|
|
125
|
+
"prop-radius": {
|
|
126
|
+
description: "Visual body size or real-world-inspired radius value.",
|
|
127
|
+
references: ["1re = Earth radius", "1sol = Sun radius"],
|
|
128
|
+
},
|
|
129
|
+
"prop-mass": {
|
|
130
|
+
description: "Optional mass value for the body.",
|
|
131
|
+
references: ["1me = Earth mass", "1sol = Sun mass"],
|
|
132
|
+
},
|
|
133
|
+
"prop-gravity": {
|
|
134
|
+
description: "Surface gravity or a custom gravity marker.",
|
|
135
|
+
references: ["1g = Earth-like gravity", "0.16g = Moon-like gravity"],
|
|
136
|
+
},
|
|
137
|
+
"prop-temperature": {
|
|
138
|
+
description: "Typical temperature or narrative temperature marker.",
|
|
139
|
+
references: ["288K = Earth-like average", "1200K = very hot world"],
|
|
140
|
+
},
|
|
141
|
+
"prop-atmosphere": {
|
|
142
|
+
description: "Short atmosphere descriptor for the object.",
|
|
143
|
+
references: ['"nitrogen-oxygen"', '"methane haze"'],
|
|
144
|
+
},
|
|
145
|
+
"prop-inner": {
|
|
146
|
+
description: "Inner edge for a belt, ring, or broad phenomenon.",
|
|
147
|
+
references: ["120000km = ring inner edge", "2au = belt starts here"],
|
|
148
|
+
},
|
|
149
|
+
"prop-outer": {
|
|
150
|
+
description: "Outer edge for a belt, ring, or broad phenomenon.",
|
|
151
|
+
references: ["190000km = ring outer edge", "3au = belt ends here"],
|
|
152
|
+
},
|
|
153
|
+
};
|
|
64
154
|
export function createWorldOrbitEditor(container, options = {}) {
|
|
65
155
|
ensureBrowserEnvironment(container);
|
|
66
156
|
installEditorStyles();
|
|
@@ -83,6 +173,7 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
83
173
|
let previewTimer = null;
|
|
84
174
|
let lastPreviewSvg = "";
|
|
85
175
|
let lastPreviewMarkup = "";
|
|
176
|
+
const inspectorSectionState = new Map();
|
|
86
177
|
const showTextPane = options.showTextPane ?? true;
|
|
87
178
|
const showInspector = options.showInspector ?? true;
|
|
88
179
|
const showPreview = options.showPreview ?? true;
|
|
@@ -605,6 +696,7 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
605
696
|
if (!inspector) {
|
|
606
697
|
return;
|
|
607
698
|
}
|
|
699
|
+
captureInspectorSectionState(inspector, inspectorSectionState);
|
|
608
700
|
const formState = {
|
|
609
701
|
selection: selection ? { path: { ...selection } } : null,
|
|
610
702
|
system: atlasDocument.system,
|
|
@@ -619,26 +711,32 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
619
711
|
switch (selection.kind) {
|
|
620
712
|
case "system":
|
|
621
713
|
inspector.innerHTML = diagnosticSummary + renderSystemInspector(formState);
|
|
714
|
+
applyInspectorSectionState(inspector, inspectorSectionState);
|
|
622
715
|
decorateInspectorDiagnostics(selection, diagnostics);
|
|
623
716
|
return;
|
|
624
717
|
case "defaults":
|
|
625
718
|
inspector.innerHTML = diagnosticSummary + renderDefaultsInspector(formState);
|
|
719
|
+
applyInspectorSectionState(inspector, inspectorSectionState);
|
|
626
720
|
decorateInspectorDiagnostics(selection, diagnostics);
|
|
627
721
|
return;
|
|
628
722
|
case "metadata":
|
|
629
723
|
inspector.innerHTML = diagnosticSummary + renderMetadataInspector(formState, selection.key ?? "");
|
|
724
|
+
applyInspectorSectionState(inspector, inspectorSectionState);
|
|
630
725
|
decorateInspectorDiagnostics(selection, diagnostics);
|
|
631
726
|
return;
|
|
632
727
|
case "viewpoint":
|
|
633
728
|
inspector.innerHTML = diagnosticSummary + renderViewpointInspector(formState, selection.id ?? "");
|
|
729
|
+
applyInspectorSectionState(inspector, inspectorSectionState);
|
|
634
730
|
decorateInspectorDiagnostics(selection, diagnostics);
|
|
635
731
|
return;
|
|
636
732
|
case "annotation":
|
|
637
733
|
inspector.innerHTML = diagnosticSummary + renderAnnotationInspector(formState, selection.id ?? "");
|
|
734
|
+
applyInspectorSectionState(inspector, inspectorSectionState);
|
|
638
735
|
decorateInspectorDiagnostics(selection, diagnostics);
|
|
639
736
|
return;
|
|
640
737
|
case "object":
|
|
641
738
|
inspector.innerHTML = diagnosticSummary + renderObjectInspector(formState, selection.id ?? "");
|
|
739
|
+
applyInspectorSectionState(inspector, inspectorSectionState);
|
|
642
740
|
decorateInspectorDiagnostics(selection, diagnostics);
|
|
643
741
|
return;
|
|
644
742
|
}
|
|
@@ -907,12 +1005,16 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
907
1005
|
return;
|
|
908
1006
|
}
|
|
909
1007
|
}
|
|
1008
|
+
const details = viewer?.getObjectDetails(objectId) ?? null;
|
|
910
1009
|
dragState = {
|
|
911
1010
|
kind,
|
|
912
1011
|
objectId,
|
|
913
1012
|
pointerId: event.pointerId,
|
|
914
1013
|
startedFrom: createHistoryEntry(),
|
|
915
1014
|
changed: false,
|
|
1015
|
+
orbitRadiusContext: kind === "orbit-radius" && details
|
|
1016
|
+
? createOrbitRadiusDragContext(atlasDocument, viewer.getScene(), details)
|
|
1017
|
+
: null,
|
|
916
1018
|
};
|
|
917
1019
|
handle.setPointerCapture?.(event.pointerId);
|
|
918
1020
|
event.preventDefault();
|
|
@@ -938,7 +1040,7 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
938
1040
|
break;
|
|
939
1041
|
case "orbit-radius":
|
|
940
1042
|
if (details.object.placement?.mode === "orbit" && details.orbit) {
|
|
941
|
-
nextDocument = updateOrbitRadius(atlasDocument, dragState.objectId, details, pointer);
|
|
1043
|
+
nextDocument = updateOrbitRadius(atlasDocument, dragState.objectId, details, pointer, dragState.orbitRadiusContext ?? null);
|
|
942
1044
|
}
|
|
943
1045
|
break;
|
|
944
1046
|
case "at-reference":
|
|
@@ -978,6 +1080,7 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
978
1080
|
if (!dragState || dragState.pointerId !== event.pointerId) {
|
|
979
1081
|
return;
|
|
980
1082
|
}
|
|
1083
|
+
const completedDrag = dragState;
|
|
981
1084
|
if (!dragState.changed) {
|
|
982
1085
|
dragState = null;
|
|
983
1086
|
return;
|
|
@@ -988,6 +1091,9 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
988
1091
|
sourceText = canonicalSource;
|
|
989
1092
|
dragState = null;
|
|
990
1093
|
renderAll();
|
|
1094
|
+
if (completedDrag.kind === "orbit-radius") {
|
|
1095
|
+
maybeFitOrbitResizeInView(completedDrag.objectId);
|
|
1096
|
+
}
|
|
991
1097
|
updateDirtyState();
|
|
992
1098
|
emitSnapshot();
|
|
993
1099
|
}
|
|
@@ -1214,6 +1320,24 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
1214
1320
|
lastPreviewMarkup = nextMarkup;
|
|
1215
1321
|
}
|
|
1216
1322
|
}
|
|
1323
|
+
function maybeFitOrbitResizeInView(objectId) {
|
|
1324
|
+
if (!viewer) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
const details = viewer.getObjectDetails(objectId);
|
|
1328
|
+
if (!details) {
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const visibleBounds = getViewerVisibleBounds(viewer.getScene(), viewer.getState());
|
|
1332
|
+
const margin = 36 / Math.max(viewer.getState().scale, 0.001);
|
|
1333
|
+
const point = details.renderObject;
|
|
1334
|
+
if (point.x < visibleBounds.minX + margin ||
|
|
1335
|
+
point.x > visibleBounds.maxX - margin ||
|
|
1336
|
+
point.y < visibleBounds.minY + margin ||
|
|
1337
|
+
point.y > visibleBounds.maxY - margin) {
|
|
1338
|
+
viewer.fitToSystem();
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1217
1341
|
function shouldIgnoreShortcutEvent(event) {
|
|
1218
1342
|
const target = event.target;
|
|
1219
1343
|
if (!target) {
|
|
@@ -1320,56 +1444,117 @@ function resolveInitialEditorState(options) {
|
|
|
1320
1444
|
};
|
|
1321
1445
|
}
|
|
1322
1446
|
function buildEditorMarkup() {
|
|
1447
|
+
const previewOpen = shouldPreviewSectionBeOpenByDefault();
|
|
1323
1448
|
return `<section class="wo-editor-shell">
|
|
1324
1449
|
<div class="wo-editor-toolbar" data-editor-toolbar></div>
|
|
1325
1450
|
<div class="wo-editor-status" data-editor-status role="status" aria-live="polite"></div>
|
|
1326
1451
|
<div class="wo-editor-main">
|
|
1327
1452
|
<aside class="wo-editor-sidebar" data-editor-pane="sidebar">
|
|
1328
|
-
<div class="wo-editor-panel">
|
|
1329
|
-
|
|
1330
|
-
<div class="wo-editor-outline" data-editor-outline></div>
|
|
1331
|
-
</div>
|
|
1332
|
-
<div class="wo-editor-panel">
|
|
1333
|
-
<h2>Diagnostics</h2>
|
|
1334
|
-
<div class="wo-editor-diagnostics" data-editor-diagnostics></div>
|
|
1335
|
-
</div>
|
|
1453
|
+
<div class="wo-editor-panel">${renderPanelSection("Atlas", "atlas", `<div class="wo-editor-outline" data-editor-outline></div>`)}</div>
|
|
1454
|
+
<div class="wo-editor-panel">${renderPanelSection("Diagnostics", "diagnostics", `<div class="wo-editor-diagnostics" data-editor-diagnostics></div>`)}</div>
|
|
1336
1455
|
</aside>
|
|
1337
1456
|
<div class="wo-editor-stage-panel">
|
|
1338
1457
|
<div class="wo-editor-stage-shell" data-editor-stage-shell>
|
|
1339
1458
|
<div class="wo-editor-stage" data-editor-stage></div>
|
|
1340
1459
|
<div class="wo-editor-overlay" data-editor-overlay></div>
|
|
1341
1460
|
</div>
|
|
1342
|
-
<div class="wo-editor-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1461
|
+
<div class="wo-editor-panel" data-editor-pane="preview">
|
|
1462
|
+
${renderPanelSection("Preview", "preview", `<div class="wo-editor-preview">
|
|
1463
|
+
<div class="wo-editor-preview-card">
|
|
1464
|
+
<h3>Static SVG</h3>
|
|
1465
|
+
<div class="wo-editor-preview-visual" data-editor-preview-visual></div>
|
|
1466
|
+
</div>
|
|
1467
|
+
<div class="wo-editor-preview-card">
|
|
1468
|
+
<h3>Embed Markup</h3>
|
|
1469
|
+
<pre class="wo-editor-preview-markup" data-editor-preview-markup></pre>
|
|
1470
|
+
</div>
|
|
1471
|
+
</div>`, previewOpen)}
|
|
1351
1472
|
</div>
|
|
1352
1473
|
</div>
|
|
1353
|
-
<aside class="wo-editor-panel wo-editor-inspector" data-editor-pane="inspector"
|
|
1474
|
+
<aside class="wo-editor-panel wo-editor-inspector" data-editor-pane="inspector">
|
|
1475
|
+
${renderPanelSection("Inspector", "inspector", `<div data-editor-inspector></div>`)}
|
|
1476
|
+
</aside>
|
|
1354
1477
|
</div>
|
|
1355
1478
|
<div class="wo-editor-panel wo-editor-text-panel" data-editor-pane="text">
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
></div>
|
|
1479
|
+
${renderPanelSection("Source", "source", `<textarea
|
|
1480
|
+
class="wo-editor-source"
|
|
1481
|
+
data-editor-source
|
|
1482
|
+
spellcheck="false"
|
|
1483
|
+
aria-describedby="worldorbit-editor-source-diagnostics"
|
|
1484
|
+
></textarea>
|
|
1485
|
+
<div
|
|
1486
|
+
class="wo-editor-source-diagnostics"
|
|
1487
|
+
id="worldorbit-editor-source-diagnostics"
|
|
1488
|
+
data-editor-source-diagnostics
|
|
1489
|
+
aria-live="polite"
|
|
1490
|
+
></div>`)}
|
|
1369
1491
|
</div>
|
|
1370
1492
|
<div class="wo-editor-live-region" data-editor-live aria-live="polite" aria-atomic="true"></div>
|
|
1371
1493
|
</section>`;
|
|
1372
1494
|
}
|
|
1495
|
+
function renderPanelSection(title, sectionId, content, open = true) {
|
|
1496
|
+
return `<details class="wo-editor-panel-section" data-editor-panel-section="${escapeHtml(sectionId)}"${open ? " open" : ""}>
|
|
1497
|
+
<summary><span>${escapeHtml(title)}</span></summary>
|
|
1498
|
+
<div class="wo-editor-panel-section-body">${content}</div>
|
|
1499
|
+
</details>`;
|
|
1500
|
+
}
|
|
1501
|
+
function renderInspectorSection(formId, sectionId, title, content, open = false) {
|
|
1502
|
+
const stateKey = inspectorSectionStateKey(formId, sectionId);
|
|
1503
|
+
return `<details class="wo-editor-inspector-section" data-editor-form-section="${escapeHtml(sectionId)}" data-editor-form-id="${escapeHtml(formId)}" data-editor-section-state="${escapeHtml(stateKey)}"${open ? " open" : ""}>
|
|
1504
|
+
<summary><span>${escapeHtml(title)}</span></summary>
|
|
1505
|
+
<div class="wo-editor-inspector-section-body">${content}</div>
|
|
1506
|
+
</details>`;
|
|
1507
|
+
}
|
|
1508
|
+
function renderFieldLabel(label, name) {
|
|
1509
|
+
return `<span class="wo-editor-field-label">${escapeHtml(label)}${renderFieldHelp(name)}</span>`;
|
|
1510
|
+
}
|
|
1511
|
+
function renderFieldHelp(name) {
|
|
1512
|
+
const help = FIELD_HELP[name];
|
|
1513
|
+
if (!help) {
|
|
1514
|
+
return "";
|
|
1515
|
+
}
|
|
1516
|
+
return `<details class="wo-editor-field-help">
|
|
1517
|
+
<summary aria-label="Explain ${escapeAttribute(name)}">?</summary>
|
|
1518
|
+
<div class="wo-editor-field-help-card">
|
|
1519
|
+
<p>${escapeHtml(help.description)}</p>
|
|
1520
|
+
${(help.references?.length ?? 0) > 0
|
|
1521
|
+
? `<div class="wo-editor-field-help-chips">${(help.references ?? [])
|
|
1522
|
+
.map((entry) => `<span>${escapeHtml(entry)}</span>`)
|
|
1523
|
+
.join("")}</div>`
|
|
1524
|
+
: ""}
|
|
1525
|
+
</div>
|
|
1526
|
+
</details>`;
|
|
1527
|
+
}
|
|
1528
|
+
function captureInspectorSectionState(container, state) {
|
|
1529
|
+
for (const section of container.querySelectorAll("[data-editor-section-state]")) {
|
|
1530
|
+
const key = section.dataset.editorSectionState;
|
|
1531
|
+
if (!key) {
|
|
1532
|
+
continue;
|
|
1533
|
+
}
|
|
1534
|
+
state.set(key, section.open);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function applyInspectorSectionState(container, state) {
|
|
1538
|
+
for (const section of container.querySelectorAll("[data-editor-section-state]")) {
|
|
1539
|
+
const key = section.dataset.editorSectionState;
|
|
1540
|
+
if (!key || !state.has(key)) {
|
|
1541
|
+
continue;
|
|
1542
|
+
}
|
|
1543
|
+
section.open = state.get(key) === true;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
function inspectorSectionStateKey(formId, sectionId) {
|
|
1547
|
+
return `${formId}:${sectionId}`;
|
|
1548
|
+
}
|
|
1549
|
+
function shouldPreviewSectionBeOpenByDefault() {
|
|
1550
|
+
if (typeof window === "undefined") {
|
|
1551
|
+
return true;
|
|
1552
|
+
}
|
|
1553
|
+
if (typeof window.matchMedia === "function") {
|
|
1554
|
+
return !window.matchMedia("(max-width: 1280px)").matches;
|
|
1555
|
+
}
|
|
1556
|
+
return window.innerWidth > 1280;
|
|
1557
|
+
}
|
|
1373
1558
|
function renderOutlineButton(path, label, activeKey, diagnosticBuckets) {
|
|
1374
1559
|
const key = selectionKey(path);
|
|
1375
1560
|
const bucket = key ? diagnosticBuckets.get(key) : null;
|
|
@@ -1381,36 +1566,36 @@ function renderOutlineButton(path, label, activeKey, diagnosticBuckets) {
|
|
|
1381
1566
|
function renderSystemInspector(formState) {
|
|
1382
1567
|
return `<form class="wo-editor-form" data-editor-form="system">
|
|
1383
1568
|
<h2>System</h2>
|
|
1384
|
-
${renderTextField("System ID", "system-id", formState.system?.id ?? "")}
|
|
1385
|
-
|
|
1569
|
+
${renderInspectorSection("system", "basics", "Basics", `${renderTextField("System ID", "system-id", formState.system?.id ?? "")}
|
|
1570
|
+
${renderTextField("Title", "system-title", formState.system?.title ?? "")}`, true)}
|
|
1386
1571
|
</form>`;
|
|
1387
1572
|
}
|
|
1388
1573
|
function renderDefaultsInspector(formState) {
|
|
1389
1574
|
const defaults = formState.system?.defaults;
|
|
1390
1575
|
return `<form class="wo-editor-form" data-editor-form="defaults">
|
|
1391
1576
|
<h2>Defaults</h2>
|
|
1392
|
-
${renderSelectField("Projection", "defaults-view", [
|
|
1577
|
+
${renderInspectorSection("defaults", "basics", "Basics", `${renderSelectField("Projection", "defaults-view", [
|
|
1393
1578
|
["topdown", "Topdown"],
|
|
1394
1579
|
["isometric", "Isometric"],
|
|
1395
1580
|
], defaults?.view ?? "topdown")}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1581
|
+
${renderTextField("Scale preset", "defaults-scale", defaults?.scale ?? "")}
|
|
1582
|
+
${renderTextField("Units", "defaults-units", defaults?.units ?? "")}
|
|
1583
|
+
${renderSelectField("Render preset", "defaults-preset", [
|
|
1399
1584
|
["", "Document default"],
|
|
1400
1585
|
["diagram", "Diagram"],
|
|
1401
1586
|
["presentation", "Presentation"],
|
|
1402
1587
|
["atlas-card", "Atlas Card"],
|
|
1403
1588
|
["markdown", "Markdown"],
|
|
1404
1589
|
], defaults?.preset ?? "")}
|
|
1405
|
-
|
|
1590
|
+
${renderTextField("Theme", "defaults-theme", defaults?.theme ?? "")}`, true)}
|
|
1406
1591
|
</form>`;
|
|
1407
1592
|
}
|
|
1408
1593
|
function renderMetadataInspector(formState, key) {
|
|
1409
1594
|
const value = formState.system?.atlasMetadata[key] ?? "";
|
|
1410
1595
|
return `<form class="wo-editor-form" data-editor-form="metadata">
|
|
1411
1596
|
<h2>Metadata</h2>
|
|
1412
|
-
${renderTextField("Key", "metadata-key", key)}
|
|
1413
|
-
|
|
1597
|
+
${renderInspectorSection("metadata", "entry", "Entry", `${renderTextField("Key", "metadata-key", key)}
|
|
1598
|
+
${renderTextAreaField("Value", "metadata-value", value)}`, true)}
|
|
1414
1599
|
</form>`;
|
|
1415
1600
|
}
|
|
1416
1601
|
function renderViewpointInspector(formState, id) {
|
|
@@ -1420,38 +1605,38 @@ function renderViewpointInspector(formState, id) {
|
|
|
1420
1605
|
}
|
|
1421
1606
|
return `<form class="wo-editor-form" data-editor-form="viewpoint">
|
|
1422
1607
|
<h2>Viewpoint</h2>
|
|
1423
|
-
${renderTextField("ID", "viewpoint-id", viewpoint.id)}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1608
|
+
${renderInspectorSection("viewpoint", "basics", "Basics", `${renderTextField("ID", "viewpoint-id", viewpoint.id)}
|
|
1609
|
+
${renderTextField("Label", "viewpoint-label", viewpoint.label)}
|
|
1610
|
+
${renderTextAreaField("Summary", "viewpoint-summary", viewpoint.summary)}
|
|
1611
|
+
${renderTextField("Focus object", "viewpoint-focus", viewpoint.focusObjectId ?? "")}
|
|
1612
|
+
${renderTextField("Selected object", "viewpoint-select", viewpoint.selectedObjectId ?? "")}
|
|
1613
|
+
${renderSelectField("Projection", "viewpoint-projection", [
|
|
1429
1614
|
["topdown", "Topdown"],
|
|
1430
1615
|
["isometric", "Isometric"],
|
|
1431
1616
|
], viewpoint.projection)}
|
|
1432
|
-
|
|
1617
|
+
${renderSelectField("Preset", "viewpoint-preset", [
|
|
1433
1618
|
["", "Document default"],
|
|
1434
1619
|
["diagram", "Diagram"],
|
|
1435
1620
|
["presentation", "Presentation"],
|
|
1436
1621
|
["atlas-card", "Atlas Card"],
|
|
1437
1622
|
["markdown", "Markdown"],
|
|
1438
1623
|
], viewpoint.preset ?? "")}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
${renderTextField("Filter query", "filter-query", viewpoint.filter?.query ?? "")}
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1624
|
+
${renderTextField("Zoom", "viewpoint-zoom", viewpoint.zoom === null ? "" : String(viewpoint.zoom))}
|
|
1625
|
+
${renderTextField("Rotation", "viewpoint-rotation", String(viewpoint.rotationDeg))}`, true)}
|
|
1626
|
+
${renderInspectorSection("viewpoint", "layers", "Layers", `<fieldset class="wo-editor-fieldset">
|
|
1627
|
+
<legend>Layers</legend>
|
|
1628
|
+
${renderCheckboxField("Background", "layer-background", viewpoint.layers.background !== false)}
|
|
1629
|
+
${renderCheckboxField("Guides", "layer-guides", viewpoint.layers.guides !== false)}
|
|
1630
|
+
${renderCheckboxField("Orbits back", "layer-orbits-back", viewpoint.layers["orbits-back"] !== false)}
|
|
1631
|
+
${renderCheckboxField("Orbits front", "layer-orbits-front", viewpoint.layers["orbits-front"] !== false)}
|
|
1632
|
+
${renderCheckboxField("Objects", "layer-objects", viewpoint.layers.objects !== false)}
|
|
1633
|
+
${renderCheckboxField("Labels", "layer-labels", viewpoint.layers.labels !== false)}
|
|
1634
|
+
${renderCheckboxField("Metadata", "layer-metadata", viewpoint.layers.metadata !== false)}
|
|
1635
|
+
</fieldset>`)}
|
|
1636
|
+
${renderInspectorSection("viewpoint", "filter", "Filter", `${renderTextField("Filter query", "filter-query", viewpoint.filter?.query ?? "")}
|
|
1637
|
+
${renderTextField("Filter object types", "filter-object-types", viewpoint.filter?.objectTypes.join(" ") ?? "")}
|
|
1638
|
+
${renderTextField("Filter tags", "filter-tags", viewpoint.filter?.tags.join(" ") ?? "")}
|
|
1639
|
+
${renderTextField("Filter groups", "filter-groups", viewpoint.filter?.groupIds.join(" ") ?? "")}`)}
|
|
1455
1640
|
</form>`;
|
|
1456
1641
|
}
|
|
1457
1642
|
function renderAnnotationInspector(formState, id) {
|
|
@@ -1461,12 +1646,12 @@ function renderAnnotationInspector(formState, id) {
|
|
|
1461
1646
|
}
|
|
1462
1647
|
return `<form class="wo-editor-form" data-editor-form="annotation">
|
|
1463
1648
|
<h2>Annotation</h2>
|
|
1464
|
-
${renderTextField("ID", "annotation-id", annotation.id)}
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1649
|
+
${renderInspectorSection("annotation", "entry", "Entry", `${renderTextField("ID", "annotation-id", annotation.id)}
|
|
1650
|
+
${renderTextField("Label", "annotation-label", annotation.label)}
|
|
1651
|
+
${renderTextField("Target object", "annotation-target", annotation.targetObjectId ?? "")}
|
|
1652
|
+
${renderTextField("Source object", "annotation-source", annotation.sourceObjectId ?? "")}
|
|
1653
|
+
${renderTextAreaField("Body", "annotation-body", annotation.body)}
|
|
1654
|
+
${renderTextField("Tags", "annotation-tags", annotation.tags.join(" "))}`, true)}
|
|
1470
1655
|
</form>`;
|
|
1471
1656
|
}
|
|
1472
1657
|
function renderObjectInspector(formState, id) {
|
|
@@ -1485,62 +1670,62 @@ function renderObjectInspector(formState, id) {
|
|
|
1485
1670
|
: "";
|
|
1486
1671
|
return `<form class="wo-editor-form" data-editor-form="object">
|
|
1487
1672
|
<h2>Object</h2>
|
|
1488
|
-
${renderTextField("ID", "object-id", object.id)}
|
|
1489
|
-
|
|
1490
|
-
${renderSelectField("Placement mode", "placement-mode", [
|
|
1673
|
+
${renderInspectorSection("object", "identity", "Identity", `${renderTextField("ID", "object-id", object.id)}
|
|
1674
|
+
${renderSelectField("Type", "object-type", OBJECT_TYPES.map((type) => [type, humanizeIdentifier(type)]), object.type)}`, true)}
|
|
1675
|
+
${renderInspectorSection("object", "placement", "Placement", `${renderSelectField("Placement mode", "placement-mode", [
|
|
1491
1676
|
["", "None"],
|
|
1492
1677
|
["orbit", "Orbit"],
|
|
1493
1678
|
["at", "At"],
|
|
1494
1679
|
["surface", "Surface"],
|
|
1495
1680
|
["free", "Free"],
|
|
1496
1681
|
], placementMode)}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
${renderTextAreaField("Description", "info-description", object.info.description ?? "")}
|
|
1682
|
+
${renderTextField("Placement target", "placement-target", placementTarget)}
|
|
1683
|
+
${renderTextField("Free value", "placement-free", freeValue)}
|
|
1684
|
+
${renderTextField("Distance", "placement-distance", object.placement?.mode === "orbit" && object.placement.distance ? formatUnitValue(object.placement.distance) : "")}
|
|
1685
|
+
${renderTextField("Semi-major", "placement-semiMajor", object.placement?.mode === "orbit" && object.placement.semiMajor ? formatUnitValue(object.placement.semiMajor) : "")}
|
|
1686
|
+
${renderTextField("Eccentricity", "placement-eccentricity", object.placement?.mode === "orbit" && object.placement.eccentricity !== undefined ? String(object.placement.eccentricity) : "")}
|
|
1687
|
+
${renderTextField("Period", "placement-period", object.placement?.mode === "orbit" && object.placement.period ? formatUnitValue(object.placement.period) : "")}
|
|
1688
|
+
${renderTextField("Angle", "placement-angle", object.placement?.mode === "orbit" && object.placement.angle ? formatUnitValue(object.placement.angle) : "")}
|
|
1689
|
+
${renderTextField("Inclination", "placement-inclination", object.placement?.mode === "orbit" && object.placement.inclination ? formatUnitValue(object.placement.inclination) : "")}
|
|
1690
|
+
${renderTextField("Phase", "placement-phase", object.placement?.mode === "orbit" && object.placement.phase ? formatUnitValue(object.placement.phase) : "")}`, true)}
|
|
1691
|
+
${renderInspectorSection("object", "properties", "Properties", `<fieldset class="wo-editor-fieldset">
|
|
1692
|
+
<legend>Properties</legend>
|
|
1693
|
+
${renderTextField("Kind", "prop-kind", readStringProperty(object.properties.kind))}
|
|
1694
|
+
${renderTextField("Class", "prop-class", readStringProperty(object.properties.class))}
|
|
1695
|
+
${renderTextField("Culture", "prop-culture", readStringProperty(object.properties.culture))}
|
|
1696
|
+
${renderTextField("Tags", "prop-tags", readTagsProperty(object.properties.tags))}
|
|
1697
|
+
${renderTextField("Color", "prop-color", readStringProperty(object.properties.color))}
|
|
1698
|
+
${renderTextField("Image", "prop-image", readStringProperty(object.properties.image))}
|
|
1699
|
+
${renderCheckboxField("Hidden", "prop-hidden", object.properties.hidden === true)}
|
|
1700
|
+
${renderTextField("Radius", "prop-radius", readUnitProperty(object.properties.radius))}
|
|
1701
|
+
${renderTextField("Mass", "prop-mass", readUnitProperty(object.properties.mass))}
|
|
1702
|
+
${renderTextField("Density", "prop-density", readUnitProperty(object.properties.density))}
|
|
1703
|
+
${renderTextField("Gravity", "prop-gravity", readUnitProperty(object.properties.gravity))}
|
|
1704
|
+
${renderTextField("Temperature", "prop-temperature", readUnitProperty(object.properties.temperature))}
|
|
1705
|
+
${renderTextField("Albedo", "prop-albedo", readNumberProperty(object.properties.albedo))}
|
|
1706
|
+
${renderTextField("Atmosphere", "prop-atmosphere", readStringProperty(object.properties.atmosphere))}
|
|
1707
|
+
${renderTextField("Inner", "prop-inner", readUnitProperty(object.properties.inner))}
|
|
1708
|
+
${renderTextField("Outer", "prop-outer", readUnitProperty(object.properties.outer))}
|
|
1709
|
+
${renderTextField("On", "prop-on", readStringProperty(object.properties.on))}
|
|
1710
|
+
${renderTextField("Source", "prop-source", readStringProperty(object.properties.source))}
|
|
1711
|
+
${renderTextField("Cycle", "prop-cycle", readUnitProperty(object.properties.cycle))}
|
|
1712
|
+
</fieldset>`)}
|
|
1713
|
+
${renderInspectorSection("object", "info", "Info", `${renderTextAreaField("Description", "info-description", object.info.description ?? "")}`)}
|
|
1529
1714
|
</form>`;
|
|
1530
1715
|
}
|
|
1531
1716
|
function renderTextField(label, name, value) {
|
|
1532
|
-
return `<label class="wo-editor-field"
|
|
1717
|
+
return `<label class="wo-editor-field">${renderFieldLabel(label, name)}<input name="${escapeHtml(name)}" value="${escapeAttribute(value)}" /></label>`;
|
|
1533
1718
|
}
|
|
1534
1719
|
function renderTextAreaField(label, name, value) {
|
|
1535
|
-
return `<label class="wo-editor-field"
|
|
1720
|
+
return `<label class="wo-editor-field">${renderFieldLabel(label, name)}<textarea name="${escapeHtml(name)}">${escapeHtml(value)}</textarea></label>`;
|
|
1536
1721
|
}
|
|
1537
1722
|
function renderSelectField(label, name, options, selectedValue) {
|
|
1538
|
-
return `<label class="wo-editor-field"
|
|
1723
|
+
return `<label class="wo-editor-field">${renderFieldLabel(label, name)}<select name="${escapeHtml(name)}">${options
|
|
1539
1724
|
.map(([value, optionLabel]) => `<option value="${escapeHtml(value)}"${value === selectedValue ? " selected" : ""}>${escapeHtml(optionLabel)}</option>`)
|
|
1540
1725
|
.join("")}</select></label>`;
|
|
1541
1726
|
}
|
|
1542
1727
|
function renderCheckboxField(label, name, checked) {
|
|
1543
|
-
return `<label class="wo-editor-checkbox"><input type="checkbox" name="${escapeHtml(name)}"${checked ? " checked" : ""}
|
|
1728
|
+
return `<label class="wo-editor-checkbox"><input type="checkbox" name="${escapeHtml(name)}"${checked ? " checked" : ""} />${renderFieldLabel(label, name)}</label>`;
|
|
1544
1729
|
}
|
|
1545
1730
|
function createHandleElement(kind, objectId, point, label) {
|
|
1546
1731
|
const element = document.createElement("button");
|
|
@@ -1797,15 +1982,15 @@ function updateOrbitPhase(document, objectId, details, pointer) {
|
|
|
1797
1982
|
};
|
|
1798
1983
|
return next;
|
|
1799
1984
|
}
|
|
1800
|
-
function updateOrbitRadius(document, objectId, details, pointer) {
|
|
1985
|
+
function updateOrbitRadius(document, objectId, details, pointer, dragContext) {
|
|
1801
1986
|
const orbit = details.orbit;
|
|
1802
|
-
if (!orbit || details.object.placement?.mode !== "orbit") {
|
|
1987
|
+
if (!orbit || details.object.placement?.mode !== "orbit" || !dragContext) {
|
|
1803
1988
|
return document;
|
|
1804
1989
|
}
|
|
1805
1990
|
const unrotated = rotatePoint(pointer, { x: orbit.cx, y: orbit.cy }, -orbit.rotationDeg);
|
|
1806
|
-
const
|
|
1807
|
-
const
|
|
1808
|
-
const
|
|
1991
|
+
const nextDisplayedRadius = Math.max(Math.abs(unrotated.x - orbit.cx), 24);
|
|
1992
|
+
const nextBaseRadius = Math.max(nextDisplayedRadius - dragContext.radiusOffsetPx, dragContext.innerPx);
|
|
1993
|
+
const nextMetric = orbitRadiusPxToMetric(nextBaseRadius, dragContext.innerPx, dragContext.stepPx);
|
|
1809
1994
|
const next = cloneAtlasDocument(document);
|
|
1810
1995
|
const object = next.objects.find((entry) => entry.id === objectId);
|
|
1811
1996
|
if (!object || object.placement?.mode !== "orbit") {
|
|
@@ -1816,10 +2001,7 @@ function updateOrbitRadius(document, objectId, details, pointer) {
|
|
|
1816
2001
|
value: 1,
|
|
1817
2002
|
unit: "au",
|
|
1818
2003
|
};
|
|
1819
|
-
const scaled =
|
|
1820
|
-
value: roundNumber(currentValue.value * ratio, 3),
|
|
1821
|
-
unit: currentValue.unit,
|
|
1822
|
-
};
|
|
2004
|
+
const scaled = distanceMetricToUnitValue(Math.max(nextMetric, 0), dragContext.preferredUnit ?? currentValue.unit);
|
|
1823
2005
|
if (object.placement.semiMajor) {
|
|
1824
2006
|
object.placement.semiMajor = scaled;
|
|
1825
2007
|
}
|
|
@@ -1855,6 +2037,28 @@ function updateSurfaceTarget(document, objectId, scene, pointer) {
|
|
|
1855
2037
|
object.placement.target = target.objectId;
|
|
1856
2038
|
return next;
|
|
1857
2039
|
}
|
|
2040
|
+
function createOrbitRadiusDragContext(document, scene, details) {
|
|
2041
|
+
if (details.object.placement?.mode !== "orbit" || !details.orbit || !details.parent) {
|
|
2042
|
+
return null;
|
|
2043
|
+
}
|
|
2044
|
+
const targetId = details.object.placement.target;
|
|
2045
|
+
const siblingCount = document.objects.filter((entry) => entry.placement?.mode === "orbit" &&
|
|
2046
|
+
entry.placement.target === targetId).length;
|
|
2047
|
+
const spacingFactor = layoutPresetSpacingForScene(scene.layoutPreset);
|
|
2048
|
+
const stepPx = (siblingCount > 2 ? 54 : 64) * spacingFactor * scene.scaleModel.orbitDistanceMultiplier;
|
|
2049
|
+
const innerPx = details.parent.radius +
|
|
2050
|
+
56 * spacingFactor * scene.scaleModel.orbitDistanceMultiplier;
|
|
2051
|
+
const currentValue = details.object.placement.semiMajor ?? details.object.placement.distance ?? null;
|
|
2052
|
+
const currentMetric = unitValueToDistanceMetric(currentValue);
|
|
2053
|
+
const displayedRadius = details.orbit.kind === "circle" ? details.orbit.radius ?? 1 : details.orbit.rx ?? 1;
|
|
2054
|
+
const baseRadius = orbitMetricToRadiusPx(currentMetric ?? 0, innerPx, stepPx);
|
|
2055
|
+
return {
|
|
2056
|
+
innerPx,
|
|
2057
|
+
stepPx,
|
|
2058
|
+
radiusOffsetPx: displayedRadius - baseRadius,
|
|
2059
|
+
preferredUnit: currentValue?.unit ?? null,
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
1858
2062
|
function updateFreeDistance(document, objectId, scene, details, pointer) {
|
|
1859
2063
|
if (details.object.placement?.mode !== "free") {
|
|
1860
2064
|
return document;
|
|
@@ -2278,6 +2482,23 @@ function normalizeFreeDistanceUnit(unit) {
|
|
|
2278
2482
|
return null;
|
|
2279
2483
|
}
|
|
2280
2484
|
}
|
|
2485
|
+
function unitValueToDistanceMetric(value) {
|
|
2486
|
+
if (!value) {
|
|
2487
|
+
return null;
|
|
2488
|
+
}
|
|
2489
|
+
switch (value.unit) {
|
|
2490
|
+
case "au":
|
|
2491
|
+
return value.value;
|
|
2492
|
+
case "km":
|
|
2493
|
+
return value.value / AU_IN_KM;
|
|
2494
|
+
case "re":
|
|
2495
|
+
return (value.value * EARTH_RADIUS_IN_KM) / AU_IN_KM;
|
|
2496
|
+
case "sol":
|
|
2497
|
+
return (value.value * SOLAR_RADIUS_IN_KM) / AU_IN_KM;
|
|
2498
|
+
default:
|
|
2499
|
+
return value.value;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2281
2502
|
function distanceMetricToUnitValue(metric, unit) {
|
|
2282
2503
|
switch (unit) {
|
|
2283
2504
|
case "km":
|
|
@@ -2292,6 +2513,28 @@ function distanceMetricToUnitValue(metric, unit) {
|
|
|
2292
2513
|
return { value: roundNumber(metric, 2), unit: null };
|
|
2293
2514
|
}
|
|
2294
2515
|
}
|
|
2516
|
+
function orbitMetricToRadiusPx(metric, innerPx, stepPx) {
|
|
2517
|
+
return innerPx + stepPx * log2(Math.max(metric, 0) + 1);
|
|
2518
|
+
}
|
|
2519
|
+
function orbitRadiusPxToMetric(radiusPx, innerPx, stepPx) {
|
|
2520
|
+
if (radiusPx <= innerPx) {
|
|
2521
|
+
return 0;
|
|
2522
|
+
}
|
|
2523
|
+
return Math.pow(2, (radiusPx - innerPx) / Math.max(stepPx, 0.0001)) - 1;
|
|
2524
|
+
}
|
|
2525
|
+
function layoutPresetSpacingForScene(layoutPreset) {
|
|
2526
|
+
switch (layoutPreset) {
|
|
2527
|
+
case "compact":
|
|
2528
|
+
return 0.84;
|
|
2529
|
+
case "presentation":
|
|
2530
|
+
return 1.2;
|
|
2531
|
+
default:
|
|
2532
|
+
return 1;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
function log2(value) {
|
|
2536
|
+
return Math.log(value) / Math.log(2);
|
|
2537
|
+
}
|
|
2295
2538
|
function escapeHtml(value) {
|
|
2296
2539
|
return value
|
|
2297
2540
|
.replaceAll("&", "&")
|
|
@@ -2391,6 +2634,62 @@ function installEditorStyles() {
|
|
|
2391
2634
|
text-transform: uppercase;
|
|
2392
2635
|
letter-spacing: 0.08em;
|
|
2393
2636
|
}
|
|
2637
|
+
.wo-editor-panel h3 {
|
|
2638
|
+
margin: 0 0 12px;
|
|
2639
|
+
color: rgba(237, 246, 255, 0.82);
|
|
2640
|
+
font: 700 12px/1.2 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2641
|
+
text-transform: uppercase;
|
|
2642
|
+
letter-spacing: 0.08em;
|
|
2643
|
+
}
|
|
2644
|
+
.wo-editor-panel-section,
|
|
2645
|
+
.wo-editor-inspector-section {
|
|
2646
|
+
min-width: 0;
|
|
2647
|
+
}
|
|
2648
|
+
.wo-editor-panel-section > summary,
|
|
2649
|
+
.wo-editor-inspector-section > summary {
|
|
2650
|
+
display: flex;
|
|
2651
|
+
align-items: center;
|
|
2652
|
+
justify-content: space-between;
|
|
2653
|
+
gap: 10px;
|
|
2654
|
+
cursor: pointer;
|
|
2655
|
+
list-style: none;
|
|
2656
|
+
color: #edf6ff;
|
|
2657
|
+
font: 700 14px/1.2 "Segoe UI Variable Display", "Segoe UI", sans-serif;
|
|
2658
|
+
text-transform: uppercase;
|
|
2659
|
+
letter-spacing: 0.08em;
|
|
2660
|
+
}
|
|
2661
|
+
.wo-editor-inspector-section > summary {
|
|
2662
|
+
font: 700 12px/1.2 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2663
|
+
color: rgba(237, 246, 255, 0.9);
|
|
2664
|
+
}
|
|
2665
|
+
.wo-editor-panel-section > summary::-webkit-details-marker,
|
|
2666
|
+
.wo-editor-inspector-section > summary::-webkit-details-marker,
|
|
2667
|
+
.wo-editor-field-help > summary::-webkit-details-marker {
|
|
2668
|
+
display: none;
|
|
2669
|
+
}
|
|
2670
|
+
.wo-editor-panel-section > summary::after,
|
|
2671
|
+
.wo-editor-inspector-section > summary::after {
|
|
2672
|
+
content: "▾";
|
|
2673
|
+
color: rgba(240, 180, 100, 0.86);
|
|
2674
|
+
font-size: 12px;
|
|
2675
|
+
transition: transform 0.18s ease;
|
|
2676
|
+
}
|
|
2677
|
+
.wo-editor-panel-section:not([open]) > summary::after,
|
|
2678
|
+
.wo-editor-inspector-section:not([open]) > summary::after {
|
|
2679
|
+
transform: rotate(-90deg);
|
|
2680
|
+
}
|
|
2681
|
+
.wo-editor-panel-section-body {
|
|
2682
|
+
display: grid;
|
|
2683
|
+
gap: 16px;
|
|
2684
|
+
margin-top: 14px;
|
|
2685
|
+
min-width: 0;
|
|
2686
|
+
}
|
|
2687
|
+
.wo-editor-inspector-section-body {
|
|
2688
|
+
display: grid;
|
|
2689
|
+
gap: 12px;
|
|
2690
|
+
margin-top: 12px;
|
|
2691
|
+
min-width: 0;
|
|
2692
|
+
}
|
|
2394
2693
|
.wo-editor[data-wo-show-inspector="false"] [data-editor-pane="inspector"] { display: none; }
|
|
2395
2694
|
.wo-editor[data-wo-show-text-pane="false"] [data-editor-pane="text"] { display: none; }
|
|
2396
2695
|
.wo-editor[data-wo-show-preview="false"] [data-editor-pane="preview"] { display: none; }
|
|
@@ -2519,8 +2818,23 @@ function installEditorStyles() {
|
|
|
2519
2818
|
margin-bottom: 14px;
|
|
2520
2819
|
}
|
|
2521
2820
|
.wo-editor-form { display: grid; gap: 12px; min-width: 0; }
|
|
2821
|
+
.wo-editor-inspector-section {
|
|
2822
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
2823
|
+
border-radius: 18px;
|
|
2824
|
+
padding: 14px;
|
|
2825
|
+
background: rgba(255,255,255,0.02);
|
|
2826
|
+
}
|
|
2522
2827
|
.wo-editor-field { display: grid; gap: 6px; }
|
|
2523
|
-
.wo-editor-field
|
|
2828
|
+
.wo-editor-field-label,
|
|
2829
|
+
.wo-editor-fieldset legend {
|
|
2830
|
+
display: flex;
|
|
2831
|
+
align-items: center;
|
|
2832
|
+
justify-content: space-between;
|
|
2833
|
+
gap: 10px;
|
|
2834
|
+
}
|
|
2835
|
+
.wo-editor-field-label,
|
|
2836
|
+
.wo-editor-checkbox .wo-editor-field-label,
|
|
2837
|
+
.wo-editor-fieldset legend {
|
|
2524
2838
|
color: rgba(237,246,255,0.72);
|
|
2525
2839
|
font: 600 11px/1.2 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2526
2840
|
text-transform: uppercase;
|
|
@@ -2573,11 +2887,69 @@ function installEditorStyles() {
|
|
|
2573
2887
|
.wo-editor-checkbox {
|
|
2574
2888
|
display: flex;
|
|
2575
2889
|
gap: 10px;
|
|
2576
|
-
align-items:
|
|
2890
|
+
align-items: flex-start;
|
|
2577
2891
|
color: #edf6ff;
|
|
2578
2892
|
font: 500 13px/1.4 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2579
2893
|
}
|
|
2894
|
+
.wo-editor-checkbox input {
|
|
2895
|
+
margin-top: 2px;
|
|
2896
|
+
}
|
|
2897
|
+
.wo-editor-field-help {
|
|
2898
|
+
position: relative;
|
|
2899
|
+
flex: 0 0 auto;
|
|
2900
|
+
}
|
|
2901
|
+
.wo-editor-field-help > summary {
|
|
2902
|
+
display: inline-flex;
|
|
2903
|
+
align-items: center;
|
|
2904
|
+
justify-content: center;
|
|
2905
|
+
width: 20px;
|
|
2906
|
+
height: 20px;
|
|
2907
|
+
border-radius: 999px;
|
|
2908
|
+
border: 1px solid rgba(240, 180, 100, 0.28);
|
|
2909
|
+
background: rgba(240, 180, 100, 0.12);
|
|
2910
|
+
color: #ffdda9;
|
|
2911
|
+
cursor: pointer;
|
|
2912
|
+
font: 700 11px/1 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2913
|
+
list-style: none;
|
|
2914
|
+
}
|
|
2915
|
+
.wo-editor-field-help-card {
|
|
2916
|
+
display: grid;
|
|
2917
|
+
gap: 8px;
|
|
2918
|
+
margin-top: 8px;
|
|
2919
|
+
padding: 10px 12px;
|
|
2920
|
+
border-radius: 14px;
|
|
2921
|
+
border: 1px solid rgba(240, 180, 100, 0.2);
|
|
2922
|
+
background: rgba(12, 26, 39, 0.92);
|
|
2923
|
+
color: rgba(237, 246, 255, 0.86);
|
|
2924
|
+
text-transform: none;
|
|
2925
|
+
letter-spacing: normal;
|
|
2926
|
+
font: 500 12px/1.45 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2927
|
+
}
|
|
2928
|
+
.wo-editor-field-help-card p {
|
|
2929
|
+
margin: 0;
|
|
2930
|
+
}
|
|
2931
|
+
.wo-editor-field-help-chips {
|
|
2932
|
+
display: flex;
|
|
2933
|
+
flex-wrap: wrap;
|
|
2934
|
+
gap: 6px;
|
|
2935
|
+
}
|
|
2936
|
+
.wo-editor-field-help-chips span {
|
|
2937
|
+
border-radius: 999px;
|
|
2938
|
+
padding: 4px 8px;
|
|
2939
|
+
background: rgba(255,255,255,0.06);
|
|
2940
|
+
color: #edf6ff;
|
|
2941
|
+
font: 600 11px/1.3 "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
2942
|
+
text-transform: none;
|
|
2943
|
+
letter-spacing: normal;
|
|
2944
|
+
}
|
|
2580
2945
|
.wo-editor-preview { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
2946
|
+
.wo-editor-preview-card {
|
|
2947
|
+
border-radius: 18px;
|
|
2948
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
2949
|
+
background: rgba(255,255,255,0.03);
|
|
2950
|
+
padding: 14px;
|
|
2951
|
+
min-width: 0;
|
|
2952
|
+
}
|
|
2581
2953
|
.wo-editor-preview-visual {
|
|
2582
2954
|
min-height: 240px;
|
|
2583
2955
|
overflow: auto;
|