Jump to content
  • JavaScript Flat Sidebar for Spotfire


    A simple flat sidebar navigation JavaScript to use in TextAreas to enhance page navigation and features

     

    sidebar-flat.thumb.gif.92a7f239a84263644f4479192ff6e9d9.gif The Flat Sidebar saves real state. 
    • Intended for simple page navigation
    • Optional icons for links navigation
    • Groups Spotfire Controls
    • Does not overlay with other visualizations

    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>
    	<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>
    
    
    
    <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>
     

    html 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>
     

    JavaScript

    sidebar-flat.js

    sidebar = document.getElementById("sidebar")
    h=sidebar.parentElement.offsetHeight;
    bgColor = window.getComputedStyle(document.querySelector(".sfc-text-area")).backgroundColor;
    hasLogo = document.querySelector("#sidebar-logo");
    hasFeathers = typeof feather!="undefined";
      
    template = `
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" />
    
    <div class="container">
      <div class="sidebar-logo"></div>
      <nav class="side-nav">
        <ul class="nav-menu sidebar-nav"></ul>
      </nav>
       <div class="sidebar-controls"></div>
    </div>
    
     
    <style>
    
    .sidebar-logo{
    	text-align:center;
    	padding-top:${hasLogo?0:5}x;
    }
    .sidebar-logo img{
    	text-align:center;
    	margin:0px;padding:0;
    }
    
    /*vertical line under logo*/
    .sidebar-logo::after{
            display:${hasLogo?"block":"none"};
    	content:"";
            padding-top:5px;
    	border-bottom:2px solid ;
    }
    
    /*logo image matches fontSize*/
    .sidebar-logo *{
    	vertical-align:middle;
    	height:${sidebar.style.fontSize} !important;
    	width:unset !important;
    	text-align:center;
    	padding-top:10px;
    	display:initial;
            width:none;
    }
    
    /*takes entire screen*/
    .container {
        height: ${h}px;
    
    }
    .side-nav .nav-menu {
      list-style: none;
      background-color: ${sidebar.style.backgroundColor};
      display:contents;
    }
    .side-nav .nav-item {
      position: relative;
      padding: 10px 20px;
    }
    .nav-item.active {
      background-color: ${bgColor }; /*◄*/
      box-shadow: 0px -3px rgba(0, 0, 0, 0.2), 0px 3px rgba(0, 0, 0, 0.2);
    }
    .nav-item.active a {
      color: ${sidebar.style.backgroundColor||"#3498db"} !important;
    }
    .nav-item a {
      text-decoration: none !important;
      color: ${sidebar.style.color||"white"} !important;
    }
    .menu-text {
      padding: 0 20px;
    }
    .side-nav .nav-item.active::before {
      content: "";
      position: absolute;
      background-color: transparent;
      bottom: 100%;
      right: 0;
      height: 150%; 
      width: 20px;
      border-bottom-right-radius: 25px;
      box-shadow: 0 20px 0 0 ${bgColor};/*◄*/
    }
    .side-nav .nav-item.active::after {
      content: "";
      position: absolute;
      background-color: transparent;
      top: 100%;
      right: 0;
      height: 150%;
      width: 20px;
      border-top-right-radius: 25px;
      box-shadow: 0 -20px 0 0 ${bgColor};/*◄*/
    }
    
    .icon {
        margin-right: 15px;
    }
    
    
    details {
        padding: 10px;
    }
    
    details > div {
        padding: 10px 20px 0 10px;
        display: flex;
        flex-direction: column;
        align-items: stretch;
    }
    
    details > div  a{
        color:${sidebar.style.color} !important;
    }  
    
    details .sf-element{
        color:${sidebar.style.background} !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;
    }
    
    details summary {
      cursor: pointer;  
    }
    
    #sidebar summary {
       padding-left: 10px;
       cursor:default;
    }
    
     
    </style>` 
    
    sidebar.innerHTML = template
    
    //move components (ids) to template placeholders (class names)
    function moveElement(component,templateComponent){
       if(templateComponent!=undefined){
    
          if (component.id == "sidebar-nav") {
    		  
    		icons = document.querySelector("#sidebar-nav-icons");
    		if (hasFeathers && icons) icons = icons.innerText.split(",").map(x=>`<i class="icon" data-feather="${x}"></i>`);
    		if (!hasFeathers && icons) icons = icons.innerText.split(",").map(x=>`<i class="icon fa-solid fa-${x}"></i>`);
    		
             let i=0;
    	 [...document.querySelectorAll("#sidebar-nav a")].forEach(a=>{
                li = document.createElement("li");
                li.className="nav-item";
                if(a.innerText.endsWith("***")) {
                   li.className="nav-item active";
                   a.innerText = a.innerText.replace("***","");
                }
                if (icons && icons[i]) a.insertAdjacentHTML("afterbegin",icons[i++]);
                li.append(a);
                document.querySelector(".sidebar-nav").append(li);
             })
          }
    
    
    	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();
    } 
    
    //behave like accordion
    setTimeout(function(){
      details = [...document.querySelectorAll("#sidebar details")]
      details.forEach((detail) => {
        detail.addEventListener('click', (e) => {
          const active = details.find(d => d.open)
          if (!e.currentTarget.open && active) {
            active.open = false
          }
        })
      })
    
    },500)
    
    //move elements
    var components = "nav,title,logo,options,controls,nav-icons"; 
    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",""))+0+"px";
    if (hasFeathers) feather.replace({width:iconSize,height:iconSize})
     

     

    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...