From c38ce7b155c7da49d087ff8a43fa9fcfaf66523d Mon Sep 17 00:00:00 2001 From: Lenox Wiltshire Date: Sat, 13 Jun 2026 12:55:20 -0400 Subject: [PATCH 1/2] [feature]: Add the ability to resize the sidebars Signed-off-by: Lenox Wiltshire --- assets/js/sidebar-load-width.js | 18 ++++ assets/js/sidebar-resizer.js | 114 ++++++++++++++++++++ assets/scss/_styles_project.scss | 77 +++++++++++++ layouts/docs/baseof.html | 15 ++- layouts/partials/load-sidebars-width.html | 2 + layouts/partials/sidebar-resize-script.html | 2 + package-lock.json | 30 +++--- 7 files changed, 240 insertions(+), 18 deletions(-) create mode 100644 assets/js/sidebar-load-width.js create mode 100644 assets/js/sidebar-resizer.js create mode 100644 layouts/partials/load-sidebars-width.html create mode 100644 layouts/partials/sidebar-resize-script.html diff --git a/assets/js/sidebar-load-width.js b/assets/js/sidebar-load-width.js new file mode 100644 index 00000000000..913ce628bc6 --- /dev/null +++ b/assets/js/sidebar-load-width.js @@ -0,0 +1,18 @@ +(function () { + try { + var leftWidth = localStorage.getItem("left-sidebar-width"); + var tocWidth = localStorage.getItem("toc-width"); + var cssStyles = ""; + + if (leftWidth) cssStyles += "--left-sidebar-width: " + leftWidth + "px;"; + if (tocWidth) cssStyles += "--toc-width: " + tocWidth + "px;"; + + if (cssStyles) { + var styleTag = document.createElement("style"); + styleTag.innerHTML = ".td-resizable-grid .td-main > .row.flex-xl-nowrap {" + cssStyles + "}"; + document.head.appendChild(styleTag); + } + } catch (e) { + console.warn("LocalStorage blocked or unavailable:", e); + } +})(); \ No newline at end of file diff --git a/assets/js/sidebar-resizer.js b/assets/js/sidebar-resizer.js new file mode 100644 index 00000000000..f39d90fec1f --- /dev/null +++ b/assets/js/sidebar-resizer.js @@ -0,0 +1,114 @@ +(function () { + document.addEventListener("DOMContentLoaded", () => { + const gridContainer = document.querySelector(".td-resizable-grid .td-main > .row.flex-xl-nowrap"); + const leftResizer = document.getElementById("left-resizer"); + const rightResizer = document.getElementById("right-resizer"); + + if (!gridContainer) return; + + const LEFT_SIDEBAR_KEY = "left-sidebar-width"; + const TOC_KEY = "toc-width"; + + const storage = { + get: (key) => { + try { return localStorage.getItem(key); } + catch (e) { return null; } + }, + set: (key, value) => { + try { localStorage.setItem(key, value); } + catch (e) { return null; } + } + }; + + function setupResizer(resizer, type) { + resizer.addEventListener("pointerdown", (e) => { + e.preventDefault(); + + resizer.setPointerCapture(e.pointerId); + resizer.classList.add("is-dragging"); + + document.body.style.cursor = "col-resize"; + document.body.style.userSelect = "none"; + + const startX = e.clientX; + const styles = window.getComputedStyle(gridContainer); + const gridColumns = styles.gridTemplateColumns ? styles.gridTemplateColumns.split(" ") : []; + + /* + grid-template-columns over in _styles_project.scss has the following structure: + + --left-sidebar-width --sidebar-resize-width 1fr --sidebar-resize-width --toc-width; + + so gridcolumns[0] targets the left sidebar and gridcolumns[4] targets the toc + + */ + + let initialLeftSidebarWidth, initialTocWidth; + if (gridColumns.length >= 5 && gridColumns[0] !== "none") { + initialLeftSidebarWidth = parseInt(gridColumns[0], 10); + initialTocWidth = parseInt(gridColumns[4], 10); + } else { + initialLeftSidebarWidth = parseInt(styles.getPropertyValue('--left-sidebar-width'), 10); + initialTocWidth = parseInt(styles.getPropertyValue('--toc-width'), 10); + } + + const minWidth = parseInt(styles.getPropertyValue(type === "left" ? '--left-sidebar-min-width' : '--toc-min-width'), 10); + + const cssMaxWidth = parseInt(styles.getPropertyValue(type === "left" ? '--left-sidebar-max-width' : '--toc-max-width'), 10); + const maxAllowedByScreen = Math.floor(window.innerWidth * 0.4); + const maxWidth = Math.min(cssMaxWidth, maxAllowedByScreen); + + let currentWidth = type === "left" ? initialLeftSidebarWidth : initialTocWidth; + let ticking = false; + let animationFrameId = null; + + function onPointerMove(moveEvent) { + const deltaX = moveEvent.clientX - startX; + + if (type === "left") { + currentWidth = Math.max(minWidth, Math.min(maxWidth, initialLeftSidebarWidth + deltaX)); + } else if (type === "right") { + currentWidth = Math.max(minWidth, Math.min(maxWidth, initialTocWidth - deltaX)); + } + + if (!ticking) { + animationFrameId = window.requestAnimationFrame(() => { + const varName = type === "left" ? "--left-sidebar-width" : "--toc-width"; + gridContainer.style.setProperty(varName, `${currentWidth}px`); + ticking = false; + }); + ticking = true; + } + } + + function onPointerUp(upEvent) { + if (animationFrameId) { + window.cancelAnimationFrame(animationFrameId); + animationFrameId = null; + ticking = false; + } + + resizer.releasePointerCapture(upEvent.pointerId); + resizer.classList.remove("is-dragging"); + + document.body.style.cursor = ""; + document.body.style.userSelect = ""; + + const storageKey = type === "left" ? LEFT_SIDEBAR_KEY : TOC_KEY; + storage.set(storageKey, currentWidth); + + document.removeEventListener("pointermove", onPointerMove); + document.removeEventListener("pointerup", onPointerUp); + document.removeEventListener("pointercancel", onPointerUp); + } + + document.addEventListener("pointermove", onPointerMove); + document.addEventListener("pointerup", onPointerUp); + document.addEventListener("pointercancel", onPointerUp); + }); + } + + if (leftResizer) setupResizer(leftResizer, "left"); + if (rightResizer) setupResizer(rightResizer, "right"); + }); +})(); \ No newline at end of file diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index 5a34ccd09be..dc0b5b1fe4e 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -394,6 +394,83 @@ a:not([href]):not([class]):hover { } } +// Left sidebar & Right sidebar Resize +:root { + --left-sidebar-width: 240px; + --toc-width: 240px; + + --left-sidebar-min-width: 180px; + --left-sidebar-max-width: 500px; + + --toc-min-width: 180px; + --toc-max-width: 400px; + + --sidebar-resize-width: 5px; +} + +@media (min-width: 1200px) { + .td-resizable-grid .td-main > .row.flex-xl-nowrap { + display: grid; + grid-template-columns: + var(--left-sidebar-width) + var(--sidebar-resize-width) + 1fr + var(--sidebar-resize-width) + var(--toc-width); + } + + .td-sidebar { + grid-column: 1; + grid-row: 1; + } + + #left-resizer { + grid-column: 2; + grid-row: 1; + padding-left: 0 !important; + padding-right: 0 !important; + box-sizing: border-box; + } + + main[role="main"] { + grid-column: 3; + grid-row: 1; + } + + #right-resizer { + grid-column: 4; + grid-row: 1; + padding-left: 0 !important; + padding-right: 0 !important; + box-sizing: border-box; + } + + .td-sidebar-toc { + grid-column: 5; + grid-row: 1; + } + + .td-resizable-grid .td-sidebar, + .td-resizable-grid .td-sidebar-toc, + .td-resizable-grid main[role="main"] { + width: auto; + } + + //change the colors to something of meshery? + .layout-resizer { + width: var(--sidebar-resize-width); + cursor: col-resize; + background-color: rgba(0, 0, 0, 0.03); + transition: background-color 0.15s ease; + z-index: 1; //Must be lower than the sticky header + } + + .layout-resizer:hover, + .layout-resizer.is-dragging { + background-color: var(--primary, #007bff); + } +} + // pageinfo .pageinfo { font-weight: $font-weight-medium; diff --git a/layouts/docs/baseof.html b/layouts/docs/baseof.html index 3503963fb79..46ed5ee6110 100644 --- a/layouts/docs/baseof.html +++ b/layouts/docs/baseof.html @@ -7,17 +7,23 @@
{{ partial "navbar.html" . }}
-
+
+ +
+ +
+ +
{{ partial "version-banner.html" . }} {{ block "main" . }}{{ end }}
+ + {{ partial "load-sidebars-width.html" . }}
{{ partial "footer.html" . }}
{{ partial "scripts.html" . }} + {{ partial "sidebar-resize-script.html" }} {{ partial "image-modal.html" . }} diff --git a/layouts/partials/load-sidebars-width.html b/layouts/partials/load-sidebars-width.html new file mode 100644 index 00000000000..8e525e37e6b --- /dev/null +++ b/layouts/partials/load-sidebars-width.html @@ -0,0 +1,2 @@ +{{ $resizerScript := resources.Get "js/sidebar-load-width.js" | minify | fingerprint }} + \ No newline at end of file diff --git a/layouts/partials/sidebar-resize-script.html b/layouts/partials/sidebar-resize-script.html new file mode 100644 index 00000000000..2b8b9836f3d --- /dev/null +++ b/layouts/partials/sidebar-resize-script.html @@ -0,0 +1,2 @@ +{{ $resizerScript := resources.Get "js/sidebar-resizer.js" | minify | fingerprint }} + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 78f5ce407aa..7a86c1657a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -840,21 +840,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/typescript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/tinyglobby/node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -898,6 +883,21 @@ "node": ">=8.0" } }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", From 47724c03be4613ce4c2e6743612ce066cb3f4c7e Mon Sep 17 00:00:00 2001 From: Lenox Wiltshire Date: Tue, 16 Jun 2026 12:55:08 -0400 Subject: [PATCH 2/2] [chore] .scss cleanup, logic spread to small screens for responsiveness and added the logic to all of the other layouts making use of sidebar and toc Signed-off-by: Lenox Wiltshire --- assets/js/sidebar-load-width.js | 10 ++-- assets/js/sidebar-resizer.js | 11 +++-- assets/scss/_styles_project.scss | 57 +++++++++++++---------- layouts/404.html | 12 ++++- layouts/docs/baseof.html | 2 +- layouts/partials/load-sidebars-width.html | 3 +- layouts/release/baseof.html | 11 ++++- layouts/video/baseof.html | 17 +++++-- 8 files changed, 80 insertions(+), 43 deletions(-) diff --git a/assets/js/sidebar-load-width.js b/assets/js/sidebar-load-width.js index 913ce628bc6..698c03e62e4 100644 --- a/assets/js/sidebar-load-width.js +++ b/assets/js/sidebar-load-width.js @@ -1,11 +1,11 @@ (function () { try { - var leftWidth = localStorage.getItem("left-sidebar-width"); - var tocWidth = localStorage.getItem("toc-width"); + var leftWidth = parseInt(localStorage.getItem("left-sidebar-width"), 10); + var tocWidth = parseInt(localStorage.getItem("toc-width"), 10); var cssStyles = ""; - - if (leftWidth) cssStyles += "--left-sidebar-width: " + leftWidth + "px;"; - if (tocWidth) cssStyles += "--toc-width: " + tocWidth + "px;"; + + if (!isNaN(leftWidth)) cssStyles += "--left-sidebar-width: " + leftWidth + "px;"; + if (!isNaN(tocWidth)) cssStyles += "--toc-width: " + tocWidth + "px;"; if (cssStyles) { var styleTag = document.createElement("style"); diff --git a/assets/js/sidebar-resizer.js b/assets/js/sidebar-resizer.js index f39d90fec1f..fd36d0103d0 100644 --- a/assets/js/sidebar-resizer.js +++ b/assets/js/sidebar-resizer.js @@ -34,13 +34,16 @@ const styles = window.getComputedStyle(gridContainer); const gridColumns = styles.gridTemplateColumns ? styles.gridTemplateColumns.split(" ") : []; - /* + /* grid-template-columns over in _styles_project.scss has the following structure: + min(768px) + --left-sidebar-width --sidebar-resize-width 1fr + + min(1200px) --left-sidebar-width --sidebar-resize-width 1fr --sidebar-resize-width --toc-width; so gridcolumns[0] targets the left sidebar and gridcolumns[4] targets the toc - */ let initialLeftSidebarWidth, initialTocWidth; @@ -54,9 +57,7 @@ const minWidth = parseInt(styles.getPropertyValue(type === "left" ? '--left-sidebar-min-width' : '--toc-min-width'), 10); - const cssMaxWidth = parseInt(styles.getPropertyValue(type === "left" ? '--left-sidebar-max-width' : '--toc-max-width'), 10); - const maxAllowedByScreen = Math.floor(window.innerWidth * 0.4); - const maxWidth = Math.min(cssMaxWidth, maxAllowedByScreen); + const maxWidth = parseInt(styles.getPropertyValue(type === "left" ? '--left-sidebar-max-width' : '--toc-max-width'), 10); let currentWidth = type === "left" ? initialLeftSidebarWidth : initialTocWidth; let ticking = false; diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index dc0b5b1fe4e..f18d4ca17a9 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -408,15 +408,32 @@ a:not([href]):not([class]):hover { --sidebar-resize-width: 5px; } -@media (min-width: 1200px) { +.layout-resizer { + width: var(--sidebar-resize-width); + cursor: col-resize; + background-color: rgba(0, 0, 0, 0.03); + transition: background-color 0.15s ease; + z-index: 1; //Must be lower than the sticky header +} + +.layout-resizer:hover, +.layout-resizer.is-dragging { + background-color: $primary; +} + +.td-resizable-grid .td-sidebar, +.td-resizable-grid .td-sidebar-toc, +.td-resizable-grid main[role="main"] { + width: auto; +} + +@media (min-width: 768px) { .td-resizable-grid .td-main > .row.flex-xl-nowrap { display: grid; grid-template-columns: var(--left-sidebar-width) var(--sidebar-resize-width) - 1fr - var(--sidebar-resize-width) - var(--toc-width); + 1fr; } .td-sidebar { @@ -436,6 +453,18 @@ a:not([href]):not([class]):hover { grid-column: 3; grid-row: 1; } +} + +@media (min-width: 1200px) { + .td-resizable-grid .td-main > .row.flex-xl-nowrap { + display: grid; + grid-template-columns: + var(--left-sidebar-width) + var(--sidebar-resize-width) + 1fr + var(--sidebar-resize-width) + var(--toc-width); + } #right-resizer { grid-column: 4; @@ -449,26 +478,6 @@ a:not([href]):not([class]):hover { grid-column: 5; grid-row: 1; } - - .td-resizable-grid .td-sidebar, - .td-resizable-grid .td-sidebar-toc, - .td-resizable-grid main[role="main"] { - width: auto; - } - - //change the colors to something of meshery? - .layout-resizer { - width: var(--sidebar-resize-width); - cursor: col-resize; - background-color: rgba(0, 0, 0, 0.03); - transition: background-color 0.15s ease; - z-index: 1; //Must be lower than the sticky header - } - - .layout-resizer:hover, - .layout-resizer.is-dragging { - background-color: var(--primary, #007bff); - } } // pageinfo diff --git a/layouts/404.html b/layouts/404.html index 410580771b7..acb3db8ac78 100644 --- a/layouts/404.html +++ b/layouts/404.html @@ -7,17 +7,24 @@
{{ partial "navbar.html" . }}
-
+
+ +
+ +
+ + +
{{ partial "version-banner.html" . }} {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }} @@ -27,11 +34,14 @@

Not found

Please let us know about this issue and return to the home page.

{{ end }}
+ + {{ partial "load-sidebars-width.html" . }}
{{ partial "footer.html" . }}
{{ partial "scripts.html" . }} + {{ partial "sidebar-resize-script.html" }} diff --git a/layouts/docs/baseof.html b/layouts/docs/baseof.html index 46ed5ee6110..e75bf3f4427 100644 --- a/layouts/docs/baseof.html +++ b/layouts/docs/baseof.html @@ -14,7 +14,7 @@ {{ partial "sidebar.html" . }} -
+
diff --git a/layouts/partials/load-sidebars-width.html b/layouts/partials/load-sidebars-width.html index 8e525e37e6b..4e206de7dd6 100644 --- a/layouts/partials/load-sidebars-width.html +++ b/layouts/partials/load-sidebars-width.html @@ -1,2 +1,3 @@ + {{ $resizerScript := resources.Get "js/sidebar-load-width.js" | minify | fingerprint }} - \ No newline at end of file + \ No newline at end of file diff --git a/layouts/release/baseof.html b/layouts/release/baseof.html index 2145f978f24..66b5d9311e8 100644 --- a/layouts/release/baseof.html +++ b/layouts/release/baseof.html @@ -13,12 +13,17 @@ class="td-{{ .Kind }}{{ with .Page.Params.body_class }} {{ . }}{{ end }}" >
{{ partial "navbar.html" . }}
-
+
+ +
+ +
+
{{ partial "footer.html" . }}
- {{ partial "scripts.html" . }} {{ partial "image-modal.html" . }} + {{ partial "scripts.html" . }} {{ partial "sidebar-resize-script.html" }} {{ partial "image-modal.html" . }} \ No newline at end of file diff --git a/layouts/video/baseof.html b/layouts/video/baseof.html index 7f988f54859..1ce62809758 100644 --- a/layouts/video/baseof.html +++ b/layouts/video/baseof.html @@ -13,26 +13,35 @@ class="td-{{ .Kind }}{{ with .Page.Params.body_class }} {{ . }}{{ end }}" >
{{ partial "navbar.html" . }}
-
+
+ +
+ +
+ +
{{ partial "version-banner.html" . }} {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }} {{ block "main" . }}{{ end }}
+ + {{ partial "load-sidebars-width.html" . }}
{{ partial "footer.html" . }}
{{partial "video-category-navigation.html" .}} - {{ partial "scripts.html" . }} {{ partial "image-modal.html" . }} + {{ partial "scripts.html" . }} {{ partial "image-modal.html" . }} {{ partial "sidebar-resize-script.html" }}