A popup style sidebar for Spotfire
How to use
Add a TextArea and edit the HTML. Add the sample html code below and then the provided JavaScript at the end. Just create a new script and copy+paste the code from the sidebar-popup.js into a new JavaScript.
html
Example no navigation grouping
<DIV id="sidebar" style="FONT-SIZE: 20px; BACKGROUND: #3498db; COLOR: white"></DIV> <span id="sidebar-logo">C. Corp</span> <DIV id="sidebar-nav" > <a>Page 1</a> <a>Page 2</a> <a>SpotfireControl (repalce with link spotfire control)</a> <a>Page 4</a> <a>Page 5</a> <a>Page 6</a> <a>Page 7</a> <a>Page 8</a> </div> <div id="sidebar-nav-icons" >house,user,circle,box,umbrella,music,heart,gear</div> <div id="sidebar-controls"> <div>Control group 1</div> <div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> </div> <div>Control group 2</div> <div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> </div> </div>
Example with groups
<DIV id="sidebar" style="FONT-SIZE: 15px; BACKGROUND: #3498db; COLOR: white"></DIV> <span id="sidebar-logo"> <img src="bffeccd1047746e5bd1a3a11c6048a9d.png"/> </span> <DIV id="sidebar-nav" > <a>Page 1</a> <li> <a>Page 2***</a> <a>Page 3</a> </li> <a>Page 4</a> <li> <a>Page 5</a> <a>Page 6</a> </li> <a>Page 7</a> <li> <a>Page 8</a> </li> </div> <div id="sidebar-nav-icons" >house,user,circle,box,umbrella,music,heart,gear </div> <div id="sidebar-controls" style="border:1px solid black;background:orange"> <div>Control group 1</div> <div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> </div> <div>Control group 2</div> <div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> <div>replace with spotfire control</div> </div> </div>
Example with scrollbar and as a popup panel
<DIV id="sidebar" style="FONT-SIZE: 20px; BACKGROUND: #3498db; COLOR: white"></DIV> <span id="sidebar-logo">Options</span> <DIV id="sidebar-nav" style="padding:20px;overflow-y: auto;height: 80vh;" > Spotfire controls here </div> <div id="sidebar-nav-icons" ></div>
JavaScript
sidebar-popup.js
sidebar = document.getElementById("sidebar") h=sidebar.offsetParent.offsetHeight; hasLogo = document.querySelector("#sidebar-logo"); fontSize = parseInt(window.getComputedStyle(document.querySelector("#sidebar")).fontSize); hasTrigger = document.querySelector("#sidebar-trigger"); hasFeathers = typeof feather != "undefined"; template = ` <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" /> <span class="sidebar-trigger" id="showMenuBtn" title="click to show menu"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg> </span> <nav class="main-menu"> <span class="right" id="hideMenuBtn" title="clcik to hide menu" ><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></span> <ul><li class="sidebar-logo"></li></ul> <ul id="navItems" class="sidebar-nav"></ul> <ul id="navItems" class="sidebar-controls"> </ul> </nav> <style> #showMenuBtn { FONT-SIZE: 20px; COLOR: ${sidebar.style.background}; width: 25px; text-align: center; border-radius: 15px; cursor: pointer; position: absolute; } #hideMenuBtn { cursor: pointer; z-index: 40; position: absolute; } #navItems li a { position: relative; display: flex; vertical-align: middle; align-items: center; font-size:${fontSize}px; line-height:3; } .submenu { overflow: hidden; max-height: 0; margin-left:2em; -webkit-transition: all 0.5s ease-out; } .submenu:before { content: "▼"; position: absolute; right: 15px; top: ${fontSize*.75}px; } .icon { width: 22.5px; height: 22.5px; margin-right: 15px; margin-left: 15px; display: flex; align-items: center; align-content: flex-end; justify-content: center; } .right{ position:absolute; right:10px; } /*when using text as logo*/ .sidebar-logo { color: ${sidebar.style.color}; font-size: ${fontSize*1.5}px; width: 100% !important; top: -7px; padding: 2px; text-align: center; border-bottom: 1px solid white; } /*when using an image as logo*/ .sidebar-logo img{ background: ${sidebar.style.background}; color: ${sidebar.style.color}; height:unset !important; max-width:50% !important; min-width:${fontSize*3}px; } .main-menu { position:fixed; z-index:10; box-shadow: 3px 3px 10px 1px #888; background: ${sidebar.style.background}; border-right:1px solid #555; height:${h}px; width:${fontSize*3}px; overflow:hidden; transition:width .05s linear; } .main-menu, nav.main-menu.expanded { width:260px; overflow:visible; } .main-menu>ul { margin:7px 0; } .main-menu li { position:relative; display:block; width:260px; cursor:default; } details li{ display:contents; } .main-menu li>a { color:${sidebar.style.color}!important; text-decoration:none !important; transition:all .1s linear; width:260+${fontSize}px; } nav ul,nav li { padding:0; } .main-menu li:xhover .submenu { max-height: 200px; } .main-menu .expanded { max-height: fit-content; } details { padding: 10px; } summary { padding-left: 10px; cursor:default; } details > div { padding: 10px 20px 0 10px; display: flex; flex-direction: column; align-items: stretch; } details > div a { color: white !important; } details .sf-element-dropdown-list-item.sfpc-selected{ color:${sidebar.style.background} !important; background:${sidebar.style.color} !important; } details .sf-element-text-box{ color:${sidebar.style.background} !important; } details .sf-element-dropdown .sf-element-text-box{ color:${sidebar.style.background} !important; } details .sf-element-filter-item .sf-element-text-box, details .sf-element-item-slider, details .sf-element-text-box { color:${sidebar.style.color} !important; } details .sfc-list-box{ background:${sidebar.style.background} !important; } .DropdownListContainer { z-index:100; } </style> ` //move components (ids) to template placeholders (class names) function moveElement(component,templateComponent){ if(templateComponent!=undefined){ if (component.id == "sidebar-nav") { ul = document.getElementById("navItems"); icons = document.querySelector("#sidebar-nav-icons"); if (hasFeathers) icons = icons.innerText.split(",").map(x=>`<i class="icon" data-feather="${x}"></i>`); if (!hasFeathers) icons = icons.innerText.split(",").map(x=>`<i class="icon fa-solid fa-${x}"></i>`); navItems = [...document.querySelectorAll("#sidebar-nav > *")].forEach((x)=>{ if (x.nodeName=="A"){ if(x.innerText.endsWith("***")) x.innerText = x.innerText.replace("***",""); } if (x.nodeName=="A" && x.nextElementSibling?.nodeName!="LI"){ if(x.innerText.endsWith("***")) x.innerText = x.innerText.replace("***",""); li = document.createElement("li"); x.insertAdjacentHTML("afterbegin",icons.shift()); li.append(x); ul.append(li); } if (x.nodeName=="A" && x.nextElementSibling?.nodeName=="LI"){ li = document.createElement("li"); x.insertAdjacentHTML("afterbegin",icons.shift().replace("icon","icon parent")); li.append(x); ul.append(li); } if (x.nodeName=="LI"){ sul = document.createElement("ul"); sul.className="submenu"; [...x.querySelectorAll("a")].forEach(a=>{ if(a.innerText.endsWith("***")) a.innerText = a.innerText.replace("***",""); li = document.createElement("li"); a.insertAdjacentHTML("afterbegin",icons.shift()); li.append(a); sul.append(li); }) ul.lastChild.append(sul); } }); } if(component.id=="sidebar-controls"){ let controls = [...document.querySelectorAll("#sidebar-controls > *")] for (i=0;i<controls.length;i+=2){ isOpen=false; if(controls[i].innerText.endsWith("***")){ isOpen=true; controls[i].innerText = controls[i].innerText.replace("***",""); } sum = document.createElement("summary"); det = document.createElement("details"); div = document.createElement("div"); det.append(sum); sum.append(...controls[i].childNodes); div.append(...controls[i+1].childNodes); det.append(div); templateComponent.append(det); if(isOpen) sum.click(); } } templateComponent.append(...component.childNodes); } //if (!templateComponent) console.log(`⚠️ class ".${component.id}" does not exists on template!`); component.remove(); } sidebar.innerHTML = template //move elements var components = "nav,title,logo,options,controls,nav-icons,trigger"; components = components.split(",").map(x=>{return "#sidebar-"+x}).join(", "); [...document.querySelectorAll(components)].forEach(component=>{templateComponent="."+component.id;moveElement(component,document.querySelector(templateComponent)) }); iconSize = parseInt(window.getComputedStyle(sidebar).getPropertyValue("font-size").replace("px",""))-5+"px"; if (hasFeathers) feather.replace({width:iconSize,height:iconSize}) //show or hide menu function showMenu(isVisible){ document.querySelector(".main-menu").hidden=!isVisible document.getElementById("showMenuBtn").hidden=isVisible; console.log(isVisible) //save state (TBD) window.localStorage.setItem("sidebarVisibleState",isVisible); } document.getElementById("hideMenuBtn").onclick=()=>{showMenu(false)}; document.getElementById("showMenuBtn").onclick=()=>{showMenu(true)}; //expand on click [...document.querySelectorAll(".sidebar-nav li")].forEach(x=>{if(x.lastChild.className=="submenu"){ x.onclick = function(){x.lastChild.classList.toggle("expanded")}; }}) //load state (TBD) showMenu(JSON.parse(window.localStorage.getItem("sidebarVisibleState")));
See also
JavaScript Sidebar for Spotfire
JavaScript Masthead for Spotfire
IronPython Masthead for Spotfire
- 1
Recommended Comments
There are no comments to display.