Path: blob/main/src/format/dashboard/format-dashboard-sidebar.ts
6451 views
/*1* format-dashboard-sidebar.ts2*3* Copyright (C) 2020-2022 Posit Software, PBC4*/56import { asCssSize } from "../../core/css.ts";7import { Document, Element } from "../../core/deno-dom.ts";8import { recursiveApplyFillClasses } from "./format-dashboard-layout.ts";9import { makeEl, processAndRemoveAttr } from "./format-dashboard-shared.ts";1011const kSidebarPanelClass = "sidebar-panel";12const kSidebarClass = "sidebar";13const kSidebarContentClass = "sidebar-content";1415const kSidebarAttrPosition = "data-position";16const kSidebarAttrPositionRight = "right";17const kBsLibSidebarRight = "sidebar-right";1819export function makeSidebar(20id: string,21sidebar: Element,22contents: Element[],23doc: Document,24) {25// Create the sidebar container26const sidebarContainerEl = makeEl("div", {27classes: ["bslib-sidebar-layout", "html-fill-item"],28attributes: {29"data-bslib-sidebar-open": "desktop",30"data-bslib-sidebar-init": "true",31},32}, doc);3334// Capture the content (the sidebar's next sibling)35const sidebarMainEl = makeEl("div", {36classes: ["main", "html-fill-container"],37}, doc);38contents.forEach((content) => {39sidebarMainEl.appendChild(content);40});4142// See if there is a width43// Read the position and apply class if needed44processAndRemoveAttr(45sidebar,46kSidebarAttrPosition,47(_el: Element, value: string) => {48if (value === kSidebarAttrPositionRight) {49sidebarContainerEl.classList.add(kBsLibSidebarRight);50}51},52);5354processAndRemoveAttr(55sidebar,56"data-width",57(_el: Element, value: string) => {58const size = asCssSize(value);5960const styleRaw = sidebarContainerEl.getAttribute("style");61const styleVal = styleRaw !== null ? styleRaw : "";62const newStyle = styleVal + " --bslib-sidebar-width: " + size;63sidebarContainerEl.setAttribute("style", newStyle);64},65);6667// Remove the sidebar class68sidebar?.classList.remove(kSidebarClass);6970const sidebarAsideEl = makeEl("aside", {71id,72classes: [kSidebarClass, "html-fill-container", "html-fill-item"],73}, doc);7475// place contents inside76if (sidebar !== null) {77sidebar.classList.add("html-fill-container", "html-fill-item");78sidebarAsideEl.appendChild(sidebar);79}8081sidebarContainerEl.appendChild(sidebarMainEl);82recursiveApplyFillClasses(sidebarContainerEl);8384sidebarContainerEl.appendChild(sidebarAsideEl);85sidebarContainerEl.append(...sidebarToggle(id, doc));86return sidebarContainerEl;87}8889export function processSidebars(doc: Document) {90// use a counter to provision ids91const sidebarNodes = doc.querySelectorAll(`.${kSidebarPanelClass}`);92let sidebarCount = 1;93for (const sidebarNode of sidebarNodes) {94const sidebarEl = sidebarNode as Element;95const sidebarId = sidebarEl.id !== ""96? sidebarEl.id97: `bslib-sidebar-${sidebarCount++}`;9899const sidebarContentsEl = sidebarEl.querySelector(`.${kSidebarClass}`);100const sidebarMainContentsEl = sidebarEl.querySelector(101`.${kSidebarContentClass}`,102);103104let sidebarContainerEl = undefined;105if (sidebarContentsEl !== null && sidebarMainContentsEl !== null) {106sidebarContainerEl = makeSidebar(sidebarId, sidebarContentsEl, [107sidebarMainContentsEl,108], doc);109sidebarEl.replaceWith(sidebarContainerEl);110sidebarContainerEl.parentElement?.classList.add(111"dashboard-sidebar-container",112);113}114}115116// Decorate the body of the document if there is a top level sidebar panel117const topLevelSidebar = doc.querySelector(118".page-layout-custom > .bslib-sidebar-layout, .page-layout-custom .dashboard-page > .bslib-sidebar-layout",119);120if (topLevelSidebar !== null) {121topLevelSidebar.setAttribute("data-bslib-sidebar-border", "false");122topLevelSidebar.setAttribute("data-bslib-sidebar-border-radius", "false");123124doc.body.classList.add("dashboard-sidebar");125}126}127128function sidebarToggle(id: string, doc: Document) {129const html = `130<button class="collapse-toggle" type="button" title="Toggle sidebar" aria-expanded="true" aria-controls="${id}">131<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="bi bi-chevron-left collapse-icon" style="fill:currentColor;" aria-hidden="true" role="img">132<path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"></path>133</svg>134</button>135<script data-bslib-sidebar-init>136bslib.Sidebar.initCollapsibleAll()137</script>138`;139const container = doc.createElement("DIV");140container.innerHTML = html;141return container.childNodes;142}143144145