From d2ae1c037fbf2d94a885ff97c0e35b720fa8aa03 Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Sat, 25 Jan 2025 22:39:48 +0100 Subject: [PATCH 1/4] Make sidebar resizable --- python_docs_theme/static/pydoctheme.css | 19 +++++--- python_docs_theme/static/sidebar.js_t | 65 ++++++++++++------------- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css index 0f6f8d37..65b218fc 100644 --- a/python_docs_theme/static/pydoctheme.css +++ b/python_docs_theme/static/pydoctheme.css @@ -139,7 +139,13 @@ span.pre { white-space: unset; } +div.bodywrapper { + margin-left: 250px; +} + div.sphinxsidebar { + display: flex; + width: 250px; float: none; position: sticky; top: 0; @@ -157,12 +163,12 @@ div.sphinxsidebar h4 { } div.sphinxsidebarwrapper { - width: 217px; box-sizing: border-box; height: 100%; overflow-x: hidden; overflow-y: auto; - float: left; + float: none; + flex-grow: 1; } div.sphinxsidebarwrapper > h3:first-child { @@ -197,12 +203,13 @@ div.sphinxsidebar input[type='text'] { margin-left: 0; color: #444444; font-size: 1.2em; - cursor: pointer; + cursor: col-resize; padding-top: 1px; - float: right; + float: none; display: table; /* after Sphinx 4.x and earlier is dropped, only the below is needed */ width: 12px; + min-width: 12px; border-radius: 0 5px 5px 0; border-left: none; } @@ -468,7 +475,7 @@ div.genindex-jumpbox a { font-size: 0.875rem; } div.bodywrapper { - margin: 0; + margin: 0 !important; } /* Typography */ div.body h1 { @@ -490,7 +497,7 @@ div.genindex-jumpbox a { } /* Remove sidebar and top related bar */ div.related, .sphinxsidebar { - display: none; + display: none !important; } /* Anchorlinks are not hidden by fixed-positioned navbar when scrolled to */ html { diff --git a/python_docs_theme/static/sidebar.js_t b/python_docs_theme/static/sidebar.js_t index a08aa0fd..22dafb4d 100644 --- a/python_docs_theme/static/sidebar.js_t +++ b/python_docs_theme/static/sidebar.js_t @@ -27,12 +27,12 @@ const initialiseSidebar = () => { // global elements used by the functions. - const bodyWrapper = document.getElementsByClassName("bodywrapper")[0] - const sidebar = document.getElementsByClassName("sphinxsidebar")[0] - const sidebarWrapper = document.getElementsByClassName("sphinxsidebarwrapper")[0] + const bodyWrapper = document.querySelector(".bodywrapper") + const sidebar = document.querySelector(".sphinxsidebar") + const sidebarWrapper = document.querySelector(".sphinxsidebarwrapper") // exit early if the document has no sidebar for some reason - if (typeof sidebar === "undefined") { + if (!sidebar) { return } @@ -44,46 +44,43 @@ const initialiseSidebar = () => { #} {% if sphinx_version_tuple is defined and sphinx_version_tuple[0] >= 5 %} const sidebarButton = document.getElementById("sidebarbutton") - const sidebarArrow = sidebarButton.querySelector('span') {% else %} // create the sidebar button element const sidebarButton = document.createElement("div") sidebarButton.id = "sidebarbutton" - // create the sidebar button arrow element - const sidebarArrow = document.createElement("span") - sidebarArrow.innerText = "«" - sidebarButton.appendChild(sidebarArrow) - sidebar.appendChild(sidebarButton) {% endif %} + sidebarbutton.innerHTML = "" + sidebarbutton.tabindex = "0" // make it focusable + sidebarbutton.role = "slider" + sidebarbutton.title = _("Resize sidebar") + sidebarbutton.setAttribute("aria-label", _("Resize sidebar by dragging")) + sidebarbutton.setAttribute("aria-valuetext", _("Sidebar width XXX pixels")) + let clientX; - const collapse_sidebar = () => { - bodyWrapper.style.marginLeft = ".8em" - sidebar.style.width = ".8em" - sidebarWrapper.style.display = "none" - sidebarArrow.innerText = "»" - sidebarButton.title = _("Expand sidebar") - window.localStorage.setItem("sidebar", "collapsed") + function onMouseMove(e) { + e.preventDefault() + const sidebarWidth = sidebar.offsetWidth + const newWidth = Math.max(0, Math.min(window.innerWidth, sidebarWidth + e.clientX - clientX)) + clientX = e.clientX + sidebar.style.width = `${newWidth}px` + bodyWrapper.style.marginLeft = `${newWidth}px` + window.localStorage.setItem("sidebar-width", newWidth) } - const expand_sidebar = () => { - bodyWrapper.style.marginLeft = "" - sidebar.style.removeProperty("width") - sidebarWrapper.style.display = "" - sidebarArrow.innerText = "«" - sidebarButton.title = _("Collapse sidebar") - window.localStorage.setItem("sidebar", "expanded") - } - - sidebarButton.addEventListener("click", () => { - (sidebarWrapper.style.display === "none") ? expand_sidebar() : collapse_sidebar() + sidebarButton.addEventListener("mousedown", e => { + e.preventDefault() + clientX = e.clientX + document.addEventListener("mousemove", onMouseMove) + document.addEventListener("mouseup", () => { + document.removeEventListener("mousemove", onMouseMove) + sidebarbutton.setAttribute("aria-valuetext", _("Sidebar width XXX pixels")) + }) }) - const sidebar_state = window.localStorage.getItem("sidebar") - if (sidebar_state === "collapsed") { - collapse_sidebar() - } - else if (sidebar_state === "expanded") { - expand_sidebar() + const sidebarWidth = parseInt(window.localStorage.getItem("sidebar-width"), 10) + if(Number.isFinite(sidebarWidth)) { + sidebar.style.width = `${sidebarWidth}px` + bodyWrapper.style.marginLeft = `${sidebarWidth}px` } } From ea9e509bad346f91803b3dc9299aca193dad794a Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Sun, 26 Jan 2025 23:14:19 +0100 Subject: [PATCH 2/4] Add min and max sidebar width --- python_docs_theme/static/sidebar.js_t | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python_docs_theme/static/sidebar.js_t b/python_docs_theme/static/sidebar.js_t index 22dafb4d..30323363 100644 --- a/python_docs_theme/static/sidebar.js_t +++ b/python_docs_theme/static/sidebar.js_t @@ -49,6 +49,9 @@ const initialiseSidebar = () => { const sidebarButton = document.createElement("div") sidebarButton.id = "sidebarbutton" {% endif %} + const sidebarMinWidth = 200 + const sidebarMaxWidth = Math.round(0.5 * window.innerWidth) + sidebarbutton.innerHTML = "" sidebarbutton.tabindex = "0" // make it focusable sidebarbutton.role = "slider" @@ -60,7 +63,10 @@ const initialiseSidebar = () => { function onMouseMove(e) { e.preventDefault() const sidebarWidth = sidebar.offsetWidth - const newWidth = Math.max(0, Math.min(window.innerWidth, sidebarWidth + e.clientX - clientX)) + const newWidth = Math.max( + sidebarMinWidth, + Math.min(sidebarMaxWidth, sidebarWidth + e.clientX - clientX) + ) clientX = e.clientX sidebar.style.width = `${newWidth}px` bodyWrapper.style.marginLeft = `${newWidth}px` From 98e56246ef6f072f15f4196d451ccf3c7f19f869 Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Sun, 26 Jan 2025 23:14:49 +0100 Subject: [PATCH 3/4] Use ngettext --- python_docs_theme/static/sidebar.js_t | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/python_docs_theme/static/sidebar.js_t b/python_docs_theme/static/sidebar.js_t index 30323363..bb8d4fa5 100644 --- a/python_docs_theme/static/sidebar.js_t +++ b/python_docs_theme/static/sidebar.js_t @@ -26,6 +26,7 @@ */ const initialiseSidebar = () => { + const ngettext = Documentation.ngettext // global elements used by the functions. const bodyWrapper = document.querySelector(".bodywrapper") const sidebar = document.querySelector(".sphinxsidebar") @@ -57,7 +58,14 @@ const initialiseSidebar = () => { sidebarbutton.role = "slider" sidebarbutton.title = _("Resize sidebar") sidebarbutton.setAttribute("aria-label", _("Resize sidebar by dragging")) - sidebarbutton.setAttribute("aria-valuetext", _("Sidebar width XXX pixels")) + sidebarbutton.setAttribute( + "aria-valuetext", + ngettext( + "Sidebar width {count} pixel", + "Sidebar width {count} pixels", + sidebar.offsetWidth + ).replace("{count}", sidebar.offsetWidth) + ) let clientX; function onMouseMove(e) { @@ -79,7 +87,14 @@ const initialiseSidebar = () => { document.addEventListener("mousemove", onMouseMove) document.addEventListener("mouseup", () => { document.removeEventListener("mousemove", onMouseMove) - sidebarbutton.setAttribute("aria-valuetext", _("Sidebar width XXX pixels")) + sidebarbutton.setAttribute( + "aria-valuetext", + ngettext( + "Sidebar width {count} pixel", + "Sidebar width {count} pixels", + sidebar.offsetWidth + ).replace("{count}", sidebar.offsetWidth) + ) }) }) From b97d986b773a0ba4590dfeac0bd0a963f0323ede Mon Sep 17 00:00:00 2001 From: Tomas Roun Date: Mon, 27 Jan 2025 21:51:40 +0100 Subject: [PATCH 4/4] Set cursor via JS --- python_docs_theme/static/pydoctheme.css | 2 +- python_docs_theme/static/sidebar.js_t | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css index 65b218fc..8327941a 100644 --- a/python_docs_theme/static/pydoctheme.css +++ b/python_docs_theme/static/pydoctheme.css @@ -203,7 +203,7 @@ div.sphinxsidebar input[type='text'] { margin-left: 0; color: #444444; font-size: 1.2em; - cursor: col-resize; + cursor: default; /* cursor is set to 'col-resize' using JS */ padding-top: 1px; float: none; display: table; diff --git a/python_docs_theme/static/sidebar.js_t b/python_docs_theme/static/sidebar.js_t index bb8d4fa5..63fe5683 100644 --- a/python_docs_theme/static/sidebar.js_t +++ b/python_docs_theme/static/sidebar.js_t @@ -57,6 +57,7 @@ const initialiseSidebar = () => { sidebarbutton.tabindex = "0" // make it focusable sidebarbutton.role = "slider" sidebarbutton.title = _("Resize sidebar") + sidebarbutton.style.cursor = "col-resize" // Set the cursor only if JS is enabled sidebarbutton.setAttribute("aria-label", _("Resize sidebar by dragging")) sidebarbutton.setAttribute( "aria-valuetext",