Jump to content
  • JavaScript Slim Sidebar for Spotfire


    Create a slim sidebar style for your analysis file using JavaScript

     

    sidebar-slim.thumb.gif.aabc57b09049f6845f17f61d309d3864.gif This slim sidebar is Intended for smooth page navigation
    • Can be minimized
    • Can group pages
    • Overlays other visualizations
    • Does not support Spotfire controls

    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 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>
    	<SpotfireControl (repalce with link spotfire control) />
    	<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>
     

    Example (with groups)

    <DIV id="sidebar" style="FONT-SIZE: 20px; BACKGROUND: #243772; COLOR: white"></DIV>
    
    <span id="sidebar-logo"><img src="bffeccd1047746e5bd1a3a11c6048a9d.png" style="border: 0; width: 409px; height: 113px;"/></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>
     

    JavaScript

    sidebar-slim.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">
    ${hasTrigger?'':'<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>'}
    </span>
     
    
    <nav class="main-menu"> 
    
        <ul><li class="sidebar-logo"></li></ul>
         <ul><li><i><span class="right" id="hideMenuBtn" title="clcik to hide menu" ><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye-off"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg></span></i></li></ul> 
      
        
        <ul id="navItems" class="sidebar-nav"></ul>    
    
     
      </nav>  
      
    <style>      
     
    #showMenuBtn {
    	FONT-SIZE: 20px;
    	BACKGROUND: ${sidebar.style.background};
    	COLOR: ${sidebar.style.color};
    	width: 25px;
    	text-align: center;
    	border-radius: 15px;
    	cursor: pointer;
    	position: absolute;
    }
    
    #hideMenuBtn{
       padding:3px;
       cursor: pointer;
       z-index:40;
       position: absolute;
       top: -50px;}
    
    
    #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: ${fontSize*1.5-fontSize/2}px;
        margin-left: ${fontSize*1.5-fontSize/2}px;
        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: 14px;
        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:hover,nav.main-menu.expanded {
    	width:260px;
    	overflow:visible;
    }
    
    .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>ul {
     margin:7px 0;
    }
    
    .main-menu li {
     position:relative;
     display:block;
     width:260px;
    }
    
    .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:hover .submenu {
      max-height: 200px;
    }
    
    
    
    </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); 
    		    }  
    
    		});
    
    
    
    
     
          }
          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)};
    
    //load state (TBD)
    showMenu(JSON.parse(window.localStorage.getItem("sidebarVisibleState")));
     

     

    See also

    JavaScript Sidebar for Spotfire

    JavaScript Masthead for Spotfire

    IronPython Masthead for Spotfire

     


    User Feedback

    Recommended Comments

    There are no comments to display.


×
×
  • Create New...