mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
An ordinary collapsible GEV panel between CCTV and Context, starting collapsed with the Mapillary mark in its strip. Body: a gated empty state when no client token is present, plain-English query box (ASK becomes STOP while running), streamed result chips, imagery filters with a colour legend, and the embedded viewer whose expanded mode is a focus-trapped dialog. All wording lives in a pure presentation module. Co-Authored-By: Claude Fable 5.1 <[email protected]>
210 lines
15 KiB
HTML
210 lines
15 KiB
HTML
<div id="left-panel-stack">
|
||
<!-- Data Layer Toggle Panel -->
|
||
<div id="data-panel" class="panel-collapsible collapsed active" data-panel-id="data-panel">
|
||
<div class="panel-glow"></div>
|
||
<div class="data-panel-inner">
|
||
<div class="panel-header">
|
||
<span class="panel-title">DATA LAYERS</span>
|
||
<span class="panel-divider"></span>
|
||
<button class="panel-collapse-btn" data-collapse-target="data-panel" title="Collapse panel">+</button>
|
||
</div>
|
||
<div id="data-toggles" class="data-toggle-list"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CCTV Coverage Panel -->
|
||
<div id="cctv-panel" class="panel-collapsible collapsed" data-panel-id="cctv-panel">
|
||
<div class="panel-glow"></div>
|
||
<div class="cctv-panel-inner">
|
||
<div class="panel-header">
|
||
<span class="panel-title">CCTV</span>
|
||
<span class="panel-divider"></span>
|
||
<button class="panel-collapse-btn" data-collapse-target="cctv-panel" title="Collapse panel">+</button>
|
||
</div>
|
||
<div id="cctv-frame-wrap" class="cctv-frame-wrap">
|
||
<img id="cctv-frame" alt="CCTV feed frame" />
|
||
</div>
|
||
<div id="cctv-source-badge" role="status" aria-live="polite">SOURCE · UNKNOWN</div>
|
||
<div id="cctv-meta">Enable CCTV to load camera intersections</div>
|
||
<div class="cctv-controls">
|
||
<button id="cctv-enable-btn" class="scene-btn">CCTV OFF</button>
|
||
<button id="cctv-nearest-btn" class="scene-btn">NEAREST</button>
|
||
</div>
|
||
<div class="cctv-controls">
|
||
<button id="cctv-prev-btn" class="scene-btn">PREV</button>
|
||
<select id="cctv-camera-select" aria-label="CCTV camera"></select>
|
||
<button id="cctv-next-btn" class="scene-btn">NEXT</button>
|
||
</div>
|
||
<div class="cctv-controls">
|
||
<button id="cctv-focus-btn" class="scene-btn">FOCUS</button>
|
||
<button id="cctv-coverage-btn" class="scene-btn">COVERAGE OFF</button>
|
||
<button id="cctv-auto-hop-btn" class="scene-btn">AUTO HOP OFF</button>
|
||
</div>
|
||
<div class="cctv-controls">
|
||
<button id="cctv-projection-btn" class="scene-btn">PROJECTION ON</button>
|
||
<span id="cctv-quality-chip">CAL · --</span>
|
||
</div>
|
||
<div class="cctv-calibration-block">
|
||
<div class="cctv-calibration-header">
|
||
<div class="cctv-summary-label">CALIBRATION</div>
|
||
<button id="cctv-adjust-btn" class="scene-btn" title="Drag the camera in the world: rings rotate, arrows move, handles set range/FOV">ADJUST</button>
|
||
</div>
|
||
<div id="cctv-cal-readout" class="cctv-cal-readout" aria-label="Camera pose — click a value to type">
|
||
<button class="cctv-cal-value" data-cal-field="heading" title="Heading (compass °) — click to type">HDG --</button>
|
||
<button class="cctv-cal-value" data-cal-field="pitch" title="Pitch (° up/down) — click to type">PITCH --</button>
|
||
<button class="cctv-cal-value" data-cal-field="fov" title="Horizontal FOV (°) — click to type">FOV --</button>
|
||
<button class="cctv-cal-value" data-cal-field="range" title="Range / monitor-plane distance (m) — click to type">RANGE --</button>
|
||
<button class="cctv-cal-value" data-cal-field="height" title="Mount height above ground (m) — click to type">HGT --</button>
|
||
<button class="cctv-cal-value" data-cal-field="north" title="North offset from catalog position (m) — click to type">ΔN --</button>
|
||
<button class="cctv-cal-value" data-cal-field="east" title="East offset from catalog position (m) — click to type">ΔE --</button>
|
||
</div>
|
||
<div class="cctv-controls cctv-calibration-actions">
|
||
<button id="cctv-calib-save-btn" class="scene-btn">SAVE CAL</button>
|
||
<button id="cctv-calib-reset-btn" class="scene-btn">RESET CAL</button>
|
||
</div>
|
||
</div>
|
||
<div class="cctv-summary-label">SCENE SUMMARY</div>
|
||
<div id="cctv-summary">Enable CCTV to start camera-linked intelligence summaries.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Street Level (Mapillary) Panel — moved into #right-context-rail at
|
||
runtime next to CCTV (see PanelLayoutController). -->
|
||
<div id="mapillary-panel" class="panel-collapsible collapsed" data-panel-id="mapillary-panel">
|
||
<div class="panel-glow"></div>
|
||
<div class="mapillary-panel-inner">
|
||
<div class="panel-header">
|
||
<!-- Mapillary mark: path from the MapillaryJS attribution component
|
||
(mapillary-js, MIT, © Mapillary). Mapillary is a trademark of
|
||
Meta Platforms, Inc.; it is used here to identify the data source. -->
|
||
<svg class="mly-mark" viewBox="0 0 13.5 13.8" aria-hidden="true" focusable="false"><path fill="currentColor" d="M6.38154274 9.6505067C6.14007412 9.52786404 6.08124006 9.31709453 6.21044037 9.08865565 6.27614941 8.97247561 6.41859234 8.74074422 6.53468168 8.5539822 6.69432724 8.29714786 6.92701434 8.29637588 7.05835866 8.37253362 7.18970298 8.44869135 9.04853604 9.42087063 9.16874871 9.48670656 9.4525926 9.64215711 9.87118629 9.28623741 9.68342251 8.97441326 9.59375332 8.82549731 8.8103938 7.4044783 8.5614978 6.93610438 8.44825156 6.72299696 8.47921005 6.53132251 8.731647 6.40377463 8.85656436 6.3406581 9.08004239 6.20890798 9.27394762 6.09190586 9.47189219 5.9724664 9.7353488 6.06223885 9.84245555 6.24022621 9.94956229 6.41821357 13.1209182 12.2294019 13.2221517 12.4098169 13.4231294 12.7679928 13.0322853 13.1511137 12.662949 12.953094 12.4781436 12.8540105 6.62301136 9.77314936 6.38154274 9.6505067zM.200146062 6.40081205C-.111554282 6.23274106-.0545442328 5.79604052.338782648 5.68466036.672030083 5.59029317 3.37820647 4.6882634 4.19715115 4.4149007 4.34479443 4.36561757 4.46005809 4.25228232 4.50965757 4.1075867 4.78858853 3.29386671 5.72024556.575961334 5.82468911.27126979 5.9477048-.087601979 6.39304077-.0889184867 6.57454671.258502251 6.63901566.381902346 9.08940484 4.79813543 9.17465946 4.98547051 9.25991408 5.17280559 9.20498731 5.38031434 9.01176406 5.50000515 8.8185408 5.61969596 8.50343522 5.79872065 8.3936507 5.86654323 8.19489463 5.98933057 8.00439135 5.90384324 7.91365501 5.71364816 7.82291866 5.52345307 7.12387828 4.29626886 6.83882952 3.77527795 6.69634941 3.51486341 6.2671132 3.41492796 6.12283721 3.83582159 6.01848488 4.14024669 5.77526264 4.84979439 5.64864557 5.219172 5.60020375 5.3604904 5.47741944 5.48212554 5.33398124 5.52937001 4.9780163 5.64661478 4.30162944 5.86939744 3.90672375 5.99946818 3.62491469 6.0922881 3.48793523 6.52150257 3.86841776 6.70224674 3.94789525 6.74000167 5.66097153 7.65404391 5.83772054 7.73764558 6.01446954 7.82124724 6.11275281 8.06257945 6.00925316 8.23355004 5.8680804 8.46675268 5.68734796 8.76272052 5.6217862 8.85880815 5.50815838 9.02534163 5.28495077 9.08080286 5.09748996 8.98251076 4.91002915 8.88421866.311522289 6.46086689.200146062 6.40081205z"/></svg>
|
||
<span class="panel-title">STREET LEVEL</span>
|
||
<span class="panel-divider"></span>
|
||
<span id="mly-status" class="mly-status" role="status" aria-live="polite">OFF</span>
|
||
<button class="panel-collapse-btn" data-collapse-target="mapillary-panel" title="Expand panel">◀</button>
|
||
</div>
|
||
<div id="mly-body" class="mly-body">
|
||
<div id="mly-keyless" class="mly-keyless" hidden>
|
||
<p class="mly-keyless-text">Street Level needs a free Mapillary client token (<code>MAPILLARY_CLIENT_TOKEN</code>). Coverage, photos and queries stay off until one is added.</p>
|
||
<button id="mly-keyless-btn" class="scene-btn" type="button">ADD KEY IN POWER UP</button>
|
||
</div>
|
||
<fieldset id="mly-controls" class="mly-controls">
|
||
<div class="cctv-controls">
|
||
<button id="mly-enable-btn" class="scene-btn" type="button" aria-pressed="false" title="Turn the Street Level layer on or off">STREET LEVEL OFF</button>
|
||
<button id="mly-look-btn" class="scene-btn" type="button" title="Open the nearest Mapillary photo to the view centre">OPEN NEAREST PHOTO</button>
|
||
</div>
|
||
<form id="mly-query-form" class="mly-query" autocomplete="off">
|
||
<label for="mly-query-input" class="cctv-summary-label">ASK IN PLAIN ENGLISH</label>
|
||
<div class="mly-query-row">
|
||
<input id="mly-query-input" type="text" maxlength="600" spellcheck="false" placeholder="Ask about objects, signs or a place" aria-label="Ask about objects, signs or a place" />
|
||
<button id="mly-query-run" class="scene-btn mly-ask" type="submit">ASK</button>
|
||
</div>
|
||
<p id="mly-ai-hint" class="mly-hint">Objects, traffic signs, coverage or a street view of any place. Follow-ups refine the last answer.</p>
|
||
<div class="mly-suggestions" role="group" aria-label="Example queries">
|
||
<button type="button" class="mly-suggestion" data-mly-suggestion="show me all fire hydrants in Sacramento">Hydrants · Sacramento</button>
|
||
<button type="button" class="mly-suggestion" data-mly-suggestion="stop signs in downtown Detroit">Stop signs · Detroit</button>
|
||
<button type="button" class="mly-suggestion" data-mly-suggestion="cctv cameras in London">CCTV cameras · London</button>
|
||
<button type="button" class="mly-suggestion" data-mly-suggestion="show me a 360 street view here">360° view · here</button>
|
||
</div>
|
||
</form>
|
||
<div id="mly-answer" class="mly-answer" role="status" aria-live="polite"></div>
|
||
<div id="mly-error" class="mly-error" role="alert" hidden><span aria-hidden="true">⚠</span> <span id="mly-error-text"></span></div>
|
||
<div id="mly-progress" class="mly-progress" hidden>
|
||
<div id="mly-progress-fill" class="mly-progress-fill"></div>
|
||
<span id="mly-progress-label" class="mly-progress-label"></span>
|
||
</div>
|
||
<div id="mly-results" class="mly-results" hidden>
|
||
<div id="mly-result-chips" class="mly-chips"></div>
|
||
<div class="cctv-controls">
|
||
<button id="mly-frame-btn" class="scene-btn" type="button" title="Fly the camera to the result area">ZOOM TO RESULTS</button>
|
||
<button id="mly-clear-btn" class="scene-btn" type="button" title="Remove the results from the globe">CLEAR</button>
|
||
</div>
|
||
</div>
|
||
<div class="mly-filters" role="group" aria-label="Imagery filters">
|
||
<span class="cctv-summary-label">IMAGERY</span>
|
||
<div class="mly-seg" role="radiogroup" aria-label="Panorama filter">
|
||
<button type="button" class="mly-seg-btn is-active" data-mly-pano="all" role="radio" aria-checked="true">ALL</button>
|
||
<button type="button" class="mly-seg-btn" data-mly-pano="pano" role="radio" aria-checked="false">360°</button>
|
||
<button type="button" class="mly-seg-btn" data-mly-pano="flat" role="radio" aria-checked="false">FLAT</button>
|
||
</div>
|
||
<label class="cctv-summary-label" for="mly-since">SINCE</label>
|
||
<select id="mly-since" class="mly-select" aria-label="Show imagery captured since">
|
||
<option value="0">any date</option>
|
||
<option value="365">last year</option>
|
||
<option value="730">2 years</option>
|
||
<option value="1826">5 years</option>
|
||
<option value="year:2024">2024</option>
|
||
<option value="year:2022">2022</option>
|
||
<option value="year:2020">2020</option>
|
||
</select>
|
||
</div>
|
||
<ul id="mly-legend" class="mly-legend" aria-label="Coverage colours"></ul>
|
||
<div class="cctv-controls">
|
||
<button id="mly-follow-btn" class="scene-btn" type="button" aria-pressed="false" title="Move the globe camera wherever the street-level view looks">CAMERA FOLLOWS VIEW</button>
|
||
</div>
|
||
<div id="mly-viewer-wrap" class="mly-viewer-wrap" hidden>
|
||
<div class="mly-viewer-tools">
|
||
<button id="mly-viewer-expand" class="scene-btn" type="button" aria-pressed="false" title="Expand the street-level view (Esc shrinks it)"><span class="mly-btn-icon" aria-hidden="true">⤢</span><span class="mly-btn-text">EXPAND</span></button>
|
||
<div class="mly-seg" role="radiogroup" aria-label="Image fit">
|
||
<button type="button" class="mly-seg-btn is-active" data-mly-render="letterbox" role="radio" aria-checked="true" title="Show the whole image">FIT</button>
|
||
<button type="button" class="mly-seg-btn" data-mly-render="fill" role="radio" aria-checked="false" title="Fill the frame (cropped)">FILL</button>
|
||
</div>
|
||
</div>
|
||
<div class="mly-viewer-tools mly-viewer-tools-right">
|
||
<button id="mly-viewer-close" class="mly-viewer-x" type="button" title="Close the image and deselect it on the map" aria-label="Close the street-level image">×</button>
|
||
</div>
|
||
<div id="mly-viewer-placeholder" class="mly-viewer-placeholder" hidden></div>
|
||
<div id="mly-viewer" class="mly-viewer" aria-label="Mapillary street-level viewer"></div>
|
||
<div id="mly-image-meta" class="mly-image-meta">
|
||
<span id="mly-image-by" class="mly-image-by"></span>
|
||
<span class="mly-image-right">
|
||
<span id="mly-image-when" class="mly-image-when"></span>
|
||
<a id="mly-image-link" class="mly-image-link" href="https://www.mapillary.com/app/" target="_blank" rel="noopener noreferrer" title="Open this image on mapillary.com">MAPILLARY ↗</a>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div id="mly-coverage-meta" class="mly-meta"></div>
|
||
</fieldset>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Scene Director Panel -->
|
||
<div id="scene-panel" class="panel-collapsible collapsed" data-panel-id="scene-panel">
|
||
<div class="panel-glow"></div>
|
||
<div class="scene-panel-inner">
|
||
<div class="panel-header">
|
||
<span class="panel-title">SCENES</span>
|
||
<span class="panel-divider"></span>
|
||
<button class="panel-collapse-btn" data-collapse-target="scene-panel" title="Collapse panel">+</button>
|
||
</div>
|
||
<div class="scene-controls">
|
||
<select id="scene-select" aria-label="Scene recipe"></select>
|
||
<button id="scene-new-btn" class="scene-btn">NEW</button>
|
||
<button id="scene-delete-btn" class="scene-btn scene-btn-danger">DEL</button>
|
||
</div>
|
||
<div class="scene-controls">
|
||
<button id="scene-capture-btn" class="scene-btn">CAPTURE SHOT</button>
|
||
<button id="scene-update-shot-btn" class="scene-btn">UPDATE SHOT</button>
|
||
</div>
|
||
<div id="scene-shot-list" class="scene-shot-list"></div>
|
||
<div class="scene-controls">
|
||
<button id="scene-start-btn" class="scene-btn">START</button>
|
||
<button id="scene-stop-btn" class="scene-btn scene-btn-danger">STOP</button>
|
||
<button id="scene-next-btn" class="scene-btn">NEXT</button>
|
||
</div>
|
||
<div class="scene-controls">
|
||
<button id="scene-export-btn" class="scene-btn">EXPORT PRESETS</button>
|
||
<button id="scene-import-btn" class="scene-btn">IMPORT</button>
|
||
<button id="scene-download-btn" class="scene-btn">RUN LOG</button>
|
||
<input type="file" id="scene-import-file" accept="application/json,.json" hidden />
|
||
</div>
|
||
<div class="scene-progress">
|
||
<div id="scene-progress-fill">0%</div>
|
||
</div>
|
||
<div id="scene-status">Ready</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|