diff --git a/assets/js/resizable.js b/assets/js/resizable.js new file mode 100644 index 00000000000..012c8b36abc --- /dev/null +++ b/assets/js/resizable.js @@ -0,0 +1,94 @@ +(function () { + "use strict"; + + function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); } + + function init(el) { + if (el.__resizableReady) return; + + var side = el.dataset.resizableSide || "right"; + var key = el.dataset.resizableKey; + if (!key) return; + var storeKey = "resizable:" + key; + var min = parseFloat(el.dataset.resizableMin) || 0; + var max = parseFloat(el.dataset.resizableMax) || Infinity; + var def = parseFloat(el.dataset.resizableDefault) || min || 280; + var handle = el.querySelector(":scope > .resizable__handle"); + if (!handle) return; + + el.__resizableReady = true; + + function setWidth(px) { + var w = clamp(px, min, max); + el.style.setProperty("--resizable-w", w + "px"); + handle.setAttribute("aria-valuenow", String(Math.round(w))); + } + + function save() { + localStorage.setItem(storeKey, parseFloat(getComputedStyle(el).width)); + } + + var saved = parseFloat(localStorage.getItem(storeKey)); + setWidth(isNaN(saved) ? def : saved); + + var startX = 0, startW = 0; + + function onMove(e) { + var delta = side === "right" ? e.clientX - startX : startX - e.clientX; + setWidth(startW + delta); + } + function onUp(e) { + // Capture may already be released (e.g. the element was detached); guard it + // so a stray pointercancel can't leave listeners and is-resizing state stuck. + if (handle.hasPointerCapture(e.pointerId)) handle.releasePointerCapture(e.pointerId); + window.removeEventListener("pointermove", onMove); + window.removeEventListener("pointerup", onUp); + window.removeEventListener("pointercancel", onUp); + el.classList.remove("is-resizing"); + document.body.classList.remove("is-resizing"); + save(); + } + + handle.addEventListener("pointerdown", function (e) { + e.preventDefault(); + startX = e.clientX; + startW = el.getBoundingClientRect().width; + handle.setPointerCapture(e.pointerId); + el.classList.add("is-resizing"); + document.body.classList.add("is-resizing"); + window.addEventListener("pointermove", onMove); + window.addEventListener("pointerup", onUp); + window.addEventListener("pointercancel", onUp); + }); + + handle.addEventListener("dblclick", function () { setWidth(def); save(); }); + + // Keyboard accessibility + handle.setAttribute("role", "separator"); + handle.setAttribute("aria-orientation", "vertical"); + handle.setAttribute("aria-label", "Resize " + key + " panel"); + handle.setAttribute("aria-valuemin", String(Math.round(min))); + if (isFinite(max)) handle.setAttribute("aria-valuemax", String(Math.round(max))); + handle.setAttribute("tabindex", "0"); + handle.addEventListener("keydown", function (e) { + var grow = side === "right" ? "ArrowRight" : "ArrowLeft"; + var shrink = side === "right" ? "ArrowLeft" : "ArrowRight"; + var step = e.shiftKey ? 40 : 12; + var w = parseFloat(getComputedStyle(el).width); + if (e.key === grow) w += step; + else if (e.key === shrink) w -= step; + else return; + e.preventDefault(); + setWidth(w); + save(); + }); + } + + function initAll() { + document.querySelectorAll("[data-resizable]").forEach(init); + } + + if (document.readyState === "loading") + document.addEventListener("DOMContentLoaded", initAll); + else initAll(); +})(); diff --git a/assets/js/sidebar-load-width.js b/assets/js/sidebar-load-width.js deleted file mode 100644 index 84dd8c6f8bf..00000000000 --- a/assets/js/sidebar-load-width.js +++ /dev/null @@ -1,18 +0,0 @@ -(function () { - try { - var leftWidth = parseInt(localStorage.getItem("left-sidebar-width"), 10); - var tocWidth = parseInt(localStorage.getItem("toc-width"), 10); - var cssStyles = ""; - - if (!isNaN(leftWidth)) cssStyles += "--left-sidebar-width: " + leftWidth + "px;"; - if (!isNaN(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 deleted file mode 100644 index d0102c4fc05..00000000000 --- a/assets/js/sidebar-resizer.js +++ /dev/null @@ -1,113 +0,0 @@ -(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: - - 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; - 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 maxWidth = parseInt(styles.getPropertyValue(type === "left" ? '--left-sidebar-max-width' : '--toc-max-width'), 10); - 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/_content_project.scss b/assets/scss/_content_project.scss index acdefabb70c..b531674f7e6 100644 --- a/assets/scss/_content_project.scss +++ b/assets/scss/_content_project.scss @@ -315,3 +315,45 @@ th { } } } + +// Shared ecosystem callout box (emitted by the `ecosystem-box` shortcode). +$ecosystem-box-glow: inset 0 0em 4em #ebc01766, 0 0 0 2px #ebc01766, 0.3em 0.3em 1em #ebc01733; + +%ecosystem-box-base { + display: flex; + align-items: center; + font-style: italic; + gap: 0.5rem; + padding: 1rem; + margin: auto -1rem; + transition: box-shadow 0.3s ease; + text-decoration: none; + color: inherit; + + img { + height: 65px; + width: 65px; + border: 0; + background: transparent; + } +} + +.highlight-box { + @extend %ecosystem-box-base; + box-shadow: $ecosystem-box-glow; +} + +.hidden-highlight-box { + @extend %ecosystem-box-base; + box-shadow: none; + + &:hover { + box-shadow: $ecosystem-box-glow; + } + + /* Hide the sibling highlight-box's shadow when this one is hovered/focused */ + &:hover ~ .highlight-box, + &:focus ~ .highlight-box { + box-shadow: none; + } +} diff --git a/assets/scss/_resizable-bootstrap-overrides.scss b/assets/scss/_resizable-bootstrap-overrides.scss new file mode 100644 index 00000000000..777ba2939e4 --- /dev/null +++ b/assets/scss/_resizable-bootstrap-overrides.scss @@ -0,0 +1,86 @@ +/* resizable-bootstrap-overrides.scss — load ONLY in Bootstrap/Docsy consumers. + Reason: Bootstrap applies `.row > * { width:100%; max-width:100%; padding-inline }` + to every direct row child. Since .resizable is now a direct child of .row, + that rule overrides the component's own width. These selectors are 0,2,0, + so they win over `.row > *` (0,1,0) without !important. + Do NOT fold these into resizable.scss — they assume a Bootstrap `.row`. */ + +.row > .resizable { + flex: 0 0 auto; + width: var(--resizable-w, 260px); + max-width: var(--resizable-max, 480px); + min-width: 0; + padding-inline: 0; // clear Bootstrap's gutter padding on the wrapper +} + +/* Sidebar(s) are now fixed-px wrappers, not percentage columns, so main must + absorb the remaining space instead of holding col-xl-8's 66.66% max-width. */ +.row > main { + flex: 1 1 0; + max-width: none; + width: auto; +} + +/* ── Sidebar wrapper inherits the sticky + full-height role ── + .td-sidebar was sticky as a direct .row child. Now .resizable is the + direct .row child, so the wrapper must carry sticky/height. Values match + .td-sidebar's originals (top: 5.5rem, height: calc(100vh - 5.5rem)). */ +[data-resizable-key="sidebar"] { + position: sticky; + top: 5.5rem; + height: calc(100vh - 5.5rem); + align-self: flex-start; // stick instead of stretching to row height + overflow: hidden; // wrapper clips; the aside scrolls internally +} + +[data-resizable-key="sidebar"] .resizable__inner { + height: 100%; + overflow: hidden; +} + +/* Demote the aside: the wrapper is sticky now, so .td-sidebar becomes a + plain full-height scroll panel. Keeps its gradient + padding; only the + positioning role moves up to the wrapper. */ +[data-resizable-key="sidebar"] .td-sidebar { + position: static; + height: 100%; // fill wrapper, not 100vh + top: auto; + // background-image, padding-top, overflow-y: auto, overflow-x: hidden + // all remain from the base rule and still apply. +} + +@media screen and (max-width: 768px) { + /* Break the nowrap row so children can stack on their own lines. */ + .row.flex-xl-nowrap { + flex-wrap: wrap; + } + + /* Sidebar: its own full-width row, on top, not resizable. */ + .row > .resizable[data-resizable-key="sidebar"] { + position: relative; /* NOT static — keeps handle anchored if shown; prevents overlap */ + flex: 1 1 100%; /* full row */ + top: auto; + width: 100%; + max-width: none; + height: auto; /* was fit-content — auto is safer for stacked flow */ + overflow: visible; + order: 0; /* ensure it comes before main */ + box-sizing: border-box; /* padding counts inside the 100%, not added to it */ + padding-inline: 0; /* clear Bootstrap's gutter that returns at mobile */ + } + + /* Inner + aside follow the auto height instead of the desktop 100vh. */ + [data-resizable-key="sidebar"] .resizable__inner { height: auto; overflow: visible; } + [data-resizable-key="sidebar"] .td-sidebar { height: auto; } + + .row > main { + flex: 1 1 100%; + max-width: none; + order: 1; /* after the sidebar */ + } + + .resizable .resizable__handle { + display: none; + pointer-events: none; + } +} diff --git a/assets/scss/_resizable.scss b/assets/scss/_resizable.scss new file mode 100644 index 00000000000..448aa40a99e --- /dev/null +++ b/assets/scss/_resizable.scss @@ -0,0 +1,57 @@ +/* resizable.scss — portable, layout-agnostic. Ships to every consumer as-is. + The component governs its own width via --resizable-w and exposes hooks + (.resizable, .resizable__inner, .resizable__handle). It makes NO assumptions + about the parent layout (grid/flex/Bootstrap). Host-specific overrides, if + any, live in a separate file in the consuming repo. */ + +.resizable { + position: relative; + box-sizing: border-box; + flex: 0 0 auto; + width: var(--resizable-w, var(--resizable-default, 300px)); + min-width: var(--resizable-min, 0); + max-width: var(--resizable-max, none); +} + +.resizable__inner { + display: flex; + width: 100%; + height: 100%; + min-width: 0; +} + +.resizable__inner > * { + flex: 1 1 auto; + min-width: 0; +} + +.resizable__handle { + position: absolute; + inset-block: 0; + width: 15px; + cursor: col-resize; + touch-action: none; + user-select: none; + z-index: 30; +} +.resizable--right .resizable__handle { right: -5px; } +.resizable--left .resizable__handle { left: -5px; } + +.resizable__handle::after { + content: ""; + position: absolute; + inset-block: 0; + left: 50%; + width: 3px; + transform: translateX(-50%); + background: transparent; + transition: background 120ms ease; +} +.resizable__handle:hover::after, +.resizable__handle:focus-visible::after, +.resizable.is-resizing .resizable__handle::after { + background: #00b39f; +} + +body.is-resizing { cursor: col-resize; user-select: none; } +body.is-resizing * { cursor: col-resize !important; } diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index 08e017bf568..9997bcb5bb5 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -15,6 +15,8 @@ @import "elements_project"; @import "summary.scss"; @import "_kanvas-corner-popup.scss"; +@import "_resizable.scss"; +@import "_resizable-bootstrap-overrides.scss"; .navbar-dark { min-height: 5rem; @@ -406,98 +408,6 @@ 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; -} - -.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; -} - -@include media-breakpoint-down(sm) { - .td-resizable-grid .td-sidebar { - width: 100%; - } -} - -@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; - } - - .td-sidebar { - grid-column: 1; - grid-row: 1; - } - - #left-resizer { - grid-column: 2; - grid-row: 1; - padding-left: 0; - padding-right: 0; - box-sizing: border-box; - } - - main[role="main"] { - 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; - grid-row: 1; - padding-left: 0; - padding-right: 0; - box-sizing: border-box; - } - - .td-sidebar-toc { - grid-column: 5; - grid-row: 1; - } -} - // pageinfo .pageinfo { font-weight: $font-weight-medium; @@ -628,7 +538,7 @@ a:not([href]):not([class]):hover { margin-bottom: 4rem; font-size: 5rem; text-align: left; - background-image: + background-image: linear-gradient(to right, rgba(255, 255, 255, .9) 0px, rgb(0, 211, 169) 34%, rgb(235, 192, 23) 71%, rgb(255,243,197) 100%); background-position: 0% 0%, @@ -724,11 +634,11 @@ a:not([href]):not([class]):hover { .dash-sign-container { display: flex; align-items: center; - justify-content: space-between; + justify-content: space-between; text-align: right; h1.dashboard { - max-width: 70%; + max-width: 70%; text-align: left; flex-shrink: 0; @media (max-width: 768px) { diff --git a/content/en/cloud/_index.md b/content/en/cloud/_index.md index 5ed03f7db28..a05a512b064 100755 --- a/content/en/cloud/_index.md +++ b/content/en/cloud/_index.md @@ -5,71 +5,22 @@ description: > linkTitle: Cloud type: docs menu: {main: {weight: 2}} -cascade: +cascade: type: docs --- {{% pageinfo %}} - - ## Understanding the Layer5 Ecosystem -
- -
{{< svg name="cloud" >}}
- -
- - **Layer5 Cloud** is an identity provider and global console for Kanvas and Meshery deployments with an extensible and highly flexible authorization framework, tenant entitlement services, service provider-grade organizational hierarchy, team workspace management and a content catalog for public and private hosting of cloud native architectures. Layer5 Cloud is available as a service or self-hosted. -
-
+{{< ecosystem-box icon="cloud" title="Layer5 Cloud" >}} +is an identity provider and global console for Kanvas and Meshery deployments with an extensible and highly flexible authorization framework, tenant entitlement services, service provider-grade organizational hierarchy, team workspace management and a content catalog for public and private hosting of cloud native architectures. Layer5 Cloud is available as a service or self-hosted. +{{< /ecosystem-box >}} -}}"> -
-
- kanvas logo -
-
- Kanvas delivers a collaborative experience similar to how Google Workplace transforms the digital work environment and how Figma democratizes UX design tooling. Kanvas simplifies the complexity of Kubernetes and multi-cloud infrastructure management accessible to all. Kanvas provides a visual, multi-player experience that allows you to create, configure, deploy, and manage modern infrastructure with confidence. -
-
-
+{{< ecosystem-box link="kanvas/_index.md" icon="images/logos/kanvas-icon-color.svg" image="true" class="hidden-highlight-box" title="Kanvas" >}} +delivers a collaborative experience similar to how Google Workplace transforms the digital work environment and how Figma democratizes UX design tooling. Kanvas simplifies the complexity of Kubernetes and multi-cloud infrastructure management accessible to all. Kanvas provides a visual, multi-player experience that allows you to create, configure, deploy, and manage modern infrastructure with confidence. +{{< /ecosystem-box >}} - {{% /pageinfo %}} ## What is Layer5 Cloud? diff --git a/content/en/kanvas/_index.md b/content/en/kanvas/_index.md index 90e060f22d6..683d4d3b35b 100755 --- a/content/en/kanvas/_index.md +++ b/content/en/kanvas/_index.md @@ -1,11 +1,11 @@ --- title: Kanvas Documentation -description: Kanvas delivers a collaborative experience for engineers similar to how Google Workplace transforms the digital work environment and how Figma democratizes UX design tooling. +description: Kanvas delivers a collaborative experience for engineers similar to how Google Workplace transforms the digital work environment and how Figma democratizes UX design tooling. linkTitle: Kanvas type: docs menu: {main: {weight: 3}} weight: 1 -cascade: +cascade: type: docs aliases: - /meshmap/ @@ -20,60 +20,16 @@ aliases: {{% pageinfo %}} - ## Understanding the Layer5 Ecosystem -}}"> -
-
{{< svg name="cloud" >}}
-
- Layer5 Cloud is an identity provider and global console for deployments with an extensible and highly flexible authorization framework, tenant entitlement services, service provider-grade organizational hierarchy, team workspace management and a content catalog for public and private hosting of cloud native architectures. Layer5 Cloud is available as a service or self-hosted. -
-
-
+{{< ecosystem-box link="cloud/_index.md" icon="cloud" class="hidden-highlight-box" title="Layer5 Cloud" >}} +is an identity provider and global console for deployments with an extensible and highly flexible authorization framework, tenant entitlement services, service provider-grade organizational hierarchy, team workspace management and a content catalog for public and private hosting of cloud native architectures. Layer5 Cloud is available as a service or self-hosted. +{{< /ecosystem-box >}} +{{< ecosystem-box icon="images/logos/kanvas-icon-color.svg" image="true" title="Kanvas" >}} +delivers a collaborative experience similar to how Google Workplace transforms the digital work environment and how Figma democratizes UX design tooling. Kanvas simplifies the complexity of Kubernetes and multi-cloud infrastructure management accessible to all. Kanvas provides a visual, multi-player experience that allows you to create, configure, deploy, and manage modern infrastructure with confidence. +{{< /ecosystem-box >}} -}}"> -
-
-kanvas logo
-
-Kanvas delivers a collaborative experience similar to how Google Workplace transforms the digital work environment and how Figma democratizes UX design tooling. Kanvas simplifies the complexity of Kubernetes and multi-cloud infrastructure management accessible to all. Kanvas provides a visual, multi-player experience that allows you to create, configure, deploy, and manage modern infrastructure with confidence.
-
- {{% /pageinfo %}} ## What is Kanvas? diff --git a/layouts/404.html b/layouts/404.html index 56eeb26e34f..70c9eec226c 100644 --- a/layouts/404.html +++ b/layouts/404.html @@ -2,29 +2,20 @@ {{ partial "head.html" . }} - {{ partial "load-sidebars-width.html" . }} + {{ partial "resizable-head-script.html" . }}
{{ partial "navbar.html" . }}
-
+
- - -
- -
- - - + {{ partial "resizable-start.html" (dict "side" "right" "key" "sidebar" "min" 200 "max" 480 "default" 260) }} + + {{ partial "resizable-end.html" . }}
{{ partial "version-banner.html" . }} @@ -35,12 +26,20 @@

Not found

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

{{ end }}
+ + {{ partial "resizable-start.html" (dict "side" "left" "key" "toc" "min" 200 "max" 420 "default" 240 "class" "d-none d-xl-block") }} + + {{ partial "resizable-end.html" . }}
{{ partial "footer.html" . }}
{{ partial "scripts.html" . }} - {{ partial "sidebar-resize-script.html" }} + {{ partialCached "resizable-script.html" . }} diff --git a/layouts/docs/baseof.html b/layouts/docs/baseof.html index f66c4a5f5be..8766bc5985e 100644 --- a/layouts/docs/baseof.html +++ b/layouts/docs/baseof.html @@ -3,27 +3,19 @@ {{ partial "head.html" . }} - {{ partial "load-sidebars-width.html" . }} + {{ partial "resizable-head-script.html" . }}
{{ partial "navbar.html" . }}
-
+
- - -
- -
- - + {{ partial "resizable-start.html" (dict "side" "right" "key" "sidebar" "min" 200 "max" 480 "default" 260) }} + + {{ partial "resizable-end.html" . }}
{{ partial "version-banner.html" . }} {{ block "main" . }}{{ end }}
+ {{ partial "resizable-start.html" (dict "side" "left" "key" "toc" "min" 200 "max" 420 "default" 240 "class" "d-none d-xl-block") }} + + {{ partial "resizable-end.html" . }}
{{ partial "footer.html" . }}
{{ partial "scripts.html" . }} - {{ partial "sidebar-resize-script.html" }} + {{ partialCached "resizable-script.html" . }} {{ partial "image-modal.html" . }} diff --git a/layouts/partials/load-sidebars-width.html b/layouts/partials/load-sidebars-width.html deleted file mode 100644 index 5c782c5fee6..00000000000 --- a/layouts/partials/load-sidebars-width.html +++ /dev/null @@ -1,2 +0,0 @@ -{{ $resizerScript := resources.Get "js/sidebar-load-width.js" | minify | fingerprint }} - \ No newline at end of file diff --git a/layouts/partials/resizable-end.html b/layouts/partials/resizable-end.html new file mode 100644 index 00000000000..abc67c48af4 --- /dev/null +++ b/layouts/partials/resizable-end.html @@ -0,0 +1,3 @@ +
+
+
diff --git a/layouts/partials/resizable-head-script.html b/layouts/partials/resizable-head-script.html new file mode 100644 index 00000000000..11ee00e7264 --- /dev/null +++ b/layouts/partials/resizable-head-script.html @@ -0,0 +1,24 @@ + diff --git a/layouts/partials/resizable-script.html b/layouts/partials/resizable-script.html new file mode 100644 index 00000000000..b40a7db30d4 --- /dev/null +++ b/layouts/partials/resizable-script.html @@ -0,0 +1,8 @@ +{{ with resources.Get "js/resizable.js" }} + {{ if hugo.IsProduction }} + {{ $js := . | minify | fingerprint }} + + {{ else }} + + {{ end }} +{{ end }} diff --git a/layouts/partials/resizable-start.html b/layouts/partials/resizable-start.html new file mode 100644 index 00000000000..9108196bc25 --- /dev/null +++ b/layouts/partials/resizable-start.html @@ -0,0 +1,17 @@ +{{- /* Params: draggable-side ("right"|"left"), localStorage key for persisting the width (unique, required), + min, max, default (px), class (optional extra classes) */ -}} +{{- $side := .side | default "right" -}} +{{- $key := .key -}} +{{- $min := .min | default 180 -}} +{{- $max := .max | default 500 -}} +{{- $def := .default | default 300 -}} +{{- $class := .class | default "" -}} +
+
diff --git a/layouts/partials/sidebar-resize-script.html b/layouts/partials/sidebar-resize-script.html deleted file mode 100644 index 2b8b9836f3d..00000000000 --- a/layouts/partials/sidebar-resize-script.html +++ /dev/null @@ -1,2 +0,0 @@ -{{ $resizerScript := resources.Get "js/sidebar-resizer.js" | minify | fingerprint }} - \ No newline at end of file diff --git a/layouts/release/baseof.html b/layouts/release/baseof.html index b06e06d5a29..18f45f566dd 100644 --- a/layouts/release/baseof.html +++ b/layouts/release/baseof.html @@ -8,36 +8,38 @@ > {{ partial "head.html" . }} - {{ partial "load-sidebars-width.html" . }} + {{ partial "resizable-head-script.html" . }}
{{ partial "navbar.html" . }}
-
+
- + {{ partial "resizable-start.html" (dict "side" "right" "key" "sidebar" "min" 200 "max" 480 "default" 260) }} + + {{ partial "resizable-end.html" . }} -
- -
- -
{{ partial "version-banner.html" . }} {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . - }}{{ end }} {{ block "main" . }}{{ end }} + }}{{ end }} {{ block "main" . }}{{ end }}
+ + {{ partial "resizable-start.html" (dict "side" "left" "key" "toc" "min" 200 "max" 420 "default" 240 "class" "d-none d-xl-block") }} + + {{ partial "resizable-end.html" . }}
{{ partial "footer.html" . }}
- {{ partial "scripts.html" . }} {{ partial "sidebar-resize-script.html" }} {{ partial "image-modal.html" . }} + {{ partial "scripts.html" . }} {{ partialCached "resizable-script.html" . }}{{ partial "image-modal.html" . }} \ No newline at end of file diff --git a/layouts/shortcodes/ecosystem-box.html b/layouts/shortcodes/ecosystem-box.html new file mode 100644 index 00000000000..f60002573de --- /dev/null +++ b/layouts/shortcodes/ecosystem-box.html @@ -0,0 +1,42 @@ +{{- /* + Balanced ecosystem callout box. Authors pass params + inner text only. + Usage: + {{< ecosystem-box link="cloud/_index.md" icon="cloud" title="Layer5 Cloud" >}} + description text... + {{< /ecosystem-box >}} + + Params: + link - (optional) ref path to the target page. Omit for the box that + represents the current page so it doesn't render as a self-link. + icon - svg name (from assets/icons/) OR image path if image="true" + title - bold lead-in before the description + image - (optional) "true" to treat `icon` as an image src instead of an svg name + class - (optional) "highlight-box" (default) or "hidden-highlight-box" +*/ -}} + +{{- $link := .Get "link" -}} +{{- $icon := .Get "icon" -}} +{{- $title := .Get "title" -}} +{{- $class := .Get "class" | default "highlight-box" -}} +{{- $isImage := eq (.Get "image") "true" -}} + +{{- /* Keep the wrapper a literal so Goldmark recognises this as a raw HTML + block and preserves it verbatim. Emit href only when a link is supplied; + an href-less is a non-link, which avoids a self-referential link on + the box that represents the current page. */ -}} + + + {{- if $isImage -}} + {{ $title }} logo + {{- else -}} + {{- with resources.Get (printf "icons/%s.svg" $icon) -}} + {{- .Content | safeHTML -}} + {{- else -}} + + {{- end -}} + {{- end -}} + + + {{ $title }} {{ .Inner | .Page.RenderString }} + + diff --git a/layouts/video/baseof.html b/layouts/video/baseof.html index 5ab0781f86e..ac772ee7105 100644 --- a/layouts/video/baseof.html +++ b/layouts/video/baseof.html @@ -8,39 +8,39 @@ > {{ partial "head.html" . }} - {{ partial "load-sidebars-width.html" . }} + {{ partial "resizable-head-script.html" . }}
{{ partial "navbar.html" . }}
-
+
- - -
- -
- - + {{ partial "resizable-start.html" (dict "side" "right" "key" "sidebar" "min" 200 "max" 480 "default" 260) }} + + {{ partial "resizable-end.html" . }}
{{ partial "version-banner.html" . }} {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . - }}{{ end }} {{ block "main" . }}{{ end }} + }}{{ end }} {{ block "main" . }}{{ end }}
+ + {{ partial "resizable-start.html" (dict "side" "left" "key" "toc" "min" 200 "max" 420 "default" 240 "class" "d-none d-xl-block") }} + + {{ partial "resizable-end.html" . }}
{{ partial "footer.html" . }}
{{partial "video-category-navigation.html" .}} - {{ partial "scripts.html" . }} {{ partial "image-modal.html" . }} {{ partial "sidebar-resize-script.html" }} + {{ partial "scripts.html" . }} {{ partial "image-modal.html" . }} {{ partialCached "resizable-script.html" . }}