mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-24 18:50:15 +00:00
feat: add workspace panel edge reopen toggle
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
### Added
|
||||
|
||||
- **PR #2339** by @Michaelyklam (refs #2211) — The workspace panel now has a small desktop edge toggle that remains clickable after the right panel is hidden, making it possible to reopen the workspace browser without returning to Settings. The existing panel close button and composer workspace button remain unchanged; the new affordance only appears when the workspace panel is closed on desktop widths.
|
||||
|
||||
- **PR #2332** by @Michaelyklam (refs #2290) — Cron run history/output cards now surface token/cost metadata when the underlying cron output markdown includes it. The backend parses optional model/token/cost/duration frontmatter from cron output files and returns it from `/api/crons/history` and `/api/crons/run`; the Tasks panel renders a compact usage strip beside run rows and below expanded output without affecting older outputs that lack usage metadata.
|
||||
|
||||
### Fixed
|
||||
|
||||
+8
-1
@@ -82,6 +82,7 @@ function _workspacePanelEls(){
|
||||
layout: document.querySelector('.layout'),
|
||||
panel: document.querySelector('.rightpanel'),
|
||||
toggleBtn: $('btnWorkspacePanelToggle'),
|
||||
edgeToggleBtn: $('btnWorkspacePanelEdgeToggle'),
|
||||
collapseBtn: $('btnCollapseWorkspacePanel'),
|
||||
};
|
||||
}
|
||||
@@ -176,7 +177,7 @@ function _setButtonTooltip(btn, text){
|
||||
}
|
||||
|
||||
function syncWorkspacePanelUI(){
|
||||
const {layout,panel,toggleBtn,collapseBtn}= _workspacePanelEls();
|
||||
const {layout,panel,toggleBtn,edgeToggleBtn,collapseBtn}= _workspacePanelEls();
|
||||
if(!layout||!panel)return;
|
||||
const desktopOpen=_workspacePanelMode!=='closed';
|
||||
const mobileOpen=panel.classList.contains('mobile-open');
|
||||
@@ -190,6 +191,12 @@ function syncWorkspacePanelUI(){
|
||||
_setButtonTooltip(toggleBtn, isOpen?'Hide workspace panel':'Show workspace panel');
|
||||
toggleBtn.disabled=!canBrowse;
|
||||
}
|
||||
if(edgeToggleBtn){
|
||||
edgeToggleBtn.classList.toggle('active',isOpen);
|
||||
edgeToggleBtn.setAttribute('aria-expanded',isOpen?'true':'false');
|
||||
_setButtonTooltip(edgeToggleBtn, isOpen?'Hide workspace panel':'Show workspace panel');
|
||||
edgeToggleBtn.disabled=!canBrowse;
|
||||
}
|
||||
if(collapseBtn){
|
||||
_setButtonTooltip(collapseBtn, isCompact?'Close workspace panel':'Hide workspace panel');
|
||||
}
|
||||
|
||||
@@ -1178,6 +1178,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<button class="workspace-panel-edge-toggle has-tooltip has-tooltip--left" id="btnWorkspacePanelEdgeToggle" type="button" onclick="toggleWorkspacePanel(true)" data-tooltip="Show workspace panel" aria-label="Show workspace panel" aria-expanded="false">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</button>
|
||||
<aside class="rightpanel">
|
||||
<div class="resize-handle" id="rightpanelResize"></div>
|
||||
<div class="panel-header">
|
||||
|
||||
@@ -1329,6 +1329,9 @@
|
||||
@container rightpanel (max-width: 420px){
|
||||
.workspace-hidden-indicator{display:none!important;}
|
||||
}
|
||||
.workspace-panel-edge-toggle{position:fixed;right:10px;top:50%;transform:translateY(-50%) translateX(12px);z-index:120;width:34px;height:44px;border:1px solid var(--border2);border-radius:999px;background:var(--surface);color:var(--muted);box-shadow:0 10px 28px rgba(0,0,0,.22);display:none;align-items:center;justify-content:center;cursor:pointer;opacity:0;pointer-events:none;transition:opacity .18s ease,transform .18s ease,color .15s ease,background .15s ease,border-color .15s ease;}
|
||||
.workspace-panel-edge-toggle:hover{color:var(--text);background:var(--hover-bg);border-color:var(--accent);}
|
||||
.workspace-panel-edge-toggle:disabled{opacity:.3;cursor:not-allowed;transform:translateY(-50%);}
|
||||
/* Small accent dot on the kebab button when a non-default pref is on */
|
||||
#btnWorkspacePrefs{position:relative;}
|
||||
#btnWorkspacePrefs .workspace-prefs-dot{position:absolute;top:3px;right:3px;width:6px;height:6px;border-radius:50%;background:var(--accent-text);box-shadow:0 0 0 1.5px var(--surface);pointer-events:none;}
|
||||
@@ -1413,6 +1416,8 @@
|
||||
@media(min-width:901px){
|
||||
html[data-workspace-panel="closed"] .rightpanel{width:0 !important;opacity:0;transform:translateX(14px);border-left-color:transparent;pointer-events:none;}
|
||||
.layout.workspace-panel-collapsed .rightpanel{width:0 !important;opacity:0;transform:translateX(14px);border-left-color:transparent;pointer-events:none;}
|
||||
html[data-workspace-panel="closed"] .workspace-panel-edge-toggle{display:inline-flex;opacity:1;pointer-events:auto;transform:translateY(-50%);}
|
||||
html[data-workspace-panel="open"] .workspace-panel-edge-toggle{display:none;}
|
||||
}
|
||||
|
||||
/* Sidebar collapse breakpoint matches `_isDesktopWidth()` (min-width:641px) so
|
||||
@@ -1431,6 +1436,7 @@
|
||||
}
|
||||
|
||||
@media(max-width:900px){
|
||||
.workspace-panel-edge-toggle{display:none!important;}
|
||||
.rightpanel{display:none}
|
||||
.workspace-toggle-btn,.mobile-files-btn{display:inline-flex!important;}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Regression coverage for issue #2211 workspace panel reopen affordance."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
HTML = (ROOT / "static" / "index.html").read_text(encoding="utf-8")
|
||||
CSS = (ROOT / "static" / "style.css").read_text(encoding="utf-8")
|
||||
BOOT_JS = (ROOT / "static" / "boot.js").read_text(encoding="utf-8")
|
||||
CHANGELOG = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_workspace_panel_has_edge_reopen_toggle_outside_hidden_panel():
|
||||
assert 'id="btnWorkspacePanelEdgeToggle"' in HTML
|
||||
assert 'class="workspace-panel-edge-toggle' in HTML
|
||||
assert 'onclick="toggleWorkspacePanel(true)"' in HTML
|
||||
edge_idx = HTML.index('id="btnWorkspacePanelEdgeToggle"')
|
||||
aside_idx = HTML.index('<aside class="rightpanel">')
|
||||
assert edge_idx < aside_idx, "reopen control must remain clickable when .rightpanel is collapsed"
|
||||
|
||||
|
||||
def test_workspace_panel_edge_toggle_only_shows_when_panel_closed_on_desktop():
|
||||
assert 'html[data-workspace-panel="closed"] .workspace-panel-edge-toggle' in CSS
|
||||
assert 'html[data-workspace-panel="open"] .workspace-panel-edge-toggle' in CSS
|
||||
assert '@media(max-width:900px)' in CSS and '.workspace-panel-edge-toggle{display:none!important;}' in CSS
|
||||
|
||||
|
||||
def test_workspace_panel_sync_updates_edge_toggle_state_and_accessibility():
|
||||
assert "edgeToggleBtn: $('btnWorkspacePanelEdgeToggle')" in BOOT_JS
|
||||
assert "edgeToggleBtn.classList.toggle('active',isOpen)" in BOOT_JS
|
||||
assert "edgeToggleBtn.setAttribute('aria-expanded',isOpen?'true':'false')" in BOOT_JS
|
||||
assert "edgeToggleBtn.disabled=!canBrowse" in BOOT_JS
|
||||
|
||||
|
||||
def test_changelog_mentions_workspace_panel_reopen_affordance():
|
||||
assert "#2211" in CHANGELOG
|
||||
assert "workspace panel" in CHANGELOG.lower()
|
||||
assert "reopen" in CHANGELOG.lower()
|
||||
Reference in New Issue
Block a user