From 74f27fd1c6ff771d3493a117854b5fc6aa916988 Mon Sep 17 00:00:00 2001 From: jominki354 Date: Fri, 26 Jun 2026 11:51:13 +0900 Subject: [PATCH 01/15] nav delete --- selfdrive/carrot/README.md | 199 +++++++--- selfdrive/carrot/web/css/components.css | 98 ----- .../carrot/web/css/pages/settings/device.css | 83 ---- .../carrot/web/css/pages/settings/panels.css | 4 - selfdrive/carrot/web/css/tokens.css | 2 +- selfdrive/carrot/web/index.html | 21 +- selfdrive/carrot/web/js/pages/setting.js | 369 +----------------- .../carrot/web/js/pages/setting_device.js | 1 - selfdrive/carrot/web/js/shared/dom.js | 2 - selfdrive/carrot/web/js/shared/i18n.js | 1 - .../carrot/web/js/shared/ui/navigation.js | 9 - 11 files changed, 159 insertions(+), 630 deletions(-) diff --git a/selfdrive/carrot/README.md b/selfdrive/carrot/README.md index 39a9437834..6d11ed006c 100644 --- a/selfdrive/carrot/README.md +++ b/selfdrive/carrot/README.md @@ -11,6 +11,7 @@ selfdrive/carrot/ carrot_functions.py carrot shared functions carrot_man.py carrot manager carrot_serv.py carrot service/runtime + cweb_push.py CWP push client (device IP / git update notify) xiaoge_data.py car data server/ aiohttp backend realtime/ WebSocket realtime transports @@ -25,21 +26,25 @@ carrot_server.py -> server.app.make_app() -> server.features.register_all(app) -> web/ static files + -> on_startup background tasks (broker, hubs, heartbeat, git status, auto update, malloc trim) browser - -> web/index.html - -> web/js/shared/* - -> web/js/pages/* - -> web/js/realtime/* - -> web/js/app.js + -> GET / -> server/features/static.py injects window.__CARROT_BOOTSTRAP__ + -> web/index.html + -> web/js/vendor/* + -> web/js/translations/* + -> web/js/shared/* + shared/ui/* + -> web/js/pages/* + -> web/js/realtime/* + -> web/js/app.js ``` ## Main Entry Points | Path | Role | |---|---| -| `carrot_server.py` | Starts aiohttp web server on port `7000`. | -| `server/app.py` | Backend composition root. Creates app, runtime hubs, background tasks, routes. | +| `carrot_server.py` | Starts aiohttp web server on port `7000`. Core affinity tunable via `CARROT_WEB_CORES`. | +| `server/app.py` | Backend composition root. Creates app, runtime hubs, background tasks, routes, static serving. | | `server/features/__init__.py` | Registers backend feature modules. | | `server/config.py` | Shared backend paths and constants. | | `web/index.html` | Single HTML shell containing all page sections and script/style load order. | @@ -60,6 +65,7 @@ server/ services.py snapshot.py services/ + auto_update.py device_info.py git_state.py git_status.py @@ -71,6 +77,8 @@ server/ ssh_keys.py time_sync.py tmux.py + vision_diag.py + vision_test.py web_settings.py features/ cars.py @@ -83,20 +91,24 @@ server/ stream.py system.py terminal.py + vision_diag.py + vision_test.py web_settings.py ws.py dashcam/ screenrecord/ tools/ + terminal_commands/ ``` ## Backend Core Files | Path | Role | |---|---| -| `server/app.py` | Creates `aiohttp.Application`, `ClientSession`, `RealtimeBroker`, `CameraWsHub`, `RawWsHub`, heartbeat task, git status task, route registration, static serving. | -| `server/config.py` | `WEB_DIR`, settings paths, state paths, dashcam paths, WebRTC URL, tmux session, backup paths. | +| `server/app.py` | Creates `aiohttp.Application` (with request-log middleware + 16MB client max size), `ClientSession`, `RealtimeBroker(repo_flavor="c3")`, `CameraWsHub`, `RawWsHub`. Startup tasks: `heartbeat_loop` (when Params present), `git_status_loop`, `auto_update_loop`, periodic gc + `malloc_trim` loop. Holds `realtime_broker_poll_lock` to serialize SubMaster polls. Adds static `/` after explicit routes. | +| `server/config.py` | `WEB_DIR`/`CSS_DIR`/`JS_DIR`/`ASSETS_DIR`, settings path, state paths (`git.json`, `tool_jobs.json`, `web_settings.json`, `setting_favorites.json`, `setting_profiles.json`), dashcam/screenrecord paths, obfuscated Discord webhooks (dashcam + vision diag), `WEBRTCD_URL`, tmux session, params backup path. | | `server/features/__init__.py` | Calls each feature module's `register(app)`. | +| `server/features/static.py` | `GET /` handler — injects `window.__CARROT_BOOTSTRAP__` (webSettings, deviceLanguage, deviceLanguages) into `index.html`, no-cache headers; serves `/training/` assets. | | `server/live_runtime/broker.py` | Owns the realtime `SubMaster` broker used by `/api/live_runtime`. | | `server/live_runtime/snapshot.py` | Builds live runtime snapshots for frontend polling. | | `server/live_runtime/normalize.py` | Converts raw cereal/openpilot values into JSON-safe values. | @@ -107,38 +119,43 @@ server/ | Path | Used by | Role | |---|---|---| -| `services/params.py` | `features/params.py`, tools backup/restore | Params read/write, bulk backup values. | +| `services/params.py` | `features/params.py`, tools backup/restore | Params read/write, bulk backup values (`HAS_PARAMS` guard). | | `services/settings.py` | `features/settings.py`, static bootstrap | `carrot_settings.json` cache and parsing. | -| `services/git_state.py` | tools, metadata | Persisted git pull state such as last pull time. | -| `services/git_status.py` | `features/tools/routes.py`, startup loop | Cached git fetch/status info for update badges. | +| `services/git_state.py` | tools, auto update, metadata | Persisted git pull state such as last pull time. | +| `services/git_status.py` | `features/tools/routes.py`, auto update, startup loop | Cached git fetch/status info (ahead/behind) for update badges. | +| `services/auto_update.py` | `server/app.py` | Device-side auto `git pull` loop (when `auto_update_git_pull` web setting on); hard reset + pull, no reboot, best-effort CWP "what changed" notify. | | `services/heartbeat.py` | `server/app.py`, `features/system.py` | Heartbeat/register loop and status. | | `services/device_info.py` | `features/system.py` | Device network and calibration helpers. | | `services/time_sync.py` | `features/system.py` | Browser-to-device time sync. | | `services/tmux.py` | `features/terminal.py` | tmux session create, capture, input, clear. | | `services/ssh_keys.py` | `features/ssh_keys.py` | SSH key fetch/store helpers. | | `services/setting_favorites.py` | `features/setting_favorites.py` | Favorite setting names. | -| `services/setting_profiles.py` | `features/setting_profiles.py` | Setting profile CRUD/import/export. | -| `services/web_settings.py` | `features/web_settings.py` | Server-backed web settings. | +| `services/setting_profiles.py` | `features/setting_profiles.py` | Setting profile CRUD/import/export/apply. | +| `services/web_settings.py` | `features/web_settings.py`, static bootstrap, auto update | Server-backed web settings (`web_settings.json`). | +| `services/vision_diag.py` | `features/vision_diag.py` | Server diagnostic snapshot (camerad/encoderd/stream proxy history) + Discord upload of diagnostic bundle. | +| `services/vision_test.py` | `features/vision_test.py`, `services/vision_diag.py` | Standalone camerad + stream encoderd test runner, status/log at `/tmp/carrot-vision-test*`. | ## Backend Feature Routes | Feature | Main paths | Files | |---|---|---| -| Static/bootstrap | `/`, static fallback | `features/static.py` | -| WebRTC proxy | `/stream` | `features/stream.py` | +| Static/bootstrap | `/`, `/training/*`, static fallback | `features/static.py` | +| WebRTC proxy | `POST /stream` | `features/stream.py` | | Raw/camera WebSocket | `/ws/raw/{service}`, `/ws/raw_multiplex`, `/ws/camera/{camera}` | `features/ws.py`, `realtime/transports/*` | -| Settings | `/api/settings` | `features/settings.py`, `services/settings.py` | -| Params | `/api/params_bulk`, `/api/param_set`, restore/backup/download endpoints | `features/params.py`, `services/params.py` | -| Favorites | `/api/setting_favorites` | `features/setting_favorites.py` | -| Profiles | `/api/setting_profiles`, import/export endpoints | `features/setting_profiles.py` | -| Web settings | `/api/web_settings` | `features/web_settings.py`, `services/web_settings.py` | -| SSH keys | `/api/ssh_keys` | `features/ssh_keys.py`, `services/ssh_keys.py` | -| Cars | `/api/cars` | `features/cars.py` | -| System | heartbeat, live runtime, reboot, poweroff, recalibrate, network, calibration | `features/system.py`, `services/device_info.py`, `services/heartbeat.py` | -| Terminal | `/ws/terminal`, `/download/tmux.log` | `features/terminal.py`, `services/tmux.py` | -| Tools | `/api/tools`, `/api/tools/start`, `/api/tools/job`, `/api/tools/jobs`, `/api/tools/git_status` | `features/tools/*`, `services/git_status.py` | -| Dashcam | `/api/dashcam/*` | `features/dashcam/*` | -| Screenrecord | `/api/screenrecord/*` | `features/screenrecord/*` | +| Settings | `GET /api/settings` | `features/settings.py`, `services/settings.py` | +| Params | `GET /api/params_bulk`, `POST /api/param_set`, `POST /api/params_restore`, `POST /api/params_restore_preview`, `POST /api/params_restore_json`, `GET/POST /api/params_qr_dependency(/ensure)`, `GET /api/params_qr_backup`, `GET /download/params_backup.json` | `features/params.py`, `services/params.py` | +| Favorites | `GET/POST /api/setting_favorites` | `features/setting_favorites.py` | +| Profiles | `GET/POST /api/setting_profiles`, `/update`, `/delete`, `/preview`, `/apply` | `features/setting_profiles.py` | +| Web settings | `GET/POST /api/web_settings` | `features/web_settings.py`, `services/web_settings.py` | +| SSH keys | `GET/POST /api/ssh_keys` | `features/ssh_keys.py`, `services/ssh_keys.py` | +| Cars | `GET /api/cars` | `features/cars.py` | +| System | `GET /api/heartbeat_status`, `/api/live_runtime`, `/api/device_network`, `/api/calibration_status`, `/api/regulatory`; `POST /api/reboot`, `/api/poweroff`, `/api/recalibrate`, `/api/set_default`, `/api/time_sync` | `features/system.py`, `services/device_info.py`, `services/heartbeat.py`, `services/time_sync.py` | +| Terminal | `GET /ws/terminal`, `GET /download/tmux.log` | `features/terminal.py`, `services/tmux.py` | +| Tools | `POST /api/tools`, `/api/tools/start`, `/api/tools/jobs/notice`; `GET /api/tools/job`, `/api/tools/jobs`, `/api/tools/git_status`; `DELETE /api/tools/jobs` | `features/tools/*`, `services/git_status.py` | +| Dashcam | `/api/dashcam/*` (routes, segments, thumbnail, preview, video, download, upload) | `features/dashcam/*` | +| Screenrecord | `/api/screenrecord/*` (videos, thumbnail, video, download) | `features/screenrecord/*` | +| Vision diag | `GET /api/vision_diag/server_snapshot`, `POST /api/vision_diag/upload_discord` | `features/vision_diag.py`, `services/vision_diag.py` | +| Vision test | `GET /api/vision_test/status` | `features/vision_test.py`, `services/vision_test.py` | ## Tools Backend @@ -154,10 +171,25 @@ server/features/tools/ | File | Role | |---|---| | `actions.py` | Known tool action names and shell command allowlist. | -| `routes.py` | HTTP routes for sync actions, async jobs, job history, git status. | +| `routes.py` | HTTP routes for sync actions, async jobs, job history/clear/notice, git status. | | `jobs.py` | In-memory/persisted tool job state, log snapshots, async process helpers. | | `dispatcher.py` | Actual action implementations: git pull/sync/reset, branch, logs, backup, reboot, install, shell command. | +## Terminal Commands Backend + +```text +server/terminal_commands/ + README.md + bridge.py + cli.py + registry.py + custom_commands/ + help.py + vision_test.py +``` + +Custom in-terminal commands surfaced through the tmux terminal (see `terminal_commands/README.md`). `vision_test.py` drives the camerad/encoderd test runner from the terminal. + ## Dashcam Backend ```text @@ -210,11 +242,12 @@ realtime/ | Path | Role | |---|---| -| `raw_services.py` | Raw cereal service list definitions. | -| `raw_protocol.py` | Raw capnp packet/protocol helpers. | +| `__init__.py` | Re-exports raw protocol constants/builders and raw service helpers. | +| `raw_services.py` | Raw cereal service list definitions (core/optional, allowlist). | +| `raw_protocol.py` | Raw capnp packet/protocol helpers, hello builders, multiplex framing. | | `raw_runner.py` | Async raw stream runner. | -| `transports/camera_ws.py` | Camera stream lifecycle and WebSocket broadcasting. | -| `transports/raw_ws.py` | Raw service and multiplex WebSocket broadcasting. | +| `transports/camera_ws.py` | Camera stream lifecycle and WebSocket broadcasting (`ws_camera`). | +| `transports/raw_ws.py` | Raw service and multiplex WebSocket broadcasting (service allowlist enforced). | ## Frontend Tree @@ -239,6 +272,8 @@ web/css/ layout.css components.css responsive.css + components/ + nav_hud.css vendor/ plyr.css pages/ @@ -264,6 +299,7 @@ web/css/ | `layout.css` | Page containers, headers, common layout blocks. | | `components.css` | Shared dialogs, buttons, chips, toasts, generic components. | | `responsive.css` | Cross-page responsive adjustments loaded near the end. | +| `components/nav_hud.css` | Carrot Nav HUD V2 top-center guidance card. | | `pages/drive.css` | Drive stage, video, overlay canvas, vision controls. | | `pages/logs.css` | Logs, dashcam, screenrecord views. | | `pages/terminal.css` | Terminal page. | @@ -303,6 +339,7 @@ web/js/shared/ | Path | Scope | |---|---| +| `shared/constants.js` | Global constants — lang storage key/emoji, unit cycle, page transition classes, debug flag. | | `shared/api.js` | JSON API helpers and Params helpers. | | `shared/dom.js` | Shared DOM references from `index.html`. | | `shared/i18n.js` | Language state and UI text rendering. | @@ -357,17 +394,20 @@ web/js/pages/ | `pages/logs/dashcam.js` | Dashcam route/segment list, upload flow. | | `pages/logs/screenrecord.js` | Screenrecord list and thumbnails. | | `pages/terminal.js` | tmux WebSocket terminal UI. | -| `pages/vision_background.js` | Non-realtime page background state. | +| `pages/vision_background.js` | Non-realtime page ambient canvas background. | ### Realtime JS ```text web/js/realtime/ app_realtime.js + carrot_map.js home_drive.js hud_card.js + nav_hud.js raw_capnp.js raw_capnp_worker.js + vision_diag.js vision_raw.js vision_rtc.js vision_state.js @@ -378,11 +418,29 @@ web/js/realtime/ | `realtime/app_realtime.js` | Live runtime polling/raw stream wiring and HUD bridge. | | `realtime/home_drive.js` | Drive/Carrot Vision renderer and overlay canvas. | | `realtime/hud_card.js` | HUD card data rendering. | +| `realtime/carrot_map.js` | Kakao minimap iframe bridge (kmap), `FRAME_VERSION` gated to limit SDK quota. | +| `realtime/nav_hud.js` | Carrot Nav HUD V2 — top-center guidance card from `carrotMan` state, no iframe/network. | | `realtime/raw_capnp.js` | Raw capnp decode entry. | | `realtime/raw_capnp_worker.js` | Worker-side decode entry. | | `realtime/vision_state.js` | Shared vision/HUD state object. | | `realtime/vision_rtc.js` | WebRTC stream client. | | `realtime/vision_raw.js` | Raw WebSocket client and worker bridge. | +| `realtime/vision_diag.js` | Silent WebRTC/video diagnostic recorder (localStorage ring buffer) feeding the vision diag upload. | + +### Translations JS + +```text +web/js/translations/ + registry.js + ko.js + en.js + zh.js +``` + +| Path | Scope | +|---|---| +| `translations/registry.js` | Merges per-language packs over an English/Korean fallback into the shared `CarrotTranslations` API. | +| `translations/{ko,en,zh}.js` | Per-language string/actionLabel/errorMessage/driveMode packs. | ## HTML Page Sections @@ -403,6 +461,7 @@ Common overlay/dialog hosts in `index.html`: | ID | Scope | |---|---| | `driveHudCard` | Shared Drive HUD card DOM. | +| `carrotNavHud` | Nav HUD V2 top-center card host. | | `rtcVideo` | Shared RTC video element. | | `appToastHost` | Toast host. | | `appDialog` | Generic app dialog. | @@ -411,7 +470,7 @@ Common overlay/dialog hosts in `index.html`: ## Load Order Reference -CSS is loaded in `web/index.html` in this shape: +CSS is loaded in `web/index.html` in this order: ```text tokens.css @@ -420,33 +479,47 @@ hud_card.css base.css layout.css components.css -page CSS +pages/logs.css +pages/terminal.css +pages/settings/{base,panels,device}.css +pages/tools/{base,qr,main}.css +pages/drive.css +components/nav_hud.css responsive.css -vendor CSS +vendor/plyr.css ``` -JavaScript is loaded in this shape: +JavaScript is loaded in this order: ```text -vendor/* -translations/* -shared/* -shared/ui/* -pages/* -pages/logs/* -realtime/* +vendor/{plyr.min,qrcode-generator,jsQR}.js +translations/{registry,ko,en,zh}.js +realtime/hud_card.js +shared/{constants,dom,utils,i18n,api,setting_diff,activity}.js +shared/ui/{focus_trap,dialog,viewport,effects,navigation}.js +pages/car.js +pages/setting*.js +pages/tools*.js +pages/branch.js +pages/logs/*.js +pages/terminal.js +realtime/{raw_capnp,vision_state,vision_rtc,vision_raw,app_realtime,vision_diag,carrot_map,nav_hud}.js +pages/vision_background.js +realtime/home_drive.js app.js ``` +Asset URLs carry `?v=` cache-busting query strings; bump the version when a file changes. + ## Page Reference | Page | HTML | JS | CSS | Backend | |---|---|---|---|---| -| Drive/Home | `pageCarrot`, `driveHudCard`, `rtcVideo` | `realtime/*`, `vision_background.js` | `pages/drive.css`, `hud_card.css` | `features/system.py`, `features/ws.py`, `features/stream.py`, `realtime/transports/*` | +| Drive/Home | `pageCarrot`, `driveHudCard`, `carrotNavHud`, `rtcVideo` | `realtime/*`, `vision_background.js` | `pages/drive.css`, `hud_card.css`, `components/nav_hud.css` | `features/system.py`, `features/ws.py`, `features/stream.py`, `features/vision_diag.py`, `realtime/transports/*` | | Setting | `pageSetting` | `setting.js`, `setting_device*.js`, `car.js` | `pages/settings/*` | `features/settings.py`, `features/params.py`, `features/system.py`, `features/setting_*` | | Tools | `pageTools` | `tools.js`, `tools_notifications.js`, `tools_web_settings.js`, `tools_settings_qr.js`, `branch.js` | `pages/tools/*` | `features/tools/*`, `features/system.py`, `features/params.py`, `features/web_settings.py` | | Logs | `pageLogs` | `pages/logs/shared.js`, `dashcam.js`, `screenrecord.js` | `pages/logs.css` | `features/dashcam/*`, `features/screenrecord/*` | -| Terminal | `pageTerminal` | `terminal.js` | `pages/terminal.css` | `features/terminal.py`, `services/tmux.py` | +| Terminal | `pageTerminal` | `terminal.js` | `pages/terminal.css` | `features/terminal.py`, `services/tmux.py`, `terminal_commands/*` | | Car Select | `pageCar`, `appCarPicker` | `car.js` | `layout.css`, `components.css` | `features/cars.py`, Params | | Branch Select | `pageBranch`, `appBranchPicker` | `branch.js` | `components.css`, `pages/tools/*` | `features/tools/*` | @@ -459,7 +532,7 @@ openpilot messaging/cereal -> server/live_runtime/* -> features/system.py /api/live_runtime -> web/js/realtime/app_realtime.js - -> web/js/realtime/hud_card.js + -> web/js/realtime/hud_card.js + nav_hud.js -> web/js/realtime/home_drive.js ``` @@ -473,6 +546,14 @@ openpilot camera encode data -> pageCarrot video/canvas ``` +Vision diagnostics: + +```text +web/js/realtime/vision_diag.js (records RTC/video stats) + -> /api/vision_diag/server_snapshot (features/vision_diag.py) + -> /api/vision_diag/upload_discord -> services/vision_diag.py +``` + ### Setting ```text @@ -518,6 +599,15 @@ services/git_status.py -> tools.js refreshGitPullStatus() ``` +Auto update (no browser needed): + +```text +server/app.py on_startup + -> services/auto_update.py auto_update_loop + -> git_status (behind?) -> hard reset + git pull + -> cweb_push notify (best effort) +``` + ### Logs ```text @@ -541,7 +631,7 @@ dashcam.js web/js/pages/terminal.js -> /ws/terminal -> features/terminal.py - -> services/tmux.py + -> services/tmux.py (+ terminal_commands/*) ``` ### Branch / Git @@ -557,9 +647,10 @@ web/js/pages/branch.js | Need | File | |---|---| | Server startup | `carrot_server.py` | -| App wiring | `server/app.py` | +| App wiring / background tasks | `server/app.py` | | Route registration | `server/features/__init__.py` | | Static/bootstrap payload | `server/features/static.py` | +| Backend paths/constants | `server/config.py` | | Page HTML | `web/index.html` | | Page switching | `web/js/shared/ui/navigation.js` | | Final frontend boot | `web/js/app.js` | @@ -574,12 +665,18 @@ web/js/pages/branch.js | Tools backend actions | `server/features/tools/dispatcher.py` | | Tool job state | `server/features/tools/jobs.py` | | Git status polling | `server/services/git_status.py` | +| Auto update loop | `server/services/auto_update.py` | | Drive realtime UI | `web/js/realtime/*` | +| Nav HUD / minimap | `web/js/realtime/nav_hud.js`, `web/js/realtime/carrot_map.js` | +| Vision diagnostics | `web/js/realtime/vision_diag.js`, `server/features/vision_diag.py` | | Drive backend data | `server/features/system.py`, `server/live_runtime/*` | | Raw WebSocket | `server/features/ws.py`, `realtime/transports/raw_ws.py` | | Camera WebSocket | `realtime/transports/camera_ws.py` | | Logs UI | `web/js/pages/logs/*` | | Dashcam backend | `server/features/dashcam/*` | | Screenrecord backend | `server/features/screenrecord/*` | -| Terminal UI/backend | `web/js/pages/terminal.js`, `server/features/terminal.py` | +| Terminal UI/backend | `web/js/pages/terminal.js`, `server/features/terminal.py`, `server/terminal_commands/*` | +| Translations | `web/js/translations/*` | | Recovery server | `recovery/server.py` | + + diff --git a/selfdrive/carrot/web/css/components.css b/selfdrive/carrot/web/css/components.css index 4a4cf5fb91..f27eb4dfb7 100644 --- a/selfdrive/carrot/web/css/components.css +++ b/selfdrive/carrot/web/css/components.css @@ -805,104 +805,6 @@ body[data-page="terminal"] .app-toast-host { font-family: var(--font-mono); } -/* ── Setting Subnav ───────────────────────────────────────── */ -.setting-subnav-wrap { - margin: 0 0 var(--sp-md); - touch-action: pan-y; - position: sticky; - top: 0; - z-index: 18; - padding-top: clamp(8px, 1.8vw, 12px); - background: var(--md-surface); - isolation: isolate; -} - -.setting-subnav { - --setting-subnav-tab-width: calc((100% - var(--sp-sm) - var(--sp-sm) - var(--sp-sm) - var(--sp-sm)) / 5); - display: flex; - gap: var(--sp-sm); - justify-content: flex-start; - overflow-x: auto; - overscroll-behavior-x: contain; - scrollbar-width: none; - padding: 0 0 10px; - border-bottom: 1px solid color-mix(in srgb, var(--md-outline-var) 34%, transparent); - scroll-snap-type: x mandatory; -} - -.setting-subnav-wrap:not(.is-scrollable) .setting-subnav { - justify-content: center; -} - -.setting-subnav::before, -.setting-subnav::after { - content: ""; - flex: 0 0 calc((100% - var(--setting-subnav-tab-width)) / 2); -} - -.setting-subnav-wrap:not(.is-scrollable) .setting-subnav::before, -.setting-subnav-wrap:not(.is-scrollable) .setting-subnav::after { - flex-basis: 0; -} - -.setting-subnav::-webkit-scrollbar { - display: none; -} - -.setting-subnav__tab { - flex: 0 0 var(--setting-subnav-tab-width); - appearance: none; - min-height: 34px; - border: 1px solid color-mix(in srgb, var(--md-outline-var) 44%, transparent); - border-radius: 8px; - background: var(--md-surface-cont); - color: var(--md-on-surface-var); - padding: 7px 9px; - font-size: 12.5px; - font-weight: 800; - cursor: pointer; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-align: center; - scroll-snap-align: center; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); - transition: background 0.14s ease, border-color 0.14s ease, color 0.14s ease, transform 0.12s ease; -} - -.setting-subnav__tab:not(.is-active) { - color: var(--md-on-surface-var); -} - -.setting-subnav__tab:hover, -.setting-subnav__tab:focus-visible { - border-color: color-mix(in srgb, var(--md-primary) 36%, var(--md-outline-var)); - background: color-mix(in srgb, var(--md-surface-cont-h) 90%, var(--md-primary)); - color: var(--md-on-surface); - outline: none; -} - -.setting-subnav__tab.is-active { - border-color: color-mix(in srgb, var(--md-primary) 48%, var(--md-outline-var)); - background: var(--md-primary-state); - color: var(--md-primary); - font-weight: 850; -} - -.setting-subnav__tab:active { - background: color-mix(in srgb, var(--md-surface-cont-hh) 88%, var(--md-primary)); - color: var(--md-on-surface); - transform: translateY(1px); -} - -.setting-back-swiping .setting-subnav { - scroll-snap-type: none; -} - -.setting-back-swiping .setting-subnav__tab { - scroll-snap-align: none; -} - /* ── Group Buttons (list items) ───────────────────────────── */ .groupBtn { width: 100%; diff --git a/selfdrive/carrot/web/css/pages/settings/device.css b/selfdrive/carrot/web/css/pages/settings/device.css index 47c943c555..4e4cd94984 100644 --- a/selfdrive/carrot/web/css/pages/settings/device.css +++ b/selfdrive/carrot/web/css/pages/settings/device.css @@ -112,10 +112,6 @@ pointer-events: none; } -.page--setting .setting-subnav__tab--favorites { - color: color-mix(in srgb, #bae6fd 82%, var(--md-on-surface-var)); -} - @media (min-width: 769px) { .setting-search-panel { --setting-search-form-width: clamp(360px, 34vw, 540px); @@ -128,67 +124,6 @@ } @media (max-width: 640px) { - .page--setting .setting-subnav-wrap { - margin-bottom: 0; - top: 0; - padding-top: calc(8px + env(safe-area-inset-top, 0px)); - padding-bottom: 18px; - background: var(--md-surface); - border-bottom: 1px solid color-mix(in srgb, var(--md-stroke-soft) 72%, transparent); - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.14); - } - - .page--setting .setting-subnav-wrap::after { - display: none; - } - - .page--setting .setting-subnav { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 8px; - justify-content: stretch; - overflow: visible; - padding: 0; - border-bottom: 0; - scroll-snap-type: none; - } - - .page--setting .setting-subnav::before, - .page--setting .setting-subnav::after { - display: none; - } - - .page--setting .setting-subnav__tab { - flex: none; - min-height: 38px; - padding: 7px 6px; - border: 1px solid color-mix(in srgb, var(--md-outline-var) 44%, transparent); - border-radius: 8px; - background: var(--md-surface-cont); - color: var(--md-on-surface-var); - font-size: 12.5px; - font-weight: 800; - line-height: 1.15; - white-space: normal; - text-wrap: balance; - scroll-snap-align: none; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); - } - - .page--setting .setting-subnav__tab.is-active { - color: var(--md-primary); - border-color: color-mix(in srgb, var(--md-primary) 48%, var(--md-outline-var)); - background: var(--md-primary-state); - } - - .page--setting .setting-subnav__tab:active { - background: color-mix(in srgb, var(--md-surface-cont-hh) 88%, var(--md-primary)); - } - - .page--setting #settingSubnavWrap { - box-sizing: border-box; - } - .page--setting .settingTop { flex-direction: column; align-items: stretch; @@ -299,13 +234,6 @@ mask-image: linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 6px), transparent 100%); } - .page--setting #settingSubnavWrap { - display: none !important; - } - - .page--setting #settingSubnavWrap::after { - display: none; - } } @media (max-height: 760px) { @@ -426,10 +354,6 @@ overflow: hidden; } - .page--setting.setting-layout-split #settingSubnavWrap { - display: none !important; - } - .page--setting.setting-layout-split #groupList { display: flex; flex-direction: column; @@ -1324,7 +1248,6 @@ transform: translateY(1px); } -.page--setting #settingSubnav[hidden], .page--setting #carrotTabContent[hidden], .page--setting #deviceTabContent[hidden], .page--setting #items[hidden], @@ -1336,12 +1259,6 @@ display: none; } -/* The device tab has no top quick-tab subnav (old, unused). Hide the subnav - wrap on the device tab so no empty bar shows at any width / adaptive layout. */ -.page--setting.setting-tab-device #settingSubnavWrap { - display: none !important; -} - .page--setting #deviceItems .ctrl { display: flex; grid-template-columns: none; diff --git a/selfdrive/carrot/web/css/pages/settings/panels.css b/selfdrive/carrot/web/css/pages/settings/panels.css index 0f56c990b5..1d1cd08463 100644 --- a/selfdrive/carrot/web/css/pages/settings/panels.css +++ b/selfdrive/carrot/web/css/pages/settings/panels.css @@ -313,10 +313,6 @@ animation: setting-profile-section-fold 0.24s cubic-bezier(.2, 0, 0, 1) reverse both; } -.setting-subnav__tab--profile { - border-color: color-mix(in srgb, var(--md-primary) 34%, var(--md-outline-var)); -} - .setting-profile-panel { --setting-profile-accent: var(--md-primary, #ffab66); --setting-profile-ink: var(--md-on-surface); diff --git a/selfdrive/carrot/web/css/tokens.css b/selfdrive/carrot/web/css/tokens.css index 87ed08460b..923cfbb4b2 100644 --- a/selfdrive/carrot/web/css/tokens.css +++ b/selfdrive/carrot/web/css/tokens.css @@ -207,7 +207,7 @@ layering must come from this scale. --z-base in-flow content - --z-sticky sticky headers, subnav + --z-sticky sticky headers --z-rail side nav rail --z-nav bottom nav bar (matches existing topbar z:120) --z-fab floating action buttons diff --git a/selfdrive/carrot/web/index.html b/selfdrive/carrot/web/index.html index 033a1f3887..fac7bdb5c2 100644 --- a/selfdrive/carrot/web/index.html +++ b/selfdrive/carrot/web/index.html @@ -89,17 +89,17 @@ background: color-mix(in srgb, var(--md-primary) 14%, transparent) !important; } - + - + - - + + @@ -212,9 +212,6 @@