## Summary Rebased-on-behalf of @franksong2702 (originally PR #728 — had CHANGELOG conflict after #747 merged). Moves `#cmdDropdown` from outside `composer-box` to inside it, so the `position:absolute` anchor is scoped to the composer width rather than the full chat panel. CSS updated to use `bottom:calc(100% + 4px)` and `width:auto;max-width:100%` for clean upward positioning. Closes #633 ## Changes - `static/index.html` — moved `cmd-dropdown` div inside `composer-box` - `static/style.css` — updated `.cmd-dropdown` positioning (remove `margin-bottom`, use `bottom:calc(100% + 4px)`, add `width:auto;max-width:100%`) - `tests/test_sprint50.py` — 2 new structural tests verifying DOM position and CSS rules ## Tests 1493 passed, 1 warning (2 new tests added) **Original author:** @franksong2702
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
# Hermes Web UI -- Changelog
|
# Hermes Web UI -- Changelog
|
||||||
|
|
||||||
|
## [v0.50.98] — 2026-04-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Slash command autocomplete constrained to composer width** — the `/` command dropdown is now positioned inside the composer box, so suggestions stay visually anchored to the input area rather than expanding across the full chat panel. (Closes #633, credit: @franksong2702)
|
||||||
|
|
||||||
## [v0.50.97] — 2026-04-20
|
## [v0.50.97] — 2026-04-20
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -226,7 +226,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="composer-wrap" id="composerWrap">
|
<div class="composer-wrap" id="composerWrap">
|
||||||
<div class="cmd-dropdown" id="cmdDropdown"></div>
|
|
||||||
<div class="composer-flyout">
|
<div class="composer-flyout">
|
||||||
<div class="approval-card" id="approvalCard" role="alertdialog" aria-labelledby="approvalHeading" aria-describedby="approvalDesc">
|
<div class="approval-card" id="approvalCard" role="alertdialog" aria-labelledby="approvalHeading" aria-describedby="approvalDesc">
|
||||||
<div class="approval-inner">
|
<div class="approval-inner">
|
||||||
@@ -275,6 +274,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="composer-box" id="composerBox">
|
<div class="composer-box" id="composerBox">
|
||||||
|
<div class="cmd-dropdown" id="cmdDropdown"></div>
|
||||||
<div class="drop-hint" id="dropHint">
|
<div class="drop-hint" id="dropHint">
|
||||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
|
||||||
Drop files to upload to workspace
|
Drop files to upload to workspace
|
||||||
|
|||||||
@@ -825,7 +825,7 @@
|
|||||||
.profile-card-meta{font-size:11px;color:var(--muted);margin-top:3px;padding-left:12px;}
|
.profile-card-meta{font-size:11px;color:var(--muted);margin-top:3px;padding-left:12px;}
|
||||||
.profile-card-actions{display:flex;gap:4px;flex-shrink:0;}
|
.profile-card-actions{display:flex;gap:4px;flex-shrink:0;}
|
||||||
/* ── Slash command autocomplete dropdown ── */
|
/* ── Slash command autocomplete dropdown ── */
|
||||||
.cmd-dropdown{display:none;position:absolute;bottom:100%;left:0;right:0;background:var(--surface);border:1px solid var(--border2);border-radius:10px;box-shadow:0 -8px 24px rgba(0,0,0,.4);z-index:200;max-height:240px;overflow-y:auto;margin-bottom:4px;}
|
.cmd-dropdown{display:none;position:absolute;left:0;right:0;bottom:calc(100% + 4px);width:auto;max-width:100%;background:var(--surface);border:1px solid var(--border2);border-radius:10px;box-shadow:0 -8px 24px rgba(0,0,0,.4);z-index:200;max-height:240px;overflow-y:auto;}
|
||||||
.cmd-dropdown.open{display:block;}
|
.cmd-dropdown.open{display:block;}
|
||||||
.cmd-item{padding:8px 14px;cursor:pointer;transition:background .12s;}
|
.cmd-item{padding:8px 14px;cursor:pointer;transition:background .12s;}
|
||||||
.cmd-item:hover,.cmd-item.selected{background:rgba(255,255,255,.07);}
|
.cmd-item:hover,.cmd-item.selected{background:rgba(255,255,255,.07);}
|
||||||
|
|||||||
39
tests/test_sprint50.py
Normal file
39
tests/test_sprint50.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"""Tests for small UX regressions fixed after v0.50.96.
|
||||||
|
|
||||||
|
Covers:
|
||||||
|
- #633: slash command autocomplete dropdown should be constrained to the
|
||||||
|
composer width rather than the full chat panel width.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
REPO = pathlib.Path(__file__).parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def read(rel):
|
||||||
|
return (REPO / rel).read_text()
|
||||||
|
|
||||||
|
|
||||||
|
def test_cmd_dropdown_moved_inside_composer_box():
|
||||||
|
src = read("static/index.html")
|
||||||
|
composer_start = src.index('<div class="composer-box" id="composerBox">')
|
||||||
|
dropdown_idx = src.index('<div class="cmd-dropdown" id="cmdDropdown"></div>')
|
||||||
|
textarea_idx = src.index('<textarea id="msg"')
|
||||||
|
assert composer_start < dropdown_idx < textarea_idx, (
|
||||||
|
"cmdDropdown should live inside composerBox, before the textarea, so its "
|
||||||
|
"absolute positioning is scoped to the composer instead of the full chat panel"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cmd_dropdown_css_scoped_to_composer_width():
|
||||||
|
src = read("static/style.css")
|
||||||
|
assert ".cmd-dropdown{display:none;position:absolute;left:0;right:0;" in src, (
|
||||||
|
"cmdDropdown should be absolutely positioned with left/right anchors"
|
||||||
|
)
|
||||||
|
assert "width:auto;max-width:100%;" in src, (
|
||||||
|
"cmdDropdown width should be constrained to the positioned composer ancestor"
|
||||||
|
)
|
||||||
|
assert "bottom:calc(100% + 4px);" in src, (
|
||||||
|
"cmdDropdown should sit just above the composer box"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user