Skip to content

Commit 8c20cf5

Browse files
committed
Introduced more button and menu that appears when tabs overflow
1 parent 0246b1d commit 8c20cf5

File tree

2 files changed

+126
-1
lines changed

2 files changed

+126
-1
lines changed

app/assets/stylesheets/partials/_source_tabs.scss

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
#tabs {
66
margin-top: 0;
7+
position: relative;
78

89
// Graceful degradation when JS is not enabled
910
&:not(.has-js) {
1011
overflow-x: auto;
1112
-webkit-overflow-scrolling: touch;
1213
}
1314

15+
// Display styles for the main tab bar
1416
ul.primary {
1517
list-style-type: none;
1618
padding: 0;
@@ -19,7 +21,15 @@
1921
gap: 4px;
2022
}
2123

22-
a {
24+
li {
25+
26+
&.--hidden {
27+
display: none;
28+
}
29+
30+
}
31+
32+
a, button {
2333
padding: 12px 20px 16px;
2434
background-color: transparent;
2535
display: inline-block;
@@ -46,7 +56,43 @@
4656
}
4757
}
4858

59+
}
60+
61+
// Swap the icon to chevron-up when menu is open
62+
button[aria-expanded="true"] {
63+
64+
i::before {
65+
content: '\f077';
66+
}
67+
68+
}
69+
70+
// Display styles for the dropdown menu under the "More" button
71+
ul.-secondary {
72+
width: 100%;
73+
display: none;
74+
position: absolute;
75+
top: 100%;
76+
right: 0;
77+
list-style-type: none;
78+
padding: 0;
79+
margin: 0;
80+
z-index: 999;
81+
82+
li {
83+
width: 100%;
84+
85+
a {
86+
background-color: $color-gray-950;
87+
width: 100%;
88+
}
89+
90+
}
91+
92+
}
4993

94+
&.--show-secondary .-secondary {
95+
display: block;
5096
}
5197

5298
}

app/javascript/source_tabs.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
const container = document.querySelector('#tabs')
2+
const primary = container.querySelector('.primary')
3+
const primaryItems = container.querySelectorAll('.primary > li:not(.-more)')
4+
container.classList.add('has-js')
5+
6+
// insert "more" button and duplicate the list
7+
8+
primary.insertAdjacentHTML('beforeend', `
9+
<li class="-more">
10+
<button type="button" aria-haspopup="true" aria-expanded="false">
11+
More <i class="fa-light fa-chevron-down"></i>
12+
</button>
13+
<ul class="-secondary">
14+
${primary.innerHTML}
15+
</ul>
16+
</li>
17+
`)
18+
const secondary = container.querySelector('.-secondary')
19+
const secondaryItems = secondary.querySelectorAll('li')
20+
const allItems = container.querySelectorAll('li')
21+
const moreLi = primary.querySelector('.-more')
22+
const moreBtn = moreLi.querySelector('button')
23+
moreBtn.addEventListener('click', (e) => {
24+
e.preventDefault()
25+
container.classList.toggle('--show-secondary')
26+
moreBtn.setAttribute('aria-expanded', container.classList.contains('--show-secondary'))
27+
})
28+
29+
// adapt tabs
30+
31+
const doAdapt = () => {
32+
// reveal all items for the calculation
33+
allItems.forEach((item) => {
34+
item.classList.remove('--hidden')
35+
})
36+
37+
// hide items that won't fit in the Primary
38+
let stopWidth = moreBtn.offsetWidth
39+
let hiddenItems = []
40+
const primaryWidth = primary.offsetWidth
41+
primaryItems.forEach((item, i) => {
42+
if(primaryWidth >= stopWidth + item.offsetWidth) {
43+
stopWidth += item.offsetWidth
44+
} else {
45+
item.classList.add('--hidden')
46+
hiddenItems.push(i)
47+
}
48+
})
49+
50+
// toggle the visibility of More button and items in Secondary
51+
if(!hiddenItems.length) {
52+
moreLi.classList.add('--hidden')
53+
container.classList.remove('--show-secondary')
54+
moreBtn.setAttribute('aria-expanded', false)
55+
}
56+
else {
57+
secondaryItems.forEach((item, i) => {
58+
if(!hiddenItems.includes(i)) {
59+
item.classList.add('--hidden')
60+
}
61+
})
62+
}
63+
}
64+
65+
doAdapt() // adapt immediately on load
66+
window.addEventListener('resize', doAdapt) // adapt on window resize
67+
68+
// hide Secondary on the outside click
69+
document.addEventListener('click', (e) => {
70+
let el = e.target
71+
while(el) {
72+
if(el === moreBtn) {
73+
return;
74+
}
75+
el = el.parentNode
76+
}
77+
container.classList.remove('--show-secondary')
78+
moreBtn.setAttribute('aria-expanded', false)
79+
})

0 commit comments

Comments
 (0)