diff --git a/assets/css/part/tabbed-ui.css b/assets/css/part/tabbed-ui.css index 7bbc3175..b68854ee 100644 --- a/assets/css/part/tabbed-ui.css +++ b/assets/css/part/tabbed-ui.css @@ -1,107 +1,79 @@ -.JS .tabbed-ui > div { - background: #FAFFF8; - padding: 0.5em 1.2em 0.8em; - border: 1px solid #D2D2D2; -} -.JS .tabbed-ui > div:not(.tabbed-ui-current) { - display: none; -} +/* wrapper */ -.tabbed-ui-navigator { - padding-left: 0; - list-style-type: none; - margin: 0 0 -1px; - - vertical-align: bottom; +.tabbed-ui-wrapper { + display: grid; + grid-template-columns: 250px 1fr; + grid-gap: 40px; } -@supports (-webkit-nbsp-mode: initial) + +@media (max-width: 800px) { - .tabbed-ui-navigator { - /* needed for WebKit, not Blink */ - margin-bottom: 0; + .tabbed-ui-wrapper { + display: block; } } -.tabbed-ui-navigator li { - display: inline; -} -.tabbed-ui-navigator button { - margin-right: 0.4em; - padding: 0.2em 0.9em; - background: #FAFFF8; - border: 1px solid #D2D2D2; - opacity: 0.63; - white-space: nowrap; - display: inline-block; - outline-style: none; - box-shadow: none; - color: inherit; - transition-property: opacity; - width: auto; - font-weight: normal; - margin-top: 0; -} -.tabbed-ui-navigator button:hover { - background: #fff; - color: inherit; -} -.tabbed-ui-navigator button:focus:not(:hover):not(:active) { - opacity: 1; - outline-style: dashed; -} -.tabbed-ui-navigator button.tabbed-ui-current { - opacity: 1; - border-bottom-color: #FAFFF8; - padding-top: 0.6em; - background: #FAFFF8; -} + +/* navigation */ @media (max-width: 800px) { - .tabbed-ui-navigator { - margin-bottom: 0.4em; - } - - .tabbed-ui-navigator button { - margin-bottom: 0.5em; - } - .tabbed-ui-navigator button, .tabbed-ui-navigator button.tabbed-ui-current { - padding: 0.2em 0.9em; - border: 1px solid #D2D2D2; - } - .tabbed-ui-navigator li:last-child button { - margin-right: 0; - } - .tabbed-ui-navigator button.tabbed-ui-current { - font-weight: bold; - border-color: #aaa; + .tabbed-ui-navigation { + display: none; } } +.tabbed-ui-navigation ol { + list-style: none; + padding-left: 0; + margin: 0; + + position: sticky; + top: 20px; +} +.tabbed-ui-navigation a { + display: block; -/* information paragraph in tabbed UI */ + border: 1px solid #eee; + background: #fff; + padding: 10px 20px; -.JS .tabbed-ui .information { - box-shadow: none; - padding-top: 1.5em; - padding-bottom: 1.5em; + position: relative; + overflow: hidden; } +.tabbed-ui-navigation a:hover, .tabbed-ui-navigation a:focus { + background: #f1f1f1; +} +.tabbed-ui-navigation a::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; -@media (max-width: 800px) -{ - .JS .tabbed-ui .information { - padding-top: 0.9em; - padding-bottom: 0.9em; - } + background: #ef7f20; + width: 7px; + transform: translateX(-100%); + transition: transform linear 0.1s; +} +.tabbed-ui-navigation a.active::before { + transform: translateX(0); +} +.tabbed-ui-navigation li + li a { + border-top: none; +} +.tabbed-ui-navigation li:first-child a { + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} +.tabbed-ui-navigation li:last-child a { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; } -/* button in tabbed UI */ +/* content */ -.JS .tabbed-ui > div > form > button { - margin-top: 1.5em; - margin-bottom: 0.7em; -} -.JS .tabbed-ui + button { - margin-top: 1.3em; +.tabbed-ui div:first-child h2 { + margin-top: 0; } diff --git a/assets/js/src/TabbedUI.js b/assets/js/src/TabbedUI.js index 8638f7e0..bfe356b3 100644 --- a/assets/js/src/TabbedUI.js +++ b/assets/js/src/TabbedUI.js @@ -1,101 +1,61 @@ import '../../css/part/tabbed-ui.css'; +import tocbot from 'tocbot'; export class TabbedUI { constructor(container) { + /** @type {!Element} */ this.container = container; - this.panels = [...container.children]; - this.navigator = null; - this.buttons = []; - this.setupNavigator(); - this.setupPanels(); - } + this.wrapper = null; + this.navigation = null; - get LAST_PANEL_SESSION_KEY() - { - return 'tabbed-ui__' + location.pathname; + this.setupMarkup(); + this.setupNavigation(); } - setupNavigator() + setupMarkup() { - this.navigator = document.createElement('ul'); - this.navigator.classList.add('tabbed-ui-navigator'); - this.navigator.setAttribute('role', 'tablist'); - - this.panels.forEach((panel, i) => { - let title = panel.querySelector('h2').innerHTML; - let item = document.createElement('li'); - let button = document.createElement('button'); - - button.innerHTML = title; - button.dataset.panelNumber = i; - button.type = 'button'; - button.addEventListener('click', this.onNavigatorButtonClick.bind(this)); + this.wrapper = document.createElement('div'); + this.wrapper.classList.add('tabbed-ui-wrapper'); - this.buttons[i] = button; + this.navigation = document.createElement('nav'); + this.navigation.classList.add('tabbed-ui-navigation'); - item.appendChild(button); - this.navigator.appendChild(item); - }); - - this.container.insertBefore(this.navigator, this.panels[0]); + this.container.parentNode.replaceChild(this.wrapper, this.container); + this.wrapper.appendChild(this.navigation); + this.wrapper.appendChild(this.container); } - setupPanels() + setupNavigation() { - let defaultPanelNumber = 0; - - let currentHash = location.hash.replace('#', ''); - let savedPanelNumber = sessionStorage.getItem(this.LAST_PANEL_SESSION_KEY); - - if (null != savedPanelNumber) { - defaultPanelNumber = savedPanelNumber; - } - - this.panels.forEach((panel, i) => { - panel.setAttribute('role', 'tab'); - - if (currentHash && panel.id == currentHash) { - defaultPanelNumber = i; - - // If default panel was determined by URL hash, scroll to - // the top of the page to prevent default browser behavior. - let scrollToTop = () => { - window.scroll(0, 0); - window.removeEventListener('scroll', scrollToTop); - }; - window.addEventListener('scroll', scrollToTop); - } + this.container.querySelectorAll('h2').forEach(node => { + node.id = this.slugify(node.textContent); }); - this.changePanel(defaultPanelNumber); - } + tocbot.init({ + tocSelector: '.tabbed-ui-navigation', + contentSelector: '.tabbed-ui', + headingSelector: 'h2', - changePanel(panelNumber) - { - this.panels.forEach((panel, i) => { - panel.classList.remove('tabbed-ui-current'); - this.buttons[i].classList.remove('tabbed-ui-current'); + activeLinkClass: 'active', - if (i == panelNumber) { - panel.classList.add('tabbed-ui-current'); - this.buttons[i].classList.add('tabbed-ui-current'); - } + basePath: window.location.pathname, }); } - onNavigatorButtonClick(event) + slugify(string) { - event.preventDefault(); - - let button = event.target; - let panelNumber = button.dataset.panelNumber; - - button.blur(); - - this.changePanel(panelNumber); - sessionStorage.setItem(this.LAST_PANEL_SESSION_KEY, panelNumber); + // https://gist.github.com/codeguy/6684588 + + return string + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase() + .trim() + .replace(/[^a-z0-9 ]/g, '') + .replace(/\s+/g, '-') + ; } } diff --git a/package-lock.json b/package-lock.json index fb1084e4..96f13d53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7921,6 +7921,11 @@ "is-number": "^7.0.0" } }, + "tocbot": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/tocbot/-/tocbot-4.12.2.tgz", + "integrity": "sha512-rhw3BQkVrO+DdsFyK8UbVGtjWPg5BVrftscVFoUHOAxea4CZmTsLBmxfezeTdgk1wfHXiZWbtGst/NkFdttLFQ==" + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", diff --git a/package.json b/package.json index 6b7c253c..3f055c00 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,8 @@ "dev": "encore dev", "watch": "encore dev --watch", "build": "encore production --progress" + }, + "dependencies": { + "tocbot": "^4.12.2" } }