在使用 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, 所以程式碼會複雜一點點。