diff --git a/docs/userGuide/syntax/navBars.mbdf b/docs/userGuide/syntax/navBars.mbdf index 5707b0c9fb..7ff40fa4f6 100644 --- a/docs/userGuide/syntax/navBars.mbdf +++ b/docs/userGuide/syntax/navBars.mbdf @@ -158,3 +158,26 @@ Name | Description + +****Page and site navigation menus**** +Both [site navigation]({{ baseUrl }}/userGuide/usingComponents.html#site-navigation-menus) and [page navigation]({{ baseUrl }}/userGuide/usingComponents.html#page-navigation-menus) menus will be hidden on smaller screens. +To make these accessible on smaller screens, you can use the `` and `` components in the `lower-navbar` slot. By default, if the `lower-navbar` slot is not specified, both the site and +page navigation buttons will automatically be added if they exist. + +```html{.no-line-numbers} + + + MarkBind +
  • Highlighted Link
  • + + +
    +``` + +Component | Description +--- | --- +`page-nav-button` | Pulls any element with an identifier, `id=page-nav` into the menu. If no such element exists, it pulls any [page navigation menu]({{ baseUrl }}/userGuide/usingComponents.html#page-navigation-menus) used in the layout. +`site-nav-button` | Pulls any element with an identifier, `id=site-nav` into the menu. If no such element exists, it pulls the first [site navigation menu]({{ baseUrl }}/userGuide/usingComponents.html#site-navigation-menus) used in the layout. \ No newline at end of file diff --git a/docs/userGuide/syntax/pageNavigationMenus.mbdf b/docs/userGuide/syntax/pageNavigationMenus.mbdf index a650164193..935460605f 100644 --- a/docs/userGuide/syntax/pageNavigationMenus.mbdf +++ b/docs/userGuide/syntax/pageNavigationMenus.mbdf @@ -17,6 +17,8 @@ 3. **Position the page navigation menu** within your layout using the `{% raw %}{{ pageNav }}{% endraw %}` variable. +4. **(Optional) To make pageNav accessible on smaller screens, you can use the `` component in the [navbar]({{baseUrl}}/userGuide/usingComponents.html#navbars).** +
    {{ icon_example }} diff --git a/docs/userGuide/syntax/siteNavigationMenus.mbdf b/docs/userGuide/syntax/siteNavigationMenus.mbdf index c5c501cf3e..9bb93ddb3c 100644 --- a/docs/userGuide/syntax/siteNavigationMenus.mbdf +++ b/docs/userGuide/syntax/siteNavigationMenus.mbdf @@ -7,6 +7,7 @@ Steps to add a siteNav: 1. Format your siteNav as an unordered Markdown list 2. Include it under a `` element. +3. (Optional) To make siteNav accessible on smaller screens, you can use the `` component in the [navbar]({{baseUrl}}/userGuide/usingComponents.html#navbars).
    diff --git a/packages/core-web/src/index.js b/packages/core-web/src/index.js index 6ca1b68a80..fd142a3fd4 100644 --- a/packages/core-web/src/index.js +++ b/packages/core-web/src/index.js @@ -50,6 +50,40 @@ function detectAndApplyFixedHeaderStyles() { margin-top: calc(-${headerHeight}px - ${bufferHeight}rem); height: calc(${headerHeight}px + ${bufferHeight}rem); }`); + insertCss(`.nav-menu-open { max-height: calc(100% - ${headerHeight}px); }`); + + const addResizeHeaderListener = () => { + const resizeObserver = new ResizeObserver(() => { + const newHeaderHeight = headerSelector.height(); + const sheets = document.styleSheets; + for (let i = 0; i < sheets.length; i += 1) { + const rules = sheets[i].cssRules; + // eslint-disable-next-line lodash/prefer-get + if (rules && rules[0] && rules[0].selectorText) { + switch (rules[0].selectorText) { + case '.fixed-header-padding': + sheets[i].deleteRule(0); + sheets[i].insertRule(`.fixed-header-padding { padding-top: ${newHeaderHeight}px !important }`); + break; + case 'span.anchor': + rules[0].style.top = `calc(-${newHeaderHeight}px - ${bufferHeight}rem)`; + break; + case 'span.card-container::before': + rules[0].style.marginTop = `calc(-${newHeaderHeight}px - ${bufferHeight}rem)`; + rules[0].style.height = `calc(${newHeaderHeight}px + ${bufferHeight}rem)`; + break; + case '.nav-menu-open': + rules[0].style.maxHeight = `calc(100% - ${newHeaderHeight}px + 50px)`; + break; + default: + break; + } + } + } + }); + resizeObserver.observe(headerSelector[0]); + }; + addResizeHeaderListener(); } function updateSearchData(vm) { diff --git a/packages/core-web/src/styles/markbind.css b/packages/core-web/src/styles/markbind.css index 172a06db93..76946594d4 100644 --- a/packages/core-web/src/styles/markbind.css +++ b/packages/core-web/src/styles/markbind.css @@ -120,7 +120,7 @@ code.hljs.inline { header[fixed] { position: fixed; width: 100%; - z-index: 1000; + z-index: 1001; } /* #app is treated as the main container */ diff --git a/packages/vue-components/src/Navbar.vue b/packages/vue-components/src/Navbar.vue index 874b5cffa1..c2be04f3a0 100644 --- a/packages/vue-components/src/Navbar.vue +++ b/packages/vue-components/src/Navbar.vue @@ -1,31 +1,39 @@ @@ -255,4 +280,12 @@ export default { color: #fff !important; background: #007bff; } + + .lower-navbar-container { + background-color: #fff; + border-bottom: 1px solid #c1c1c1; + height: 50px; + width: 100%; + position: relative; + } diff --git a/packages/vue-components/src/Overlay.vue b/packages/vue-components/src/Overlay.vue new file mode 100644 index 0000000000..84581dacea --- /dev/null +++ b/packages/vue-components/src/Overlay.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/packages/vue-components/src/PageNavButton.vue b/packages/vue-components/src/PageNavButton.vue new file mode 100644 index 0000000000..8f963c1941 --- /dev/null +++ b/packages/vue-components/src/PageNavButton.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/packages/vue-components/src/SiteNavButton.vue b/packages/vue-components/src/SiteNavButton.vue new file mode 100644 index 0000000000..d5614f81d2 --- /dev/null +++ b/packages/vue-components/src/SiteNavButton.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/packages/vue-components/src/__tests__/Navbar.spec.js b/packages/vue-components/src/__tests__/Navbar.spec.js new file mode 100644 index 0000000000..1486a7e2e3 --- /dev/null +++ b/packages/vue-components/src/__tests__/Navbar.spec.js @@ -0,0 +1,87 @@ +import { mount } from '@vue/test-utils'; +import Navbar from '../Navbar.vue'; +import PageNavButton from '../PageNavButton.vue'; +import SiteNavButton from '../SiteNavButton.vue'; + +const DEFAULT_STUBS = { + 'page-nav-button': PageNavButton, + 'site-nav-button': SiteNavButton, +}; + +const NAVBAR_CONTENT = ` +Your Logo +
  • Topic 1
  • +
  • Topic 2
  • + +`; + +const OMIT_PAGE_AND_SITE_NAV_BUTTONS = '
    '; + +const SITE_NAV_BUTTON = ` + +`; + +const PAGE_NAV_BUTTON = ` + +`; + +const SITE_AND_PAGE_NAV_BUTTONS = ` + +`; + +describe('Navbar and secondary navbar', () => { + test('navbar without site and page nav buttons', async () => { + const wrapper = mount(Navbar, { + slots: { + default: NAVBAR_CONTENT, + 'lower-navbar': OMIT_PAGE_AND_SITE_NAV_BUTTONS, + }, + stubs: DEFAULT_STUBS, + }); + + expect(wrapper.element).toMatchSnapshot(); + }); + + test('navbar with site nav button', async () => { + const wrapper = mount(Navbar, { + slots: { + default: NAVBAR_CONTENT, + 'lower-navbar': SITE_NAV_BUTTON, + }, + stubs: DEFAULT_STUBS, + }); + + expect(wrapper.element).toMatchSnapshot(); + }); + + test('navbar with page nav button', async () => { + const wrapper = mount(Navbar, { + slots: { + default: NAVBAR_CONTENT, + 'lower-navbar': PAGE_NAV_BUTTON, + }, + stubs: DEFAULT_STUBS, + }); + + expect(wrapper.element).toMatchSnapshot(); + }); + + test('navbar with site and page nav buttons', async () => { + const wrapper = mount(Navbar, { + slots: { + default: NAVBAR_CONTENT, + 'lower-navbar': SITE_AND_PAGE_NAV_BUTTONS, + }, + stubs: DEFAULT_STUBS, + }); + + expect(wrapper.element).toMatchSnapshot(); + }); +}); diff --git a/packages/vue-components/src/__tests__/__snapshots__/Navbar.spec.js.snap b/packages/vue-components/src/__tests__/__snapshots__/Navbar.spec.js.snap new file mode 100644 index 0000000000..3d723db6c4 --- /dev/null +++ b/packages/vue-components/src/__tests__/__snapshots__/Navbar.spec.js.snap @@ -0,0 +1,303 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Navbar and secondary navbar navbar with page nav button 1`] = ` +
    + + + +
    +`; + +exports[`Navbar and secondary navbar navbar with site and page nav buttons 1`] = ` +
    + + + +
    +`; + +exports[`Navbar and secondary navbar navbar with site nav button 1`] = ` +
    + + + +
    +`; + +exports[`Navbar and secondary navbar navbar without site and page nav buttons 1`] = ` +
    + + + +`; diff --git a/packages/vue-components/src/index.js b/packages/vue-components/src/index.js index 72493e927d..cba13d00d1 100644 --- a/packages/vue-components/src/index.js +++ b/packages/vue-components/src/index.js @@ -26,6 +26,9 @@ import tipBox from './TipBox.vue'; import trigger from './Trigger.vue'; import siteNav from './SiteNav.vue'; import submenu from './Submenu.vue'; +import siteNavButton from './SiteNavButton.vue'; +import pageNavButton from './PageNavButton.vue'; +import overlay from './Overlay.vue'; const components = { box: tipBox, @@ -46,6 +49,9 @@ const components = { trigger, siteNav, submenu, + siteNavButton, + pageNavButton, + overlay, }; const directives = { diff --git a/packages/vue-components/src/utils/pubsub.js b/packages/vue-components/src/utils/pubsub.js new file mode 100644 index 0000000000..9c5eb2e29d --- /dev/null +++ b/packages/vue-components/src/utils/pubsub.js @@ -0,0 +1,15 @@ +const subscribers = {}; + +export function subscribe(event, handler) { + if (!subscribers[event]) { + subscribers[event] = []; + } + subscribers[event].push(handler); +} + +export function publish(event) { + if (!subscribers[event]) { + return; + } + subscribers[event].forEach(handler => handler()); +}