# dsh-qol
Quality-of-life tweaks for the DeepSeek Harness (dsh) Web GUI: a session tab bar, sidebar swipe gestures, IME/keyboard adaptation, touch feedback, a full-screen settings rewrite and more — **each independently toggleable** from **Settings → QoL**, taking effect instantly and persisted per browser. Mobile-first; some features (tab bar, status animation, etc.) apply on desktop too.  ## Features All toggles in **Settings → QoL** are organized into 4 groups (click a group header to collapse it): ### Navigation & switching | Feature | Description | Default | |---|---|---| | Active-session Tab Bar | Horizontally shows session tabs at the top of the page; one-tap switching, no accidental keyboard pull-up; **supports context menu** (Close tab, Pin/Unpin tab, Close other tabs); **supports pinned tabs** (pinned tabs stay at the far left with a pin icon and won't be evicted by the window limit); **supports drag-and-drop reordering** (drag tabs with mouse to reorder, dragging across pinned/unpinned boundaries automatically updates pin status); **supports mouse wheel horizontal scrolling** (wheel down/up translates to horizontal scroll, preventing scroll leak to the page below); fresh sessions show as "New Session" until the first message is sent; **the + button is pinned at the bar's right edge** (it never scrolls away). **Display mode** (switchable in Settings → QoL): both modes share the same open/close tab set (middle-click/× to close, states update live) and differ only in ordering — **Standard** = fixed open order; **Recent** = by activity time, newest-active leftmost (the colored status dots are informational only and never affect ordering) | On (mode defaults to Standard) | | Sidebar swipe | Expand the sidebar by swiping right and collapse by swiping left **anywhere on screen** (64px threshold, non-following; the left 16px edge yields to the system back gesture; input fields / horizontal scrollers skipped; no response while a dialog is open; swiping over buttons is safe — it never triggers a click) | On | | Sidebar overlay | On mobile the sidebar opens as an overlay covering content instead of squeezing the main area into a reflow | On | | Collapse sidebar on switch | On narrow screens, picking a session in the sidebar auto-collapses it and returns to the conversation (≤768px only) | On | | No keyboard on switch | Switching sessions never auto-focuses the input box, so the IME never pops up; covers sidebar session rows, active tabs and archive jumps; tapping the input box directly still focuses it manually | On | | Previous/next user message | Adds a two-in-one vertical button right above the "Back to bottom" floating button (bottom-right): the upper half jumps to the previous user message, the lower half to the next one, both top-aligned, for stepping through a long conversation; the host's own "Back to bottom" stays a separate button | On | | Auto load older on top | Long sessions lazy-load history: arriving at the very top of the conversation auto-clicks the host's "Load earlier" pill with viewport anchored (no jump); one shot per arrival, re-arms after leaving the top | On | | Pin workspace to top | Adds "Pin to top" / "Unpin" entries to the ⋯ menu on each workspace row in the sidebar: **multiple workspaces can be pinned**, pinned ones are fixed at the top of the list (order persisted server-side, surviving reloads) and show a small pin icon at the row's right edge; unpinning moves a workspace back after the pinned section | On | ### Input & keyboard | Feature | Description | Default | |---|---|---| | IME/keyboard adaptation | viewport meta (`viewport-fit=cover` + `interactive-widget=resizes-content`), a `100dvh` height chain, composer safe area, iOS `visualViewport` CSS-variable fallback (**never changes element sizes/fonts**) | On | | Enter inserts newline | Enter in the input box inserts a newline instead of sending; send with Ctrl/⌘+Enter (steer/queue while the agent runs), Shift+Enter still inserts a newline; IME candidate confirmation and the @ menu are unaffected | Off | | Hide permission dropdown | Hides the permission (Access mode) dropdown trigger inside the input box to save horizontal space; model selection and context usage are unaffected | On | ### Touch & feedback | Feature | Description | Default | |---|---|---| | Touch feedback | `touch-action: manipulation` (kills the 300ms delay and double-tap zoom), disables the system tap highlight, `:active` press feedback, iOS `:active` fix, respects `prefers-reduced-motion` (**never changes element sizes**) | On | | Disable touch long-press drag | On Android, long-pressing a sidebar session row triggers a system drag (a side effect of the desktop reorder feature), and Chromium touch drags frequently hang the page — nothing responds until reload; dragstart is cancelled while touching, so **desktop mouse drag-reorder is unaffected**. Finger drag-reordering on touch-screen laptops is also disabled (mouse/trackpad reordering still works) | On | ### Display & settings page | Feature | Description | Default | |---|---|---| | Full-screen settings rewrite | The settings dialog stacks full-screen at ≤768px with horizontally scrolling tabs, a collapsed-tab-width bugfix and safe-area adaptation | On | | Settings tab memory | Reopening settings restores the last selected tab instead of resetting to General | Off | | Prevent horizontal scroll | Prevent horizontal scrolling in the main content area at all times; blockquotes, unbroken text and code blocks are constrained within their container to wrap or scroll internally | On | | Code/table inner scroll | Long code blocks and tables scroll horizontally inside their containers; body text wraps without overflowing | On | | Status animation optimization | Replaces the SVG opacity chase-dot animation with a CSS transform pulse on the compositor thread, zero main-thread cost. Measured idle FPS via rAF: 35 → 55 | On | ## Install ```bash dsh plugin --profile web add dsh-qol ``` No manual configuration needed after install — the bundled `cordis.patch.yml` mounts automatically; once installed, a **QoL** section appears on the settings page after refreshing the web UI. Install straight from GitHub (source install; `lib/` is hand-written source and needs no local build, but the package declares a `prepare` syntax-check script, which pnpm ≥10 blocks the first time): ```bash dsh plugin --profile web add github:john-walks-slow/dsh-qol # Add the package name pnpm prints to allowBuilds in # ~/.dsh/profiles/web/pnpm-workspace.yaml, then re-run ``` ## Usage 1. Open the dsh Web GUI (best on mobile). 2. Settings → **QoL**: all toggles are organized into 4 groups (Navigation & switching / Input & keyboard / Touch & feedback / Display & settings page); click a group header to collapse it. Each click takes effect **instantly**, no page refresh needed. 3. Toggles persist automatically in browser `localStorage` (key `dsh.qol.v1`) for this browser only; deleting that key restores the defaults. Group collapse state lives in a separate key, `dsh.qol.groups`. What a saved toggle set actually looks like (`localStorage["dsh.qol.v1"]`): ```json { "active-tabbar": true, "active-tabbar-mode": "recent", "sidebar-gesture": true, "ime-viewport": true, "tap-feedback": true } ``` `active-tabbar-mode` is the tab bar's display mode (not a toggle): `"standard"` (default) or `"recent"`. You can also switch it via the **Display mode** segmented control under the "Active-session Tab Bar" toggle in Settings → QoL — it takes effect instantly. The implementation is an **attribute total-gate**: every feature maps to an `html[data-qol-