-
Notifications
You must be signed in to change notification settings - Fork 0
USE-188: Responsive behavior for tab bar #289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
25cffb6
37fd5f6
5c5c6ba
0246b1d
8c20cf5
7141740
b5c87f5
ba19d82
0e0874b
1f4be6e
b28fefb
18cb587
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| /* ============================ */ | ||
| /* Source Tab Bar in USE Search */ | ||
| /* ============================ */ | ||
|
|
||
| #tabs { | ||
| margin-top: 0; | ||
| position: relative; | ||
|
|
||
| // Graceful degradation when JS is not enabled | ||
| &:not(.has-js) { | ||
| overflow-x: auto; | ||
| -webkit-overflow-scrolling: touch; | ||
| } | ||
|
|
||
| // Display styles for the main tab bar | ||
| ul.primary { | ||
| list-style-type: none; | ||
| padding: 0; | ||
| margin: 0; | ||
| display: flex; | ||
| gap: 4px; | ||
| } | ||
|
|
||
| li { | ||
|
|
||
| &.--hidden { | ||
| display: none; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| a, button { | ||
| padding: 12px 20px 16px; | ||
| background-color: transparent; | ||
| display: inline-block; | ||
| border: 2px solid transparent; | ||
| border-bottom: 0; | ||
| white-space: nowrap; | ||
|
|
||
| @include searchUnderlinedLinks; | ||
|
|
||
| &:hover { | ||
| border-color: $color-gray-700; | ||
| background-color: $color-gray-900; | ||
| color: $color-text-oncolor; | ||
| } | ||
|
|
||
| &.active { | ||
| background-color: $color-white; | ||
| color: $color-text-primary; | ||
| text-decoration: none; | ||
|
|
||
| &:hover { | ||
| color: $color-text-primary; | ||
| border-color: transparent; | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| // Swap the icon to chevron-up when menu is open | ||
| button[aria-expanded="true"] { | ||
|
|
||
| i::before { | ||
| content: '\f077'; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| // Display styles for the dropdown menu under the "More" button | ||
| ul.-secondary { | ||
| width: 100%; | ||
| display: none; | ||
| position: absolute; | ||
| top: 100%; | ||
| right: 0; | ||
| list-style-type: none; | ||
| padding: 0; | ||
| margin: 0; | ||
| z-index: 999; | ||
|
|
||
| li { | ||
| width: 100%; | ||
|
|
||
| a { | ||
| background-color: $color-gray-950; | ||
| width: 100%; | ||
|
|
||
| &:hover { | ||
| border-color: $color-gray-950; | ||
| background-color: $color-gray-900; | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
| &.--show-secondary .-secondary { | ||
| display: block; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // =========================================================================== | ||
| // RESPONSIVE TAB BAR LOGIC WITH GRACEFUL DEGRADATION | ||
| // Source: https://css-tricks.com/container-adapting-tabs-with-more-button/ | ||
| // =========================================================================== | ||
|
|
||
| // Store references to relevant selectors | ||
| const container = document.querySelector('#tabs') | ||
| const primary = container.querySelector('.primary') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get this error in the console when this is loaded from the main USE UI page.
We likely either need to change this logic here or to not error which prevents the script from running further or only load this script on pages that have that selector. This script erroring prevents it from working when a search is run. One way to address this might be to wrap this logic in a function and then have a return block at the start of the function if the required DOM elements are not present. |
||
| const primaryItems = container.querySelectorAll('.primary > li:not(.-more)') | ||
|
|
||
| // Add a class to turn off graceful degradation style | ||
| container.classList.add('has-js') | ||
|
|
||
| // insert "more" button and duplicate the original tab bar items | ||
| primary.insertAdjacentHTML('beforeend', ` | ||
| <li class="-more"> | ||
| <button type="button" aria-haspopup="true" aria-expanded="false" aria-controls="more-options"> | ||
| More <i class="fa-light fa-chevron-down"></i> | ||
| </button> | ||
| <ul class="-secondary" id="more-options" aria-label="More options"> | ||
| ${primary.innerHTML} | ||
| </ul> | ||
| </li> | ||
| `) | ||
| const secondary = container.querySelector('.-secondary') | ||
| const secondaryItems = secondary.querySelectorAll('li') | ||
| const allItems = container.querySelectorAll('li') | ||
| const moreLi = primary.querySelector('.-more') | ||
| const moreBtn = moreLi.querySelector('button') | ||
|
|
||
| // When the more button is clicked, toggle classes to indicate the secondary menu is open | ||
| moreBtn.addEventListener('click', (e) => { | ||
| e.preventDefault() | ||
| container.classList.toggle('--show-secondary') | ||
| moreBtn.setAttribute('aria-expanded', container.classList.contains('--show-secondary')) | ||
| }) | ||
|
|
||
| // adapt tabs | ||
| const doAdapt = () => { | ||
|
|
||
| // reveal all items for the calculation | ||
| allItems.forEach((item) => { | ||
| item.classList.remove('--hidden') | ||
| }) | ||
|
|
||
| // hide items that won't fit in the Primary tab bar | ||
| let stopWidth = moreBtn.offsetWidth | ||
| let hiddenItems = [] | ||
| const primaryWidth = primary.offsetWidth | ||
| primaryItems.forEach((item, i) => { | ||
| if(primaryWidth >= stopWidth + item.offsetWidth) { | ||
| stopWidth += item.offsetWidth | ||
| } else { | ||
| item.classList.add('--hidden') | ||
| hiddenItems.push(i) | ||
| } | ||
| }) | ||
|
|
||
| // toggle the visibility of More button and items in Secondary menu | ||
| if(!hiddenItems.length) { | ||
| moreLi.classList.add('--hidden') | ||
| container.classList.remove('--show-secondary') | ||
| moreBtn.setAttribute('aria-expanded', false) | ||
| } | ||
| else { | ||
| secondaryItems.forEach((item, i) => { | ||
| if(!hiddenItems.includes(i)) { | ||
| item.classList.add('--hidden') | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // Adapt the tabs to fit the viewport | ||
| doAdapt() // immediately on load | ||
| window.addEventListener('resize', doAdapt) // on window resize | ||
|
|
||
| // hide Secondary menu on the outside click | ||
| document.addEventListener('click', (e) => { | ||
| let el = e.target | ||
| while(el) { | ||
| if(el === moreBtn) { | ||
| return; | ||
| } | ||
| el = el.parentNode | ||
| } | ||
| container.classList.remove('--show-secondary') | ||
| moreBtn.setAttribute('aria-expanded', false) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,25 @@ | ||
| <!-- Tab Navigation --> | ||
| <nav id="tabs" class="tab-navigation" aria-label="Result type navigation"> | ||
| <ul> | ||
| <ul class="primary"> | ||
| <li><%= link_to_tab("All") %></li> | ||
|
|
||
| <% if Feature.enabled?(:tab_primo_all) %> | ||
| <li><%= link_to_tab("Primo", "Articles and Catalog") %></li> | ||
| <% end %> | ||
|
|
||
| <li><%= link_to_tab("cdi", "Articles") %></li> | ||
| <li><%= link_to_tab("alma", "Catalog") %></li> | ||
| <li><%= link_to_tab("alma", "Books and media") %></li> | ||
|
|
||
| <% if Feature.enabled?(:tab_timdex_all) %> | ||
| <li><%= link_to_tab("TIMDEX") %></li> | ||
| <% end %> | ||
| <% if Feature.enabled?(:tab_timdex_alma) %> | ||
| <li><%= link_to_tab("timdex_alma", "Alma (TIMDEX)") %></li> | ||
| <% end %> | ||
| <li><%= link_to_tab("aspace", "MIT archives") %></li> | ||
| <li><%= link_to_tab("Website") %></li> | ||
| <li><%= link_to_tab("aspace", "Archival materials") %></li> | ||
| </ul> | ||
| </nav> | ||
|
|
||
| <%= javascript_include_tag "source_tabs" %> | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if the is an edge case you prefer to come back to, but if I start with a wide viewport from the USE UI home and then run a search and then narrow my viewport it does not collapse.
If I then refresh, I get the collapsed mode and it works when I expand and contract the viewport as expected.
This issue is being caused by the JS throwing an error and stopping execution.