Fix/ux UI issues#21
Merged
Merged
Conversation
- #7 numpad hotkeys: emit canonical W3C codes (NumpadSubtract etc.) the global-hotkey crate accepts; old short tokens (numsub/nummult/ numdiv/numdec/NumpadEnter->Enter) failed to register and silently reverted. Right-Alt: detect held modifiers by event.code so AltGr (key AltGraph) no longer reads as a bad main key. - #6 re-applying an identical hotkey: idempotent register + a re-apply window event so a same-value re-record re-claims the binding; recorder shows an applied confirmation. - #17 close ConfirmDialog when the overlay locks. - #20 dismiss the RMB transparency menu on lock and on window blur. - #22 Enter key saves the Tarkov paths form. - #23 clamp the overlay onto a visible monitor at startup when the window-state plugin restored off-screen coords (2K -> FHD). Adds hotkey.spec.ts (18 cases) cross-checking emitted tokens against the global-hotkey 0.7.0 parser table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The OS keeps every registered shortcut live during capture, so pressing an already-bound combo fired its action and the OS swallowed the keystroke before the webview saw it. That made three things impossible: binding a combo that is already taken (e.g. the lock combo), re-recording the identical combo (the keypress never reached the recorder, so nothing saved), and capturing right-Alt combos that collide with a default Ctrl+Alt binding on AltGr layouts. The recorder now brackets capture with suspend/resume window events: suspend unregisters every live shortcut, resume re-claims them all (which also re-applies an unchanged re-record). Replaces the earlier reapply- event hack, which never ran because capture itself was being blocked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The suspend/resume change introduced a regression: recording a new combo updates the ref (firing the change-watch) AND triggers resume, and both called tryRegister for the same combo concurrently. The second register failed with an already-registered error, the watch took its failure path, and reverted the value the user just set — so no hotkey could be saved. Register/unregister now run through a per-instance promise queue, so the watch's run sees the resume's registration and short-circuits idempotently instead of double-registering. The revert is also gated on the combo not having ended up registered, as a second guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Console logs from a Russian layout confirmed right Alt arrives as
key="AltGraph" (code "AltRight") plus a synthetic LeftControl, with the
altKey/ctrlKey flags unreliable on the event. Windows global shortcuts
have no distinct "right Alt" modifier — AltGr is delivered as Ctrl+Alt —
so capture now keys off getModifierState('AltGraph') and emits
CommandOrControl+Alt+<key>, which actually fires when right Alt is pressed.
Also removes the green-ring + check "applied" flash from the recorder
(stylistically excessive); the chip already updates to the new combo, and
the same-value re-record is re-claimed by the resume path regardless.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A Ctrl+Alt bind captured from AltGr on a Russian layout silently stops firing if the player switches to an English layout mid-game, where the same physical right-Alt key is a plain Alt with no Ctrl. Strip the synthetic Ctrl that AltGr injects and record just Alt, so the bind is layout-stable. Windows global shortcuts can't distinguish left/right Alt anyway, so plain Alt is the honest, portable representation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Right Alt on AltGr layouts (Russian etc.) is delivered by the OS as
Ctrl+Alt, so any bind made with it fires inconsistently across layouts —
it simply doesn't work while on the Russian layout. Rather than guess a
mapping, refuse to bind it: when getModifierState('AltGraph') is set the
recorder shows a clear message and waits for a different combo.
AltGraph is set only by a real AltGr, not by a manual left-Ctrl+left-Alt,
so genuine Ctrl+Alt combos (incl. the lock/airdrop defaults) are
unaffected — covered by a test.
Adds the hotkeys.altgr message (en + ru); restart vite dev to pick up the
new locale string (the i18n plugin pre-compiles JSON, no HMR).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- #11 SelectButton fluid: swap class="w-full" for the PrimeVue `fluid` prop across Player/Overlay/Language/Extracts settings so the option buttons actually stretch to fill the row (w-full only stretched the wrapper). Sliders keep w-full. - #16 first-launch language: default to the system/browser language (navigator.language ~ "ru" -> ru, else en) instead of hardcoded en. Only used when nothing is persisted; a manual choice still wins. - #12 drag handle: a dedicated top-left pi-bars grab handle on the overlay so dragging isn't a hidden affordance on the status pill. Tauri + unlocked only; title/aria from new i18n overlay.move. - #14 animated border: replace the static solid edge with a dashed marching-ants stroke (OverlayBorder.vue → SVG, teleported to body so the opacity slider can't dim it; stroke-dashoffset keyframe, seamless loop, prefers-reduced-motion guard, relative-color fallback). Removes the now-dead overlay-unlocked class toggling from useOverlayBootstrap. Restart vite dev to pick up the new overlay.move locale string (the i18n plugin pre-compiles JSON, no HMR). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The marching-ants border had a visible seam at the top-left (the path start): the rounded-rect perimeter isn't an integer multiple of the 14px dash period, and it changes with the resizable window, so the last dash never met the first. Give the rect pathLength="100" and express the dash + offset in those normalized units (0.5+0.5 period → exactly 100 dashes, offset -1 = one period). The pattern now divides the perimeter evenly and closes without a seam at any window size. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the top-left pi-bars handle with a top-center grabber: a tiny always-visible nub (when unlocked) that expands on hover into a bar showing the map name, and which is itself the drag region. Keeps the map view clean by default while making "draggable" discoverable, and gives a large, obvious grab target. Pure CSS group-hover reveal; same startDragging() call. The map name moves out of the top-right pill into the drag bar; the right cluster is now a compact status dot + gear + close. Browser mode (no window drag) keeps the status+map-name pill as before. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two follow-ups to the hover-reveal drag bar: - Make it full-width instead of a centered pill. The entire top strip is the drag region, so the window can still be grabbed back when it has been dragged mostly past a screen edge (a centered handle could end up off-screen and unreachable). A fixed-height top zone keeps the hover target comfortable; the visible bar is a faint idle line that expands to a labelled bar. - Keep the bar expanded while dragging. The OS move loop steals pointer events the instant startDragging() runs, dropping :hover and collapsing the bar mid-drag. Track a `dragging` flag (set on mousedown, cleared on mouseup or the first button-less mousemove) so the bar stays open for the whole drag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drag affordance reworked from the full-width bar (which the right-hand status/settings/close controls overlapped, and which fused with the dashed border): - The visible part is an airy pill floating below the top edge, centred so it never collides with the right controls, with a ring + shadow so it reads as floating rather than blending into the border. It grows from a grabber into a bigger labelled bar (h-8, text-sm). - The drag region stays full-width (invisible) so the window is still grabbable when dragged mostly past a screen edge; hover/expand is scoped to the centre so reaching for the controls doesn't trigger it. - Manual window listeners replaced with VueUse useEventListener (auto teardown); the bar still stays open for the whole drag via `dragging`. Settings drawer: when the overlay is small the drawer opens full-screen, so there's no outside to click-dismiss and Esc is non-obvious. Added a prominent close button in a custom header (closable=false). Adds a `close` locale string (en + ru) and uses it for the overlay close button too. Restart vite dev to pick up the new strings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rome - The settings drawer showed two close buttons: PrimeVue 4's Drawer prop is `showCloseIcon`, not `closable`, so `:closable="false"` was ignored and the built-in icon rendered alongside the custom header button. Use `:show-close-icon="false"` so only the prominent custom close remains. - Add `showOverlayChrome` (shared/tauri.ts): a DEV-only flag that renders the Tauri overlay chrome (drag bar, animated border, lock indicator) in a plain browser so the overlay UX can be previewed/iterated without a Tauri build. Enable with `?overlay` or localStorage. It only flips render gates — native window calls still guard on the real `isTauri` (OverlayHeader's startDrag), and the IPC transport is untouched, so nothing tries to reach a Tauri runtime that isn't there. OverlayHeader's render prop is renamed `isTauri` -> `tauriChrome` to make the split explicit; index.vue feeds it `showOverlayChrome`. Verified in the browser preview: airy centred drag pill expands on hover with no overlap of the right controls, animated border, lock indicator, and a single drawer close button all render correctly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drawer: drop the custom header + close button and go back to PrimeVue's built-in close (the duplicate close came from recreating it). The default X + Esc are enough. - Drag bar: the expanded bar is now full-width (unfurls from a centred grabber to a near-full-width title bar), and the hover trigger spans the full width of the top, not just the centre. The idle grabber is shorter (h-1.5). It stays full-width-grabbable for off-screen recovery and open while dragging. - No control overlap: the bar is tall enough (h-11) to fully contain the right-hand status/settings/close controls, which sit on top of it (z-1001) like title-bar controls instead of half-overlapping it. Verified in the browser preview (?overlay): idle short grabber, full- width unfurl on hover with controls cleanly seated on the bar, and a single drawer close button. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Following a UX design review, stop treating the drag bar as a container for the window controls (the root of every overlap iteration). The top band is now a single hover/drag trigger that reveals two SEPARATE, never-overlapping zones as flex siblings: - left: a drag pill (flex-1) carrying the map name — visual only, the band owns the drag so it stays grabbable full-width for off-screen recovery; - right: the status/settings/close control cluster (shrink-0, own pointer events, mousedown.stop so it never starts a drag). Being flex siblings, they can't collide at any width. Idle shows only a small centred grabber nub; hover/drag cross-fades to the revealed chrome (controls auto-hide together with the bar, per the chosen direction); locked shows just the connection dot; browser keeps its static cluster. Verified in the browser preview (?overlay): clean idle nub, full-width reveal with a clear gap between the drag pill and controls, no overlap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Changed the drag pill icon from 'pi-bars' to 'pi-arrows-alt' to better represent the drag functionality. This update enhances the visual clarity of the overlay header while maintaining the existing layout and behavior.
…touch floors - #4 Auto-follow without zoom: add an "On" mode that recenters on every position via panTo() and keeps the user's current zoom; S/M/L keep the recenter+zoom behaviour. Enum gains 'on' (superset — existing saved values stay valid), with the new option + clarified hint in en/ru. - #5 Looser map panning: bump PAN_PAD 0.15 -> 0.5 and soften maxBoundsViscosity 1.0 -> 0.5 so dragging the map doesn't hit a rigid wall. - #15 Lock pins on top: the effective always-on-top is now alwaysOnTop || clickThrough, so locking keeps the overlay visible out of raid and unlocking restores the user's setting. - #10 Floor switcher on touch: on `pointer: coarse` devices the floor buttons drop the small size and get >=44px tap targets with more gap. Restart vite dev to pick up the new playerFollowOptions.on locale string. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show both in-game clocks (left + the +12h right) as a small, non- interactive chip in the top-left corner — visible even when the overlay is locked, since the time is glanceable raid info like the map itself. Math is a pure function in @shared/tarkov-time (Tarkov runs at 7× real time, anchored to Moscow UTC+3, two clocks 12h apart — the canonical tarkov.dev formula), unit-tested with 4 cases. The chip ticks once a second from Date.now(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Zoom, floor switching and the airdrop trigger now also respond to the keyboard in a plain browser / LAN phone, not just the Tauri overlay. useGlobalShortcut stays Tauri-only (OS global shortcut); the new useBrowserShortcut is its page-level counterpart, firing the same store combos via a window keydown listener — no-op under Tauri to avoid double-firing, ignores keystrokes typed into form fields, and preventDefaults a match so combos like Ctrl+= don't also zoom the page. Matching is a pure `matchesAccelerator(event, combo)` in the hotkey lib (CommandOrControl matches Ctrl or Meta; other modifiers exact), unit- tested. index.vue binds each map action to both transports via a small helper. Lock stays overlay-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The clock chip overlapped the full-width drag bar when the top header expanded on hover. Drop it from top-3 to top-14 (just below the h-12 header band) so it never collides — still upper-left and always visible. Verified in the browser preview. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Instead of pinning the clock low, let it float in the top-left corner (top-3) and slide down to top-14 only while the drag-bar header is expanded, then back up when it collapses — so it uses the corner when free and gets out of the way when the header appears. Adds a shared app-singleton useOverlayHeaderActive (hovered/dragging/ active) owned by OverlayHeader (reset on lock/unmount so it can't stick), read by the clock to animate its `top`. Verified in the preview: corner at rest, smooth slide to below the header on hover, back on leave. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The clock animated `top` (layout) while the header reveals via transform/opacity (composited), so the two motions drifted. Slide the clock with translate-y (translate-y-11 = the 44px to top-14) instead, so both are composited transforms on the same 200ms ease-out and move in lockstep. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lets the in-process HTTP server + watchers run standalone on :47474 so a browser / LAN phone can connect (SSE, config) without launching the overlay — handy for testing the browser-side features, and the server half of the tray/headless story. Makes the Tauri AppHandle optional through the watcher chain (screenshots/logs/watcher/http_server/commands/lib): events always go to the broadcast channel (SSE), and `app.emit` to the webview only when a handle is present. The GUI path is unchanged (passes Some). Adds `run_headless()` + a second binary `tarkov-checker-headless` (no windows_subsystem, keeps a console) and a `backend:dev` pnpm script. Verified by running the binary: GET /api/ping and /api/config both 200 with the resolved paths — tauri::async_runtime works fine with no app. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The browser shortcuts (#8) worked, but the settings section to see/ configure them was tauri-only — so a browser user couldn't tell what the combos were or change them. Make the section visible with `desktop-or-tauri` (desktop browser + overlay, hidden on phones since they have no keyboard); the browser uses the same combos via useBrowserShortcut. The lock recorder stays overlay-only (no window to lock in a browser). Verified in the preview: at >=640px the Hotkeys section renders with the 5 keyboard-relevant bindings (zoom x2, floor x2, airdrop) and no lock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The backend registers the five forwarded combos (zoom-in/out, floor-up/down, airdrop) as OS-global shortcuts and broadcasts a `command` SSE event, so the overlay, any browser, and LAN phones all react regardless of focus. Combos persist in hotkeys.json and are editable from any client via /api/hotkeys. The overlay lock stays client-registered (recovery path). Drops the focus-only useBrowserShortcut. - shared: commandMessage in the SSE union + hotkeys-api schema - backend: HotkeyController trait (TauriHotkeys via the plugin, StandaloneHotkeys via its own Win32 message pump in headless), HotkeyStore, /api/hotkeys GET/PUT + suspend/resume, command event - client: hotkeys store is a thin backend sync layer, command dispatch in index.vue, useHotkeysSync (load + recorder suspend/resume bridge) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fy refs - CLAUDE.md: new "Backend-owned hotkeys" section + route/store updates - README (root EN+RU), client/desktop READMEs: the LAN/phone interface is served by the in-process Rust helper, not the removed Node/Fastify server - desktop README: replace the obsolete "out of scope" list with current capabilities, fix beforeDevCommand, note the client-side tray Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Opt-in, off by default. When zoomed in, a small faction-coloured arrow sits on the viewport edge for each off-screen extract, pointing at it. Rendered in an overlay div over the Leaflet container (not a pane) so the arrows stay pixel-fixed while panning; recomputed on move/zoom. Toggle in Settings -> Extracts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply env(safe-area-inset-*) via .sa-* helpers to the clock, top clusters, lock indicator and floor switcher so the iPhone notch / Dynamic Island / home indicator / rounded corners don't clip them. viewport-fit=cover was already set in index.html. Insets are 0 on desktop, so positions are unchanged there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A teleported context menu (same pattern as MapQuickMenu) listing all visible maps with the current one checked. Wired on the overlay drag band and the browser status pill; skipped on narrow phone viewports. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a thick dark outline (paint-order: stroke) and bump the arrow to 22px with a stronger drop-shadow. The thin filled arrows blended into the busy map; the outline makes them legible on any background. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- The clock now sits in a 40px row (= the settings button height) so its centre lines up with the status/settings cluster across the top. - Root height uses dvh instead of vh so iOS Safari's dynamic bottom bar no longer clips the floor switcher in portrait (landscape was already fine). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reorganize the settings Drawer into two tabs — Layers (map/extracts/player/ airdrop) and Settings (overlay/hotkeys/language/paths/pairing) — each a PrimeVue Accordion of collapsible sections instead of a flat Fieldset stack. - registry: SectionGroup is now layers|settings; sections carry a titleKey for the accordion header (the per-section Fieldset legend is dropped). - SettingsPanel: Tabs + per-tab Accordion (multiple). Expanded panels persist per tab; desktop opens all by default, mobile starts collapsed to keep the drawer short. - sections: drop the Fieldset wrapper and render bare content. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
) The settings drawer is now non-modal so the map stays bright and interactive behind it — toggling a layer (extracts/labels/follow/edge arrows) previews on the map in real time instead of being hidden behind a dimming mask. On phones the drawer becomes a bottom-sheet: auto height that hugs its content (capped at 85dvh with internal scroll, rounded top) so the map peeks above and the live preview stays visible. Desktop keeps the right-side panel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an opt-in "minimize to tray" overlay setting. When enabled, the ✕ button hides the window to the system tray and keeps the app running (no confirm, since it's reversible) instead of quitting; the tray's Show restores it and Quit exits. Default off keeps the ✕ as a confirmed quit. - overlay store: minimizeToTray persistedRef (tc.overlay.minimizeToTray). - useCloseConfirm: branch to window.hide() when the flag is on. - OverlaySection: toggle + hint; i18n keys (en/ru). - capabilities: grant core:window:allow-hide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the settings-drawer Layers tab with an on-map LayerRail; the gear drawer now holds system settings only. Make the overlay's lock state coherent: controls hide, glanceable read-outs stay. - LayerRail (left edge): category icons (Karta/Igrok + dimmed future Loot/ Quests) open flyouts; per-layer visibility toggle + the layer's section inline via a gear. Flyout anchored to the rail (no fixed/Teleport) so it doesn't drift in the WebView2 overlay. - Per-layer visibility primitive: useLayerVisibility (tc.layer.<id>.visible), watched by the extracts/player/airdrop composables; MapLayerContext gains visible. - Settings registry: group settings -> system, add subgroup (player/loot/quests); SettingsPanel drops the Tabs/Accordion layers tab and renders system sections only. - Floors: stepper moved into the rail bottom; Alt+wheel over the map steps floors (captured before Leaflet zoom, throttled); a read-only floor-by-wheel hotkey row + a locked-state floor read-out chip. - Map section: dropdown -> inline Listbox behind an auto-switch disclosure (no overlay flip in the 360px flyout). Player follow simplified to on/off. - Hotkey rows: combo chip + Change button on one line; register the PrimeVue Tooltip directive. - Edge arrows wrap the rail and re-flow on lock; merged clock+location pill stays glanceable in every state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the docs current with the overlay redesign committed in dcb1345: settings split into the on-map LayerRail (layers) + a system-only gear drawer; per-layer visibility (tc.layer.<id>.visible); floors moved into the rail + Alt+wheel; coherent lock state (controls hide, read-outs stay) with the merged clock+location pill; player follow simplified to on/off; edge arrows wrap the rail. Also folds in earlier audit fixes (0.0.0.0 bind, minimize-to-tray, close behaviour). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… cleanup From the architecture + code review of dcb1345: - useLayerVisibility: create the per-layer persistedRefs in a DETACHED effectScope so each one's localStorage watch survives MapView's `:key` remount on map switch. Previously the watch was captured by MapView's setup scope and died after the first map switch, silently stopping visibility persistence (real regression in a user-facing setting). - Floors: rename nextFloor/prevFloor -> floorUp/floorDown and CLAMP (no wrap-around). Up now means a higher floor everywhere - the floor-up hotkey and the rail's up button were moving in opposite directions, and the hotkey wrapped while the rail clamped. - Remove dead FloorSwitcher.vue (replaced by the in-rail floor stepper). - Drop the orphaned settingsGroups.system i18n key (en/ru). - CLAUDE.md: restore useFloorSwitcher (+ useLayerVisibility) in the composables list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Eliminate the dual-registration smell: a layer lived in BOTH the map-layer
registry and the settings-section registry (group 'layers'), linked only by a
matching string id. The map-layer registry is now the single source of truth -
each layer self-describes its rail category, order, title and inline settings:
registerMapLayer({ id, mount, category, order, titleKey, settingsComponent })
- LayerRail reads useMapLayers() and derives categories from each layer's
`category` (CATEGORY_META is now just icon/teaser metadata, not the catalog);
the base map selector is a deliberate direct MapSection import.
- Settings registry is system-only now: dropped group/subgroup, and
useSettingsSections() takes no argument.
- Removed features/map/settings.ts and features/airdrop/settings.ts - their
registrations moved into the layer index.ts files.
- useLayerVisibility keys off the one registry's ids.
Verified in preview: rail categories/order/toggles, live show-hide (persisted),
base-map flyout, system drawer. typecheck + lint clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tore (arch review #2) - New useRailObstacle: LayerRail publishes its rect (viewport coords; null when hidden) to a shared reactive singleton; edge-indicator layers consume it. - useEdgeIndicators takes a getObstacle() callback instead of document.querySelector('.layer-rail'). - useExtractsLayer no longer imports the overlay store: it reads the rail rect and repaints on change, replacing the clickThrough-driven rAF loop + the magic 260ms transition timer. The rail owns its lock/transition - it clears the obstacle immediately on lock and republishes after the enter transition. Future edge-indicator layers (loot/quests) reuse useRailObstacle - no copy of the DOM scrape or the overlay coupling. Verified: left-edge arrows still wrap the rail (x=57 = railRight 41 + 16). typecheck + lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arch review #3) The controls-hide / read-outs-stay lock policy was re-derived (!clickThrough) in every chrome component and threaded as a prop through OverlayHeader / OverlayLockIndicator. Centralize it: - New useOverlayLock(): locked / showControls (derived) + lock() action. - LayerRail, OverlayHeader, OverlayLockIndicator and pages/index.vue read the derived state from it instead of the store directly; dropped the overlay-click-through prop and the lock emit (the button calls lock() itself). App.vue keeps the raw ref - it owns the hotkey toggle + boot reset. One definition of the policy, no prop-drilling - cheaper to extend as chrome grows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…registry (arch review #4) Pin the contracts the scaling refactor introduced: - useLayerVisibility: default-visible, singleton-per-id, persists to tc.layer.<id>.visible, reads an existing value on first use. - useFloorSwitcher: floorUp/floorDown direction + clamp (no wrap), default-floor start, single-floor no-op. - map-layer registry: register/expose + HMR-safe replace-by-id. 110 tests pass; typecheck + lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Layers now live in ONE registry (registerMapLayer carries category/order/ titleKey/settingsComponent) and the settings registry is system-only. Update CLAUDE.md (Settings & layer registries + Map rendering layers) and apps/client/README (recipes + where-things-connect): drop the layers group/subgroup from the settings registry, note useRailObstacle + useOverlayLock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Browser/phone-only Display settings section plus an on-map fullscreen control for the second-screen phone use case. - Fullscreen button in the top-right cluster (mobile/touch browser only); iOS Safari has no Fullscreen API, so it shows an Add to Home Screen popover instead. Hidden once installed as a standalone PWA. - Keep screen awake (default on): Screen Wake Lock API in secure contexts, with a self-contained muted-video fallback for insecure LAN HTTP (the phone case). No nosleep.js dependency -- the proven MIT clips are embedded in-repo and driven by useNoSleepVideo. - PWA manifest + iOS meta tags for Add to Home Screen. - New browser settings-section visibility (!isTauri); Display at order 25. Reviewed by architect and code-review agents; wake-lock state-machine and denied-status fixes folded in. Verified: typecheck, lint, 110 tests, live mobile preview (fullscreen, keep-awake status, video playback). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On iOS 15 (Safari < 16.4) the map overlay layout broke on a real phone: the page could scroll, which let Safari's bottom toolbar retract and swell dvh, and the vertically-centred LayerRail + its flyout landed off-centre. Two root causes, both iOS-specific: - A scrollable body let the toolbar toggle, making 100dvh unstable. Lock the app shell (html/body/#app overflow:hidden + overscroll-behavior:none) and size the root with the stable 100%/svh chain (h-dvh -> h-full). - Tailwind v4 translate utilities rely on @property-registered vars, which Safari < 16.4 ignores, so -translate-y-1/2 produced an invalid translate declaration and centring silently failed. Replace it with a literal transform: translateY(-50%) on the rail and flyout. Also switch the rail flyout / settings drawer max-heights from dvh to svh so they stay stable under the locked toolbar. Diagnosed and verified on an iPod touch 7 (iOS 15.8) via a temporary viewport-metrics overlay (since removed): the rail now centres at the viewport midpoint with no page overflow or scroll. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…seconds Mobile/phone UX pass. - Top bar: fold the connection-status dot, the map name (>=380px) and the two in-game clocks into the always-visible left chip (TarkovTimeChip). The top-right browser cluster is now just the settings gear, so the bar no longer overflows on a 320px phone (iPod touch). Drop the clock icon. - Clock: show seconds, sampled via requestAnimationFrame so they tick smoothly (in-game time runs 7x, so a fixed interval visibly stutters them); add the seconds field to @shared/tarkov-time. - Remove the keep-awake feature entirely. There is no reliable web way to keep a mobile screen awake over plain HTTP: the Screen Wake Lock API needs a secure context (absent on iOS < 16.4, unreachable for a LAN phone) and the muted/unmuted looping-video trick no longer keeps the screen on under current iOS or Android (verified on iPod touch iOS 15 + Android). Deletes useKeepAwake, useNoSleepVideo, the embedded video asset and the display store. The Display settings section now holds only the fullscreen toggle (iOS shows an Add-to-Home-Screen hint). - Remove the on-map fullscreen button; fullscreen lives only in Display settings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show the hotkeys settings section on phones (read-only) and keep every
client's view in sync when a combo is rebound.
- Section is now visible: 'always'. Recording needs a physical keyboard (the
recorder captures window keydown), so the rows go read-only on a phone --
HotkeyRecorder hides its Change button, the Alt+wheel mouse row is hidden,
and a hint points at the overlay for rebinding. Editable on the overlay +
desktop browser as before.
- Live re-sync: a rebind now broadcasts ServerEvent::Hotkeys { config } from
BOTH PUT paths -- put_hotkeys_http (state.event_tx) and the update_hotkeys
IPC command (slot.event_sender(), the same broadcast channel) -- so other
clients refresh over SSE. New hotkeysMessage in the wire union; useHotkeysSync
applies it via store.applyConfig. The originating client already has the
effective config from its response.
- Rename packages/shared/src/ws-messages.ts -> sse-messages.ts (the transport
has been SSE since the WS migration) + all importers, the package.json
export, and docs. Fix a pre-existing extensionless relative import in
hotkeys-api (node16 needs the .js).
Verified: shared + client typecheck, lint, 110 tests; Rust built via tauri:dev;
live re-sync confirmed on an iPod touch (rebind on the overlay reflects on the
phone instantly).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed code Every `cargo test` run died at load with STATUS_ENTRYPOINT_NOT_FOUND (CI Build-overlay run 16): the lib statically imports ComCtl32 v6-only symbols (SetWindowSubclass etc., via tray-icon/muda), and the test harness exes never get tauri-build's embedded manifest, so the loader bound comctl32 v5.82. build.rs now disables tauri-build's app manifest (its entire content is the same dependency block) and emits the equivalent /MANIFEST:EMBED + /MANIFESTDEPENDENCY link args for all linked targets, tests included. Verified the shipped exe manifest is equivalent via mt.exe. Also rustfmt over already-committed unformatted files (hotkeys.rs, lan.rs, events.rs) -- `cargo fmt --check` is the first step of build-overlay.yml and was what failed runs 17/18. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…reenshots opt-in Work-in-progress slice of PLAN-LAN-AND-TRAY.md: minimize-to-tray close behaviour with a one-time native toast hint (src/notify.rs registers our own AppUserModelID so the toast is not attributed to PowerShell), the regenerated icon set from favicon.svg, the opt-in recycle-bin delete of parsed screenshots, and the client-side wiring (overlay store, tray composable, paths settings section, locales). Also carries the CI fixes that live inside feature-touched files: rustfmt across the Rust tree, clippy useless_vec in the logs.rs tests, and the CORS preflight test now sends Access-Control-Request-Private-Network -- tower-http only emits the allow header in response to it (mirrors real Chrome behaviour). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ous files - Adjusted formatting in `hotkey.spec.ts`, `tarkov-time.spec.ts`, and `useServerTransport.spec.ts` for better readability. - Enhanced code structure in `settings/registry.ts` and `settings/sections/MapSection.vue` by consolidating lines. - Improved layout in `TarkovTimeChip.vue` for consistent HTML structure. - Updated `useTrayIcon.ts` to streamline import statements. These changes focus on code clarity and maintainability without altering functionality.
Reformatted the layers section in CLAUDE.md to enhance readability and maintain consistency in the documentation. The changes include indentation adjustments for better visual hierarchy, ensuring that the structure of layers and their respective files is clear and easy to follow.
…erated files from formatting
Changed the heading in the English and Russian locale files from "Tarkov paths" to "Game integration" and "Пути Tarkov" to "Интеграция с игрой" respectively. Updated visibility settings in the settings section to 'always' for improved diagnostics. Adjusted layout in PathsSection.vue for better user experience, including a more accessible toggle switch for deleting screenshots.
- Added new scripts for frontend, backend, and Tauri development in package.json. - Introduced lint:fix script for automated linting fixes. - Updated CI workflow to run the format check using the updated format script. - Added lint:fix command to shared and client package.json files for improved linting capabilities.
- Added `UpdateBanner` component to notify users of available updates in the client. - Introduced updater logic in the Rust backend to check for and install updates from GitHub Releases. - Updated English and Russian locale files to include new updater messages. - Refactored package.json scripts for clarity and consistency. - Enhanced the Tauri application to handle self-updating, including cleanup of old executables. This commit lays the groundwork for a seamless update experience for users, ensuring they are notified of new versions and can easily install them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.