feat: add direct edit handles behind directEdit flag
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>
This commit is contained in:
148
workbench/client/probe/ol-ext-transform/probe.css
Normal file
148
workbench/client/probe/ol-ext-transform/probe.css
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user