左側分類欄位組合右側收合

在使用 clipchamp 時看到這一個功能,覺得很有趣。

比較簡單的解法,是使用 sidebar + collapse 就可以做到,範例程式:
https://getbootstrap.com/docs/5.3/examples/sidebars/

clipchame 的這個做法的優點是讓分類可以保持在左側sidebar 裡。

實作的方式是,sidebar 使用 tab 來實作,收合使用。 collapse, 參考看看 bootstrap 範例:
https://getbootstrap.com/docs/5.3/components/collapse/

一般 collapse 是上下收合,這個是左右收。

一般 tab 是上下的版面,這個是左右版面。


實際上用的到html程式碼:

  <div class="ifilter_chart">
      <div class="ifitler_chart_left_side_bar">
          <nav aria-label="左側導覽" class="ifilter_chart_left_nav normal" tabindex="0">
              <div class="ifilter_chart_left_nav_grid">
                  <div class="ifilter_chart_left_nav_item">
                      <div role="tablist">
                          <button aria-label="Filter" aria-selected="true" class="ifilter_chart_left_nav_btn active" data-bs-toggle="tab" href="#ifilter_tab_bar_filter" data-sidebar-tab="true" role="tab" tabindex="0">
                              <i class="fs-3 bi bi-filter"></i>
                              <div class="ifilter_chart_left_nav_item_text">
                                  Filter
                              </div>
                          </button>
                          
                        <button aria-label="Config" aria-selected="false" class="ifilter_chart_left_nav_btn" data-bs-toggle="tab" href="#ifilter_tab_bar_config" data-sidebar-tab="true" role="tab" tabindex="-1">
                            <i class="fs-3 bi bi-grid-fill"></i>
                            <div class="ifilter_chart_left_nav_item_text">
                                Config
                            </div>
                        </button>                          
                      </div>
                  </div>
              </div>
          </nav>
          <div style="position: relative;">
              <div aria-label="左側內容" class="ifilter_chart_left_sidebar" style="height: 100%">
                  <div class="ifilter_chart_left_sidebar_grid collapse show" id="collapse_bar_sidebar">
                      <div class="tab-content ifilter_chart_left_sidebar_grid_container" style="position: relative; box-sizing: border-box; will-change: width; width: 280px; height: 100%; max-width: 50vw; min-width: 280px;">
                          <div class="tab-pane fade active show" id="ifilter_tab_bar_filter" role="tabpanel">
<!-- your filter block here -->
                          </div>
                          <div class="tab-pane fade" id="ifilter_tab_bar_config">
<!-- your config block here -->
                          </div>
                      </div>
                  </div>
              	  
              	  <button aria-label="收合按鈕"
              	  	data-bs-toggle="collapse" data-bs-target="#collapse_bar_sidebar" aria-expanded="true" aria-controls="collapse_sidebar" 
              	  	class="btn btn-primary ifilter_chart_collapse_button ifilter_chart_collapse_icon ifilter_sidebar_button collapsed">
				    <svg class="ifilter_chart_collapse_icon_svg" height="12" viewbox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg">
				        <path d="M2.22 4.47c.3-.3.77-.3 1.06 0L6 7.19l2.72-2.72a.75.75 0 0 1 1.06 1.06L6.53 8.78c-.3.3-.77.3-1.06 0L2.22 5.53a.75.75 0 0 1 0-1.06Z" fill="currentColor">
				        </path>
				    </svg>
				</button>
              </div>
          </div>
      </div>
      <div class="ifilter_chart_canvas">
<!-- your main canvas here -->
      </div>
  </div>

css:

div.ifilter_chart {
    display: flex;
    height: 100%;	
}

.ifitler_chart_left_side_bar{
    display: flex;
    /*
    // why remark this become height: 100% 
    height: 100%; */
    position: relative;
    z-index: 5;	
}

.ifilter_chart_left_nav {
    background-color: rgb(255, 255, 255);
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 64px;
    border-inline-end: 1px solid rgb(230, 230, 230);
}

.ifilter_chart_left_nav_grid {
    flex-grow: 1;
    align-self: stretch;
    position: relative;
    overflow: hidden;
}

.ifilter_chart_left_nav_item {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 0px;
    /* overflow-y: scroll; */
}

.ifilter_chart_left_nav_btn.active {
    opacity: 1;
    color: var(--primary) !important;
    background: var(--rgba-primary-1);
    font-weight: 600;
    box-shadow: none;    
}
.ifilter_chart_left_nav_btn {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background: none;
    border: none;
    color: #737B8B;
    line-height: 1.1;
    padding: 4px;
    width: 64px;
    height: 64px;
    font-weight: 400;
    cursor: pointer;
    /* transition: color 100ms ease-in-out 0s, background 100ms ease-in-out 0s; */
}

.ifilter_chart_left_nav_item_text {
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
    
.ifilter_chart_left_sidebar {
	position: relative;
    height: 100%;
}

.ifilter_chart_left_sidebar_grid {
    background-color: rgb(255, 255, 255);
    display: flex;
    flex-direction: column;
}

.ifilter_chart_left_sidebar_media {
    background-color: rgb(255, 255, 255);
    overflow: hidden overlay;
    flex-grow: 1;
}

.ifilter_chart_left_sidebar_section {
    position: relative;
    width: 100%;
    min-height: 100%;
    display: flex;
    flex-direction: column;
}

.ifilter_chart_left_sidebar_grid_container {
    padding: 16px;
    display: flex;
    flex-direction: column;
}

.ifilter_chart_collapse_icon {
    position: absolute;
    top: calc(50% - 38px);
    height: 76px;
    width: 16px;
    color: rgb(39, 40, 54);
    transition: color 150ms ease-out 0s;
}
.ifilter_sidebar_button {
    position: absolute;
    top: calc(50% - 38px);
    transition: color 150ms ease-out 0s;	
}

.ifilter_chart_collapse_icon {
    left: 100%;
}
.ifilter_chart_collapse_icon_svg:not(.collapsed) {
    transform: rotate(90deg);
}
.ifilter_chart_collapse_icon_svg.collapsed {
    transform: rotate(270deg);
}

.ifilter_chart_collapse_icon_svg {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -6px;
    margin-top: -6px;
}

.ifilter_chart_collapse_button {
    text-align: inherit;
    padding: 0px;
    border: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    display: flex;
    -webkit-box-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    align-items: center;
}

.ifilter_chart_canvas {
	width: 100%;
	text-align: -webkit-center;
	padding-top: 3rem;
    margin-left: 20px;
}

javascript:

var collapseElementList = [].slice.call(document.querySelectorAll('.ifilter_chart_left_nav_btn'));
collapseElementList.map(function (collapseEl) {
	collapseEl.addEventListener("click", function(event){
        let targetElement = event.target || event.srcElement;
        //console.log(targetElement);
        if(targetElement.tagName=="I" || targetElement.tagName=="DIV") {
        	targetElement = targetElement.parentNode;
            //console.log(targetElement);
        }
    	
        let btn_href = targetElement.getAttribute("href");
    	let btn_selector = "";
    	let collapse_id = "";
    	if(btn_href=="#ifilter_tab_bar_config" || btn_href=="#ifilter_tab_bar_filter") {
    		collapse_id = "collapse_bar_sidebar";
    		btn_selector = 'button[data-bs-target="#'+ collapse_id +'"]';
    	}
    	const sidebar_btn = document.querySelector(btn_selector);
    	if(sidebar_btn) {
    		//console.log(sidebar_btn.getAttribute("class"));
    		if(sidebar_btn.getAttribute("class").indexOf("collapsed") > -1) {
    			const bsCollapse = new bootstrap.Collapse(document.querySelector('#'+collapse_id));
    			bsCollapse.toggle();
    		}
    	}
    });
});


var collapseElementList = [].slice.call(document.querySelectorAll('.ifilter_chart_left_sidebar_grid'));
collapseElementList.map(function (collapseEl) {
	// hide.bs.collapse
	const element_selector = "button[data-bs-target=\"#"+ collapseEl.getAttribute("id") +"\"] svg.ifilter_chart_collapse_icon_svg";
	collapseEl.addEventListener("hidden.bs.collapse", function(event){
		$(element_selector).addClass("collapsed");
	});

	// show.bs.collapse
	collapseEl.addEventListener("shown.bs.collapse", function(event){
		$(element_selector).removeClass("collapsed");
	});
});

說明:你的使用情況可能比我簡單很多,我因為有多個圖表要共用 css, 所以程式碼會複雜一點點。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *