sidebar: smooth collapse/expand transition for custom labeled actions

CSS:
- Force min-width:0 on .body-sidebar-bottom so it can shrink to the 50px
  collapsed width instead of refusing to clip past its widest label.
- Animate label max-width and margin-left with the same 0.3s
  cubic-bezier as the sidebar width — labels now slide smoothly
  under their icons on collapse instead of leaving an ellipsized
  letter at the edge.
- Hide v16.17's native .sidebar-bottom-actions row (about + collapse
  icon-buttons) since our labeled .jey-collapse-link replaces it.
- Animate .nav-item padding so it stays in sync with the sidebar
  width transition (Frappe v16 toggles padding 0→8px instantly).

JS:
- Update collapse-link DOM in place (svg href + span text) instead of
  rebuilding innerHTML, so the span keeps its identity and the
  max-width transition plays smoothly across collapse/expand toggles.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-05-01 12:52:09 +00:00
parent 534c98e062
commit 2230a2854f
2 changed files with 53 additions and 3 deletions

View File

@ -370,6 +370,15 @@ input.list-header-checkbox:checked::after {
Sidebar Full Width button
========================================================================== */
/* .body-sidebar-bottom is a flex item of .body-sidebar (column flex).
By default min-width:auto resolves to min-content, so it refuses to
shrink below the natural width of its widest text and our buttons'
labels poke past the collapsed sidebar's right edge. Force min-width:0
so it can match the cross-axis (50px collapsed) and clip properly. */
.body-sidebar .body-sidebar-bottom {
min-width: 0;
}
.jey-fullwidth-link,
.jey-theme-switch-link,
.jey-collapse-link {
@ -379,6 +388,8 @@ input.list-header-checkbox:checked::after {
align-items: center;
cursor: pointer;
margin-bottom: 8px;
width: 100%;
overflow: hidden;
}
.jey-fullwidth-link svg,
@ -392,9 +403,36 @@ input.list-header-checkbox:checked::after {
.jey-theme-switch-link span,
.jey-collapse-link span {
margin-left: 10px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: max-width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
margin-left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* When sidebar is collapsed, animate the label to zero width + zero
margin so it smoothly slides under the icon instead of leaving a
single ellipsized letter at the edge. */
.body-sidebar-container:not(.expanded) .jey-fullwidth-link span,
.body-sidebar-container:not(.expanded) .jey-theme-switch-link span,
.body-sidebar-container:not(.expanded) .jey-collapse-link span {
max-width: 0;
margin-left: 0;
}
/* Hide the v16.17 native bottom row (about + collapse icon-buttons).
Our labeled .jey-collapse-link replaces it. */
.body-sidebar .sidebar-bottom-actions {
display: none !important;
}
/* Frappe v16 toggles .nav-item padding 08px instantly between
collapsed/expanded, while the sidebar width itself transitions over
0.3s making the user/account button visibly jump 8px. Animate the
padding so it stays in sync with the width. */
.body-sidebar .nav-item {
transition: padding 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* ==========================================================================

View File

@ -761,9 +761,21 @@
var expanded = isExpanded();
var iconName = expanded ? "chevrons-left" : "chevrons-right";
var label = expanded ? __("Collapse Sidebar") : __("Expand Sidebar");
var span = link.querySelector("span");
var use = link.querySelector("svg use");
if (!span || !use) {
// First render — build the DOM.
link.innerHTML =
frappe.utils.icon(iconName, "sm", "", "", "text-ink-gray-7 current-color", true) +
"<span>" + label + "</span>";
return;
}
// Update in place so the span keeps its identity and the
// max-width transition plays smoothly across collapse/expand.
use.setAttribute("href", "#icon-" + iconName);
span.textContent = label;
}
function addCollapseButton() {