3 Commits

Author SHA1 Message Date
nesquena-hermes b49c3cbd43 fix(ux): rail tooltips, +new-conversation clipping, context-menu hover, rename pre-fill
Four small UX bugs Nathan caught while dogfooding the v0.51.17 release on
desktop. All independently reproduced with browser_console + browser_vision
on a fresh worktree before fixing.

(1) **Left-rail icon tooltips never appeared.** The rail was migrated to the
    new `.has-tooltip` system in #1782, but the legacy suppression rule
    `.rail .nav-tab:hover::after { content: none }` survived the migration.
    Its specificity (0,3,1) outweighs `.has-tooltip:hover::after` (0,2,1),
    and `content: none` removes the pseudo-element entirely on hover — so the
    new tooltip system silently no-op'd on every rail icon. Fix: drop the
    suppression rule and scope the legacy `data-label` tooltip to
    `.sidebar-nav .nav-tab` (mobile) only, so it doesn't fire on rail buttons
    that carry no `data-label` (which would render an empty styled box).

(2) **`+ New conversation` tooltip clipped at panel right edge.** The button
    sits flush with the chat panel's right edge but used `--bottom` which
    centers the tooltip on `left:50%` — half the label overflowed past the
    panel edge ("New convers..."). New `.has-tooltip--bottom-right` variant
    anchors the tooltip's RIGHT edge to the trigger so the label extends
    inward. Reusable for any future right-edge panel-head button.

(3) **Workspace right-click menu items had no hover state.** The five sites
    in `_showFileContextMenu` (Rename / Reveal / Copy path / Delete) and two
    in `_showProjectContextMenu` set `style.background = 'var(--hover)'`. The
    custom property `--hover` is undefined anywhere in the codebase. An
    undefined `var()` falls back to the property's initial value
    (`transparent` for `background`) → no visible hover feedback. The defined
    variable is `--hover-bg` (`rgba(255,255,255,.06)`), already used by every
    other hover state in the app. One-letter typo, seven sites.

(4) **Rename dialog didn't pre-fill the current filename.** The caller
    (`_inlineRenameFileItem`) passed `defaultValue: item.name` to
    `showPromptDialog`, but the dialog's input setter reads `opts.value`
    only — the param name was silently dropped, leaving only the placeholder
    visible (Nathan called it the "ghost name"). Fixed two ways for
    defense-in-depth:
    - Caller switched to canonical `value: item.name`.
    - Dialog now also accepts `defaultValue` as an alias for `value`, so
      future typos using the standard `HTMLInputElement.defaultValue` param
      name don't repeat the bug.
    Plus: added `selectStem:true` opt that selects the stem before the last
    `.` on focus (Finder-style: `report.txt` → selects `report`, extension
    preserved). Edge cases verified live: directories full-select,
    `.gitignore` full-selects (dot at index 0), `noextension` full-selects,
    `a.b.c.d` selects `a.b.c`.

## Tests

+12 new regression tests, +5 net (existing test_css_tooltips suite gained 5
class-based tests; new tests/test_workspace_context_menu_and_rename.py file
adds 7 more). Total: 4728 passed (was 4723 in v0.51.17), 4 skipped, 3
xpassed, 0 failed in 141s.

- `RailTooltipCascadeTests` — pins the killer rule's absence (with comment
  stripping so the explanatory note doesn't false-positive), pins the
  scoped `.sidebar-nav .nav-tab` form, walks every rail button to confirm
  `has-tooltip` + non-empty `data-tooltip`.
- `BottomRightTooltipVariantTests` — pins variant existence, mechanics
  (`right:0`, `left:auto`, `transform:none`), and `#btnNewChat` adoption
  (with mutual-exclusion check that it doesn't carry both `--bottom` and
  `--bottom-right`).
- `ContextMenuHoverBackgroundTests` — `var(--hover)` may not appear in
  ui.js or sessions.js (the bug shape); affirmative pin that
  `_showFileContextMenu` sets ≥4 items to `var(--hover-bg)` and
  `_showProjectContextMenu` ≥2.
- `ShowPromptDialogPrefillTests` — pins both `opts.value` and
  `opts.defaultValue` references; pins the `selectStem` mechanic
  (`lastIndexOf('.')` + `setSelectionRange(0, dot)`); pins the caller's
  use of `value:item.name` and `selectStem`.

## Verification

Live in browser at port 8789 (worktree-served):
- Rail Tasks tooltip renders 8px right of the icon at the same vertical
  level (math: btn at y=87-123, tooltip at left=44px = 36px width + 8px gap).
- New-conversation tooltip renders below + button with right edge aligned
  to button's right edge, extending leftward, fully visible.
- Right-click → Reveal in File Manager shows `rgba(255, 255, 255, 0.035)`
  background on hover (the `--hover-bg` value); was `rgba(0, 0, 0, 0)`
  (transparent) before.
- Right-click → Rename on `report.txt`: input shows `report.txt`,
  selectionStart=0, selectionEnd=6, selected text = "report". Edge cases:
  directory `docs` → full-select; `.gitignore` → full-select;
  `noextension` → full-select; `a.b.c.d` → selects `a.b.c`.

`node -c` syntax check passes on both modified JS files.

Reported by: Nathan via screenshots (rail tooltips missing, + button
clipped tooltip, Workspace right-click no hover, rename dialog blank).
2026-05-07 06:25:18 +00:00
nesquena-hermes d41555cec6 fix(ux): polish CSS tooltips + clear native title + extend coverage
Stage 311 maintainer-side enhancements on top of @jasonjcwu's PR #1782,
addressing browser-verified issues + extending coverage to high-traffic
icon buttons:

(1) Clear native title when custom data-tooltip is present (the core bug fix):
    - static/i18n.js: when data-i18n-title runs against an element that has
      data-tooltip, sync data-tooltip AND removeAttribute('title'). Without
      this, the slow ~1.5s native browser tooltip co-fires alongside the
      fast custom CSS tooltip — exactly the bug #1775 reports.
    - static/ui.js _applyDashboardStatus: same treatment for the dashboard
      rail/mobile buttons (was setting btn.title=warning unconditionally).
    - static/boot.js: added _setButtonTooltip() helper, replaced 6 direct
      .title assignments (workspace toggle/collapse/clear, voice dictate,
      voice mode active/inactive) with calls through the helper.

(2) Extend coverage to high-traffic icon buttons in static/index.html:
    - Composer area (side tooltip): btnAttach, btnMic, btnVoiceMode,
      btnWorkspacePanelToggle, btnSend.
    - Workspace panel header (bottom tooltip): btnCollapseWorkspacePanel,
      btnUpDir, btnNewFile, btnNewFolder, btnRefreshPanel, btnClearPreview.
    - All 11 buttons gain has-tooltip[--bottom] class and data-tooltip,
      lose their native title=. Total covered surfaces: rail (12), sidebar
      nav-tabs (12), panel-head (31), composer/workspace icons (11) = 66.

(3) CSS polish (browser-verified visible improvement):
    - z-index 60 → 1500/1501 so the tooltip clears all sidebar/panel
      stacking contexts. Earlier verification showed the tooltip overlapping
      the Filter conversations search input.
    - background: var(--bg-strong, ...) → var(--surface) (solid #1A1A2E
      instead of falling back via undefined cascade).
    - color: var(--text, var(--accent-text)) → var(--text) (solid warm white
      #FFF8DC instead of gold which clashed at body-text size).
    - border: var(--accent-bg-strong) → var(--border) (#2A2A45 solid
      instead of gold at 0.15 alpha — the old border was barely visible
      and the arrow ::before triangle was invisible).
    - shadow: 4px/0.45 alpha → 6px/0.55 alpha + 0 0 0 1px ring fallback.
    - Added 150ms hover-onset delay (matches Cygnus's spec in #1775); 0s
      dismissal-delay so quick mouse-aways don't leave the tooltip behind.
    - Fixed has-tooltip--bottom arrow direction: was pointing down (wrong),
      now points up at the trigger (border-color order corrected).
    - Bumped offsets: side tooltip 10px → 12px (clearance from icon edge),
      bottom tooltip 8px → 10px.

(4) Test fixes (the 2 CI failures):
    - tests/test_cron_refresh_button_835.py: assertion accepts either
      title= or data-tooltip= per #1775 (was hardcoded title=).
    - tests/test_mobile_layout.py::test_profiles_sidebar_tab_present:
      regex tolerant to additional utility classes (has-tooltip).

(5) Regression tests added to tests/test_css_tooltips.py:
    - test_native_title_cleared_when_custom_tooltip_present: pins the
      removeAttribute('title') call so we don't regress to dual tooltips.
    - test_native_title_path_preserved_for_non_tooltip_elements: pins the
      el.title fallback for elements without data-tooltip.

Browser-verified: all 72 has-tooltip elements have zero native title at
runtime (was 94 with native, 2 stuck via dashboard JS path).

Co-authored-by: Jason Wu <jasonjcwu@users.noreply.github.com>
2026-05-07 04:00:40 +00:00
fxd-jason b86bdf9dc8 fix(ux): replace native title tooltips with custom CSS tooltips (#1775)
- Add .has-tooltip CSS utility class with 300ms delay (vs ~1500ms native)
  - Position-aware: right side for rail buttons, bottom for nav/panel buttons
  - Arrow indicator pointing back at trigger element
  - :focus-visible support for keyboard accessibility
  - prefers-reduced-motion: no animation for users who opt out
- Replace native title="" with data-tooltip="" on all rail-btn, sidebar
  nav-tab, and panel-head-btn elements in index.html
- Sync data-tooltip via data-i18n-title handler for locale switching
- 17 tests covering HTML coverage, CSS class definitions, and i18n sync

Closes #1775
2026-05-07 03:58:16 +00:00