mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
Merge main into the Utilities panel
This commit is contained in:
commit
f38961ef1e
17 files changed
+161
-28
No files matched your search
@@ -40,7 +40,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: OS, Node version, browser
|
label: OS, Node version, browser
|
||||||
description: Include the versions you can find. Write "unknown" for anything unavailable.
|
description: Include the versions you can find. Write "unknown" for anything unavailable.
|
||||||
placeholder: "Windows 11, Node 24.14.0, Chrome 151"
|
placeholder: "Windows 11, Node 24.22.2, Chrome 151"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node: [24.14.0, 26.x]
|
node: [24.22.2, 26.x]
|
||||||
env:
|
env:
|
||||||
PUPPETEER_SKIP_DOWNLOAD: '1'
|
PUPPETEER_SKIP_DOWNLOAD: '1'
|
||||||
GEV_REQUIRE_ALLOCATION_GATE: ${{ matrix.node == '24.14.0' && '1' || '0' }}
|
GEV_REQUIRE_ALLOCATION_GATE: ${{ matrix.node == '24.22.2' && '1' || '0' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out source
|
- name: Check out source
|
||||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 24.14.0
|
node-version: 24.22.2
|
||||||
cache: npm
|
cache: npm
|
||||||
|
|
||||||
- name: Install locked dependencies and headless Chrome
|
- name: Install locked dependencies and headless Chrome
|
||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
- name: Use Node.js
|
- name: Use Node.js
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 24.14.0
|
node-version: 24.22.2
|
||||||
cache: npm
|
cache: npm
|
||||||
|
|
||||||
- name: Run the Pinokio install path
|
- name: Run the Pinokio install path
|
||||||
|
|||||||
+24
-3
@@ -4,13 +4,15 @@ Thanks for being here. God's Eye View is an open foundation for live spatial int
|
|||||||
|
|
||||||
## Getting set up
|
## Getting set up
|
||||||
|
|
||||||
Use Node.js 24.14.x or 26.x (also enforced by `package.json`).
|
Use Node.js 24 (24.14.0 or later) or 26.x (also enforced by `package.json`).
|
||||||
|
Prefer 24.22.1 or later: earlier releases lack the October 21, 2026 security
|
||||||
|
fixes, including CVE-2026-111497 (a Brotli decoder flaw).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/bilawalsidhu/gods-eye-view.git
|
git clone https://github.com/bilawalsidhu/gods-eye-view.git
|
||||||
cd gods-eye-view
|
cd gods-eye-view
|
||||||
nvm install 24.14.0
|
nvm install 24.22.2
|
||||||
nvm use 24.14.0
|
nvm use 24.22.2
|
||||||
npm install
|
npm install
|
||||||
npm run doctor
|
npm run doctor
|
||||||
./scripts/dev-fresh.sh # or: npm run dev (keys are optional)
|
./scripts/dev-fresh.sh # or: npm run dev (keys are optional)
|
||||||
@@ -27,6 +29,25 @@ through Pinokio; the terminal path above remains the contributor path.
|
|||||||
|
|
||||||
Open `http://localhost:4173`. Before sending a PR run `npm run build`, `npm test`, and `npm run test:track` (dev server must be up) — **all three must stay green.**
|
Open `http://localhost:4173`. Before sending a PR run `npm run build`, `npm test`, and `npm run test:track` (dev server must be up) — **all three must stay green.**
|
||||||
|
|
||||||
|
### Test prerequisites
|
||||||
|
|
||||||
|
- **`npm test`** — unit tests. Runs standalone; no dev server or credentials
|
||||||
|
required. Exit code is the gate.
|
||||||
|
- **`npm run test:track`** — the 3D flight-tracking regression harness. It
|
||||||
|
drives the **real app** in headless Chromium, so it **requires a running
|
||||||
|
dev server** (default `http://localhost:4173`). To target another instance,
|
||||||
|
run `npm run test:track -- --url <app-url>` (or
|
||||||
|
`node scripts/track-regression.mjs --url <app-url>`). It does not depend on
|
||||||
|
live OpenSky / adsb.lol / AISStream (those are optional or rate-limited
|
||||||
|
locally); it installs a persistent `fetch` shim that returns synthetic
|
||||||
|
aircraft in the exact upstream payload shapes the layers parse.
|
||||||
|
- **`npm run build`** — production Vite build. No server or credentials
|
||||||
|
required; it validates that the client bundle compiles cleanly.
|
||||||
|
|
||||||
|
Each feature also has its own headless gate; see
|
||||||
|
[Feature regression gates](#feature-regression-gates) below. Docs and changelog
|
||||||
|
rules are under [Pull requests](#pull-requests).
|
||||||
|
|
||||||
## Checking a built app locally
|
## Checking a built app locally
|
||||||
|
|
||||||
Run `npm run build` followed by `npm run preview`. Preview serves the built
|
Run `npm run build` followed by `npm run preview`. Preview serves the built
|
||||||
|
|||||||
@@ -304,6 +304,15 @@ the retrieval date (2026-07-30), exact download URL, license evidence, and the
|
|||||||
deterministic transform (`scripts/build-sf-neighborhoods.mjs`: `nhood` → `name`, ~2 m
|
deterministic transform (`scripts/build-sf-neighborhoods.mjs`: `nhood` → `name`, ~2 m
|
||||||
Douglas-Peucker simplification, 6-decimal rounding).
|
Douglas-Peucker simplification, 6-decimal rounding).
|
||||||
|
|
||||||
|
### Local CCTV source packs (`config/`)
|
||||||
|
|
||||||
|
The server can read a local camera list from `CCTV_SOURCES_FILE` (default
|
||||||
|
`config/cctv_sources.austin.json`, which ships empty) and inline JSON from
|
||||||
|
`CCTV_SOURCES_JSON`; the two are merged, and inline entries win on a duplicate
|
||||||
|
id. A non-empty local pack replaces the live open-data camera packs unless
|
||||||
|
`CCTV_FORCE_AUSTIN=1` is set. The packs under `config/` show the schema, and a
|
||||||
|
pack's cameras keep their own source's license and attribution.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Weather sources
|
## Weather sources
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
# proxies (ADS-B, AIS, Overpass, OpenAI Realtime, ...) as middleware, so there
|
# proxies (ADS-B, AIS, Overpass, OpenAI Realtime, ...) as middleware, so there
|
||||||
# is nothing else to containerise. See compose.yaml for the usual entry point.
|
# is nothing else to containerise. See compose.yaml for the usual entry point.
|
||||||
# Same Node as CI (package.json engines, .github/workflows), pinned by digest.
|
# Same Node as CI (package.json engines, .github/workflows), pinned by digest.
|
||||||
FROM node:24.14.0-slim@sha256:d8e448a56fc63242f70026718378bd4b00f8c82e78d20eefb199224a4d8e33d8
|
FROM node:24.22.2-slim@sha256:c86ecead9e55a5210ac1727de38a4ca840bf03dcaf34dc9749addbf383b1920c
|
||||||
|
|
||||||
# Puppeteer is only used by the QA scripts; skip its ~150MB Chromium download.
|
# Puppeteer is only used by the QA scripts; skip its ~150MB Chromium download.
|
||||||
ENV PUPPETEER_SKIP_DOWNLOAD=1
|
ENV PUPPETEER_SKIP_DOWNLOAD=1
|
||||||
|
|||||||
@@ -129,8 +129,9 @@ hardware; it does not establish a minimum GPU requirement.
|
|||||||
|
|
||||||
### Path 2 — Terminal / coding agent
|
### Path 2 — Terminal / coding agent
|
||||||
|
|
||||||
Use **Node.js 24.x (24.14.0 or later) or 26.x**. The setup doctor warns about
|
Use **Node.js 24.x (24.14.0 or later) or 26.x**; 24.22.1 or later (26.12.1 or
|
||||||
Node 25, which is end-of-life.
|
later on 26) includes the October 21, 2026 security fixes, among them
|
||||||
|
CVE-2026-111497. The setup doctor warns about Node 25, which is end-of-life.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/bilawalsidhu/gods-eye-view.git
|
git clone https://github.com/bilawalsidhu/gods-eye-view.git
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- The military-installations proxy (`/api/military-installations`) now refuses
|
||||||
|
cross-site and reverse-proxy-forwarded browser requests with 403 before any
|
||||||
|
Overpass work, through the same shared gate as `/api/overpass`. Same-origin
|
||||||
|
app requests and local tools such as curl still work (@Sunil56224972, #1427).
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- Between 721px and 900px wide (tablet portrait, phone landscape), the
|
||||||
|
Location and Visual Presets dock wings show only their icons, so their
|
||||||
|
labels no longer spill over the voice control or take taps meant for the
|
||||||
|
mic button. The full name stays in the tooltip and accessible name, and the
|
||||||
|
Cyber layout keeps its labels (Denis Groshev, @ZloyS, #1457).
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- The Docker image and CI now pin Node 24.22.2, the current 24 LTS patch. It
|
||||||
|
carries the October 21, 2026 security fixes first released in 24.22.1,
|
||||||
|
including CVE-2026-111497 in the Brotli decoder (Luis Ortiz, @anobjectn,
|
||||||
|
#1458).
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- Contributor docs: CONTRIBUTING lists what each of the three baseline checks
|
||||||
|
needs to run, DATA_SOURCES documents loading a local CCTV source pack, and
|
||||||
|
KNOWN-ISSUES points the floor-placement note at its verification script
|
||||||
|
instead of a missing report (Gaurav Patidar, @gaurav7902, #210).
|
||||||
+22
-2
@@ -2816,6 +2816,20 @@ isCurrent })` gates BOTH halves of the map-stack switch, which is its only
|
|||||||
> name the panel (`#location-bar` / `#control-panel`) to reach (2,5,0). Adding
|
> name the panel (`#location-bar` / `#control-panel`) to reach (2,5,0). Adding
|
||||||
> a new tray rule means checking it against the pinned variants, not just
|
> a new tray rule means checking it against the pinned variants, not just
|
||||||
> against the base rule.
|
> against the base rule.
|
||||||
|
> - **Dock wings are icon-only from 900px down to 721px (2026-10-28):** at
|
||||||
|
> ≤900px `--dock-side-compact` shrinks the Location and Visual Presets wings
|
||||||
|
> to 4.25rem, open or closed (an open tray pops out above the dock), which is
|
||||||
|
> too narrow for their text labels. The labels used to spill over the voice
|
||||||
|
> control, and the LOCATION label captured taps on the left half of the mic
|
||||||
|
> button. `src/ui/styles/command-dock-trays.css` now sets the
|
||||||
|
> labels to `font-size: 0` and drops their `›`/`‹` chevrons in that band, so
|
||||||
|
> each wing shows only its icon. `CommandDockView.vue` still gives the toggles
|
||||||
|
> their "Expand/Collapse …" `aria-label` and `title` (`trayWords`), so the
|
||||||
|
> browser tooltip is the only visible name on hover.
|
||||||
|
> The Cyber HUD layout is excluded: it sets `--dock-side-compact` to
|
||||||
|
> 9–9.75rem, which fits its labels. The former ≤620px ellipsis clip is gone:
|
||||||
|
> the phone shell takes over at 720px, so it never applied to a visible
|
||||||
|
> dock.
|
||||||
> - **LOCATION mini-status is data-only today (2026-08-20):** the collapsed
|
> - **LOCATION mini-status is data-only today (2026-08-20):** the collapsed
|
||||||
> readout now follows a free-text geocode search as well as preset pills
|
> readout now follows a free-text geocode search as well as preset pills
|
||||||
> (`src/locationStatus.js` owns the copy for both), and every other camera
|
> (`src/locationStatus.js` owns the copy for both), and every other camera
|
||||||
@@ -3455,7 +3469,8 @@ down | auth-failed` (plus the unchanged `missing-key`/`unsupported`) with
|
|||||||
> style-switch persistence state. Browser/GPU performance comparison remains
|
> style-switch persistence state. Browser/GPU performance comparison remains
|
||||||
> operator-side; the final accounting records only comparable population
|
> operator-side; the final accounting records only comparable population
|
||||||
> reductions and deterministic Node allocation/solve measurements. Those
|
> reductions and deterministic Node allocation/solve measurements. Those
|
||||||
> allocation gates are calibrated on Node.js 24.14.x; `package.json` permits
|
> allocation gates were calibrated on Node.js 24.14.x and run in CI on the
|
||||||
|
> pinned Node.js 24.22.2 with the same ceilings; `package.json` permits
|
||||||
> supported product runtimes on Node 24 or 26, while the allocation runner
|
> supported product runtimes on Node 24 or 26, while the allocation runner
|
||||||
> separately enforces Node 24 for these two calibrated probes. Each probe
|
> separately enforces Node 24 for these two calibrated probes. Each probe
|
||||||
> compiles synchronously and discards explicit-GC
|
> compiles synchronously and discards explicit-GC
|
||||||
@@ -5106,6 +5121,8 @@ repointing `OVERPASS_UPSTREAMS` refetches instead of serving another instance's
|
|||||||
answers; untagged entries stop serving once an instance is configured.
|
answers; untagged entries stop serving once an instance is configured.
|
||||||
|
|
||||||
The shared transport guards `/api/overpass` and `/api/military-installations`.
|
The shared transport guards `/api/overpass` and `/api/military-installations`.
|
||||||
|
Both query handlers refuse cross-site and forwarded browser requests through
|
||||||
|
the shared local-request gate, before any rate-limit, cache or upstream work.
|
||||||
With no configured upstream, each route serves existing cache data (including
|
With no configured upstream, each route serves existing cache data (including
|
||||||
expired entries, marked stale with the original cache/retrieval date) without
|
expired entries, marked stale with the original cache/retrieval date) without
|
||||||
refresh. An annotation miss returns HTTP 503, `OVERPASS_NOT_CONFIGURED`,
|
refresh. An annotation miss returns HTTP 503, `OVERPASS_NOT_CONFIGURED`,
|
||||||
@@ -6203,7 +6220,10 @@ The lockfile uses DOMPurify 3.4.17, protobufjs 8.8.0, PostCSS 8.5.28,
|
|||||||
source-map-js 1.2.2 and nanoid 3.3.19. Cesium remains on 1.138.0. Browser QA
|
source-map-js 1.2.2 and nanoid 3.3.19. Cesium remains on 1.138.0. Browser QA
|
||||||
uses Puppeteer 25.10.0; image-processing tools use Sharp 0.35.5. QA scripts await Puppeteer's asynchronous
|
uses Puppeteer 25.10.0; image-processing tools use Sharp 0.35.5. QA scripts await Puppeteer's asynchronous
|
||||||
executable-path lookup before testing or passing the path to Chrome. Supported Node versions remain
|
executable-path lookup before testing or passing the path to Chrome. Supported Node versions remain
|
||||||
24.14.x and 26.x. Use `npm ci` to reproduce the checked-in dependency tree.
|
Node 24 (24.14.0 or later) and 26.x; the Docker image and CI pin 24.22.2,
|
||||||
|
the current 24 LTS patch, which carries the October 21, 2026 Node.js security
|
||||||
|
fixes first released in 24.22.1 (including CVE-2026-111497). Use
|
||||||
|
`npm ci` to reproduce the checked-in dependency tree.
|
||||||
|
|
||||||
### Traffic city navigation
|
### Traffic city navigation
|
||||||
|
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ Status: Open (owner-accepted 2026-07-08, documented)
|
|||||||
a few stragglers take one more poll.
|
a few stragglers take one more poll.
|
||||||
- **Born-grounded first poll:** a contact first seen on the ground with no altitude
|
- **Born-grounded first poll:** a contact first seen on the ground with no altitude
|
||||||
data renders at the geoid for ≤1 poll until its floor cell warms.
|
data renders at the geoid for ≤1 poll until its floor cell warms.
|
||||||
- Full context, improvement ideas, and the verification oracle
|
- Verify floor-placement behavior with `scripts/qa-floor-verify.mjs` against a
|
||||||
(`scripts/qa-floor-verify.mjs`):
|
running local app; set `QA_BASE_URL` when it is not on the default port
|
||||||
`docs/superpowers/reports/2026-07-08-height-datum-handover.md`.
|
(`http://localhost:4173`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -436,7 +436,9 @@
|
|||||||
"server/providers/overpass/transport.js",
|
"server/providers/overpass/transport.js",
|
||||||
"src/sources/httpBody.js",
|
"src/sources/httpBody.js",
|
||||||
"src/i18n/marker.js",
|
"src/i18n/marker.js",
|
||||||
"src/sources/rateLimit.js"
|
"src/sources/rateLimit.js",
|
||||||
|
"server/providers/common/same-site.js",
|
||||||
|
"src/localRequestGate.mjs"
|
||||||
],
|
],
|
||||||
"external": []
|
"external": []
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export function classifyNodeVersion(version = process.versions.node) {
|
|||||||
// NEWER than this release has verified is a warning, never a refusal: a
|
// NEWER than this release has verified is a warning, never a refusal: a
|
||||||
// future Node must not brick a no-terminal install with advice its user
|
// future Node must not brick a no-terminal install with advice its user
|
||||||
// cannot follow. Too-old stays an error above — old runtimes genuinely fail.
|
// cannot follow. Too-old stays an error above — old runtimes genuinely fail.
|
||||||
return { level: 'warn', summary: 'newer than this release has verified; Node 24.14.x or 26.x is the tested path' };
|
return { level: 'warn', summary: 'newer than this release has verified; Node 24.22.x or 26.x is the tested path' };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Verify that every direct package declared by this checkout is present. */
|
/** Verify that every direct package declared by this checkout is present. */
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { makeRateLimiter, clientKey } from './common/rate-limit.js';
|
import { makeRateLimiter, clientKey } from './common/rate-limit.js';
|
||||||
|
import { admitSameSite } from './common/same-site.js';
|
||||||
import {
|
import {
|
||||||
MILITARY_INSTALLATION_ELEMENT_CAP,
|
MILITARY_INSTALLATION_ELEMENT_CAP,
|
||||||
MILITARY_INSTALLATION_MAX_RESPONSE_BYTES,
|
MILITARY_INSTALLATION_MAX_RESPONSE_BYTES,
|
||||||
@@ -97,6 +98,7 @@ function militaryInstallationsProxy() {
|
|||||||
res.end(JSON.stringify({ error: 'Method Not Allowed' }));
|
res.end(JSON.stringify({ error: 'Method Not Allowed' }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (admitSameSite(req, res)) return;
|
||||||
const url = new URL(req.url, 'http://localhost');
|
const url = new URL(req.url, 'http://localhost');
|
||||||
const requested = validMilitaryInstallationBox(url.searchParams);
|
const requested = validMilitaryInstallationBox(url.searchParams);
|
||||||
if (!requested) {
|
if (!requested) {
|
||||||
|
|||||||
@@ -54,14 +54,22 @@ async function call(handlers, url, init = {}) {
|
|||||||
Object.assign(req, {
|
Object.assign(req, {
|
||||||
method: init.method || 'GET',
|
method: init.method || 'GET',
|
||||||
url: parsed.pathname.slice(mount.length) + parsed.search || '/',
|
url: parsed.pathname.slice(mount.length) + parsed.search || '/',
|
||||||
headers: {},
|
headers: init.headers || {},
|
||||||
socket: { remoteAddress: '127.0.0.1' },
|
socket: { remoteAddress: '127.0.0.1' },
|
||||||
});
|
});
|
||||||
let status, headers, body;
|
let status, body;
|
||||||
|
let headers = {};
|
||||||
await handlers.get(mount)(req, {
|
await handlers.get(mount)(req, {
|
||||||
|
// The cross-site gate answers through statusCode/setHeader, not writeHead.
|
||||||
|
set statusCode(s) {
|
||||||
|
status = s;
|
||||||
|
},
|
||||||
|
setHeader(name, value) {
|
||||||
|
headers[name] = value;
|
||||||
|
},
|
||||||
writeHead(s, h) {
|
writeHead(s, h) {
|
||||||
status = s;
|
status = s;
|
||||||
headers = h;
|
headers = { ...headers, ...h };
|
||||||
},
|
},
|
||||||
end(b) {
|
end(b) {
|
||||||
body = b;
|
body = b;
|
||||||
@@ -166,6 +174,36 @@ test('zero egress: every Overpass consumer reaches real default handlers, and re
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the installations proxy refuses cross-site and forwarded requests before any Overpass work', async (t) => {
|
||||||
|
env(t);
|
||||||
|
t.mock.method(globalThis, 'fetch', () =>
|
||||||
|
assert.fail('unexpected upstream fetch'),
|
||||||
|
);
|
||||||
|
const handlers = routes(militaryInstallationsProxy());
|
||||||
|
const url =
|
||||||
|
'/api/military-installations?south=48.8&west=2.2&north=48.9&east=2.4';
|
||||||
|
for (const headers of [
|
||||||
|
{ 'sec-fetch-site': 'cross-site' },
|
||||||
|
{ 'sec-fetch-site': 'same-site' },
|
||||||
|
{ origin: 'https://foreign.example' },
|
||||||
|
{ origin: 'null' },
|
||||||
|
{ 'sec-fetch-site': 'same-origin', 'x-forwarded-for': '203.0.113.9' },
|
||||||
|
]) {
|
||||||
|
const response = await call(handlers, url, { headers });
|
||||||
|
assert.equal(response.status, 403, JSON.stringify(headers));
|
||||||
|
assert.equal(response.headers.get('cache-control'), 'no-store');
|
||||||
|
}
|
||||||
|
for (const headers of [
|
||||||
|
{},
|
||||||
|
{ origin: 'http://localhost:4173', 'sec-fetch-site': 'same-origin' },
|
||||||
|
]) {
|
||||||
|
const response = await call(handlers, url, {
|
||||||
|
headers: { host: 'localhost:4173', ...headers },
|
||||||
|
});
|
||||||
|
assert.notEqual(response.status, 403, JSON.stringify(headers));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('an unconfigured server is probed once and never sent a feature query', async (t) => {
|
test('an unconfigured server is probed once and never sent a feature query', async (t) => {
|
||||||
env(t);
|
env(t);
|
||||||
t.mock.method(globalThis, 'fetch', () =>
|
t.mock.method(globalThis, 'fetch', () =>
|
||||||
|
|||||||
@@ -495,6 +495,36 @@ body:not(.ui-clean-view):not(.recording-mode):has(
|
|||||||
#command-dock .gev-voice-error-tray {
|
#command-dock .gev-voice-error-tray {
|
||||||
width: min(24rem, calc(100vw - 1.5rem));
|
width: min(24rem, calc(100vw - 1.5rem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The wings shrink to --dock-side-compact at this width, open or closed (an
|
||||||
|
open tray pops out above the dock), which is too narrow for the text
|
||||||
|
labels; they would spill over the voice control and take its taps. The
|
||||||
|
wings show only their icon; the toggles keep their aria-label. Cyber sets
|
||||||
|
a wider --dock-side-compact that fits its labels, so it keeps them. */
|
||||||
|
:root:not([data-ui-theme='cyber'])
|
||||||
|
#command-dock
|
||||||
|
:is(#location-bar, #control-panel)
|
||||||
|
.panel-title,
|
||||||
|
:root:not([data-ui-theme='cyber'])
|
||||||
|
#command-dock
|
||||||
|
:is(#location-bar, #control-panel)
|
||||||
|
.location-toolbar-label {
|
||||||
|
font-size: 0;
|
||||||
|
letter-spacing: 0;
|
||||||
|
/* The empty text is still a flex item; drop the gap it would claim. */
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root:not([data-ui-theme='cyber'])
|
||||||
|
#command-dock
|
||||||
|
:is(#location-bar, #control-panel)
|
||||||
|
.panel-title::after,
|
||||||
|
:root:not([data-ui-theme='cyber'])
|
||||||
|
#command-dock
|
||||||
|
:is(#location-bar, #control-panel)
|
||||||
|
.location-toolbar-label::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 620px) {
|
@media (max-width: 620px) {
|
||||||
@@ -503,13 +533,6 @@ body:not(.ui-clean-view):not(.recording-mode):has(
|
|||||||
--dock-voice-width: 8.75rem;
|
--dock-voice-width: 8.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#command-dock .panel-title,
|
|
||||||
#command-dock .location-toolbar-label {
|
|
||||||
max-width: 2.3rem;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
#left-panel-stack {
|
#left-panel-stack {
|
||||||
bottom: calc(50vh + 8px);
|
bottom: calc(50vh + 8px);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user