Steps 1-3 of the main map road interval editor. EditSession keeps the command stack, undo/redo and previewSeq arbitration as pure logic with no OpenLayers reference, so all of it is unit-tested in node. Pointer displacement converts to meters through EPSG:4326 and spherical distance: treating a 3857 delta as meters desyncs the geometry from the cursor by 1/cos(latitude). Handle drags project onto the axis the manifest declares and clamp to its range, so the client never writes a coordinate into a road polygon. All of it sits behind a directEdit flag that defaults to off. With the flag off the workbench requests no manifest, creates no extra source and registers no interaction, so behaviour matches main. The ol-ext probe passed its three gates but is not adopted for road handles. Transform translates by the raw pointer delta, so a handle detaches from its clamped constraint value: a drag reading -24.1 m produced a draft of -5.4 m. Production needs the handle position derived from the constraint instead, which means owning the position update, so native OL PointerInteraction will carry the drag. ol-ext stays out of package.json; the probe is kept as a manual harness. Reserve handles are unreachable with the current solver, recorded in research/ rather than worked around. Also names the dead backend when an API response is empty, instead of surfacing "Unexpected end of JSON input" from response.json(). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
149 lines
2.4 KiB
CSS
149 lines
2.4 KiB
CSS
/* Probe-only styles. Deliberately not sharing the workbench stylesheet, so the
|
|
whole probe can be deleted in one directory. */
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
margin: 0;
|
|
font:
|
|
14px/1.5 system-ui,
|
|
-apple-system,
|
|
'Segoe UI',
|
|
sans-serif;
|
|
color: #1b2426;
|
|
background: #f2f4f3;
|
|
}
|
|
.probe-nav {
|
|
display: flex;
|
|
gap: 16px;
|
|
align-items: center;
|
|
padding: 10px 16px;
|
|
background: #1b2426;
|
|
color: #f2f4f3;
|
|
}
|
|
.probe-nav span {
|
|
color: #9db0b3;
|
|
font-size: 13px;
|
|
}
|
|
.probe-nav button {
|
|
margin-left: auto;
|
|
}
|
|
button {
|
|
padding: 6px 12px;
|
|
border: 1px solid #4a5a5d;
|
|
border-radius: 6px;
|
|
background: #f2f4f3;
|
|
cursor: pointer;
|
|
font: inherit;
|
|
}
|
|
.probe {
|
|
display: grid;
|
|
grid-template-columns: 1fr 340px;
|
|
height: calc(100vh - 45px);
|
|
}
|
|
.probe-map {
|
|
height: 100%;
|
|
background: #dfe4e2;
|
|
}
|
|
.probe-panel {
|
|
padding: 16px;
|
|
overflow-y: auto;
|
|
background: #fff;
|
|
border-left: 1px solid #d3dad8;
|
|
}
|
|
.probe-panel h1 {
|
|
margin: 0 0 4px;
|
|
font-size: 16px;
|
|
}
|
|
.probe-panel p {
|
|
margin: 0 0 12px;
|
|
color: #59696c;
|
|
}
|
|
.probe-panel dt {
|
|
margin-top: 12px;
|
|
font-weight: 600;
|
|
}
|
|
.probe-panel dd {
|
|
margin: 4px 0 0;
|
|
color: #35474a;
|
|
}
|
|
.probe-panel ul {
|
|
margin: 16px 0 0;
|
|
padding-left: 18px;
|
|
color: #59696c;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.probe-panel h2 {
|
|
margin: 0 0 6px;
|
|
font-size: 13px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: #59696c;
|
|
}
|
|
.probe-panel section {
|
|
margin-bottom: 20px;
|
|
}
|
|
.probe-panel ol {
|
|
margin: 0 0 8px;
|
|
padding-left: 20px;
|
|
}
|
|
.probe-panel ol li {
|
|
margin-bottom: 4px;
|
|
}
|
|
.probe-howto {
|
|
padding: 12px;
|
|
background: #eef4f2;
|
|
border-left: 3px solid #296956;
|
|
border-radius: 4px;
|
|
}
|
|
.probe-howto p,
|
|
.probe-ask p {
|
|
margin: 8px 0 0;
|
|
font-size: 13px;
|
|
}
|
|
.probe-live {
|
|
padding: 12px;
|
|
background: #1b2426;
|
|
border-radius: 6px;
|
|
}
|
|
.probe-live h2,
|
|
.probe-live p {
|
|
color: #9db0b3;
|
|
}
|
|
.probe-big {
|
|
display: block;
|
|
margin: 2px 0 6px;
|
|
font-size: 30px;
|
|
font-variant-numeric: tabular-nums;
|
|
color: #4ad2f0;
|
|
}
|
|
.probe-ask {
|
|
padding: 12px;
|
|
background: #fdf6e8;
|
|
border-left: 3px solid #d49318;
|
|
border-radius: 4px;
|
|
}
|
|
.probe-empty {
|
|
padding: 24px;
|
|
}
|
|
.probe-error {
|
|
padding: 24px;
|
|
max-width: 900px;
|
|
}
|
|
.probe-error h1 {
|
|
margin: 0 0 4px;
|
|
font-size: 18px;
|
|
color: #bf3b2e;
|
|
}
|
|
.probe-error pre {
|
|
padding: 12px;
|
|
overflow-x: auto;
|
|
background: #1b2426;
|
|
color: #f2f4f3;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
}
|