Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-docs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSarah German <sgerman@gitlab.com>2022-07-27 19:40:59 +0300
committerSarah German <sgerman@gitlab.com>2022-07-27 19:40:59 +0300
commit816bb25394206abacabd46295b30cb1c9a0bd7ab (patch)
tree336a99f1be22c0edeeb4d8bb18f1a5de78748a6a
parentb3f13cc29373981c2a5ebb17b396a891e7cb4e31 (diff)
Toggle nav on browser resize1082-responsive-navbar
-rw-r--r--content/assets/stylesheets/stylesheet.scss44
-rw-r--r--content/frontend/default/components/navigation_toggle.vue66
-rw-r--r--spec/frontend/__mocks__/match_media_mock.js15
-rw-r--r--spec/frontend/default/components/navigation_toggle_spec.js27
4 files changed, 98 insertions, 54 deletions
diff --git a/content/assets/stylesheets/stylesheet.scss b/content/assets/stylesheets/stylesheet.scss
index 5866f6b6..74350e35 100644
--- a/content/assets/stylesheets/stylesheet.scss
+++ b/content/assets/stylesheets/stylesheet.scss
@@ -88,27 +88,23 @@ ol {
&.active {
width: $sidebar-width;
.nav-toggle {
- .arrow {
- left: 19px;
- transform: rotate(0);
- &:nth-child(2) {
- left: 25px;
- }
- }
.label {
display: block;
pointer-events: none;
font-size: 0.875rem;
color: $gds-gray-700;
- margin-left: 30px;
flex-shrink: 0;
}
+ svg {
+ transform: scaleX(-1);
+ }
}
.global-nav {
visibility: visible;
}
}
.nav-toggle {
+ display: flex;
width: 100%;
height: 50px;
flex-shrink: 0;
@@ -118,34 +114,8 @@ ol {
.label {
display: none;
}
- .arrow,
- .arrow::before,
- .arrow::after {
- cursor: pointer;
- pointer-events: none;
- border-radius: 1px;
- height: 2px;
- width: 9px;
- background: $gds-gray-700;
- position: absolute;
- display: block;
- content: '';
- }
- .arrow {
- transform: rotate(180deg);
- background-color: transparent;
- &:nth-child(2) {
- left: 19px;
- }
- }
- .arrow::before {
- top: 0;
- transform: rotate(45deg) translateY(4px);
- }
- .arrow::after {
- top: 0;
- bottom: -7px;
- transform: rotate(-45deg) translateY(-4px);
+ svg {
+ fill: $gds-gray-700;
}
}
.gl-button.nav-toggle {
@@ -165,7 +135,7 @@ ol {
width: $sidebar-mobile-width;
.nav-toggle {
- display: block;
+ display: flex;
}
}
}
diff --git a/content/frontend/default/components/navigation_toggle.vue b/content/frontend/default/components/navigation_toggle.vue
index 0d50894d..8aaf8bec 100644
--- a/content/frontend/default/components/navigation_toggle.vue
+++ b/content/frontend/default/components/navigation_toggle.vue
@@ -1,6 +1,8 @@
<script>
import GlButton from '@gitlab/ui/src/components/base/button/button.vue';
+const mediaQuery = window.matchMedia(`(max-width: 1199px`);
+
export default {
components: {
GlButton,
@@ -11,8 +13,21 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ width: null,
+ open: null,
+ };
+ },
+ created() {
+ this.width = window.innerWidth;
+ mediaQuery.addEventListener('change', this.responsiveToggle);
+ },
+ beforeDestroy() {
+ mediaQuery.addEventListener('change', this.responsiveToggle);
+ },
methods: {
- toggle() {
+ toggle(direction = '') {
this.targetSelector.forEach((el) => {
const target = document.querySelector(el);
@@ -20,24 +35,49 @@ export default {
return;
}
- target.classList.toggle('active');
+ switch (direction) {
+ case 'open':
+ target.classList.add('active');
+ this.open = true;
+ break;
+ case 'close':
+ target.classList.remove('active');
+ this.open = false;
+ break;
+ default:
+ target.classList.toggle('active');
+ this.open = !this.open;
+ }
});
},
+ /**
+ * Toggle the menu visibility based on a change event.
+ *
+ * @param {*} e
+ * A media query change event.
+ * In this method, we use the "matches" property to check
+ * if the media query returns true or false.
+ */
+ responsiveToggle(e) {
+ const newWidth = window.innerWidth;
+
+ // Browser is less wide than 1199px and has decreased in width.
+ if (e.matches && newWidth < this.width) {
+ this.toggle('close');
+ }
+ // Browser is wider than 1199px and has increased in width.
+ if (!e.matches && newWidth > this.width) {
+ this.toggle('open');
+ }
+
+ this.width = newWidth;
+ },
},
};
</script>
<template>
- <gl-button class="nav-toggle border-right-0" @click="toggle">
- <!--
- TODO: Replace arrows with 'angle-double-right' icon using the icon component from gitlab-ui
- We'll do this once https://gitlab.com/gitlab-org/gitlab-ui/issues/98 is complete.
- Issue to add gitlab-ui to this project: https://gitlab.com/gitlab-org/gitlab-docs/issues/443
- -->
- <div class="d-flex align-items-center">
- <span class="arrow"></span>
- <span class="arrow"></span>
- <div class="label">Collapse sidebar</div>
- </div>
+ <gl-button class="nav-toggle gl-border-none gl-pl-5!" icon="angle-double-right" @click="toggle">
+ <span class="label gl-ml-2">Collapse sidebar</span>
</gl-button>
</template>
diff --git a/spec/frontend/__mocks__/match_media_mock.js b/spec/frontend/__mocks__/match_media_mock.js
new file mode 100644
index 00000000..0f2d0192
--- /dev/null
+++ b/spec/frontend/__mocks__/match_media_mock.js
@@ -0,0 +1,15 @@
+/**
+ * Mock matchMedia since it is not available in JSDOM.
+ * https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
+ */
+Object.defineProperty(window, 'matchMedia', {
+ writable: true,
+ value: jest.fn().mockImplementation((query) => ({
+ matches: false,
+ media: query,
+ onchange: null,
+ addEventListener: jest.fn(),
+ removeEventListener: jest.fn(),
+ dispatchEvent: jest.fn(),
+ })),
+});
diff --git a/spec/frontend/default/components/navigation_toggle_spec.js b/spec/frontend/default/components/navigation_toggle_spec.js
index 67dd0338..5eacf0d8 100644
--- a/spec/frontend/default/components/navigation_toggle_spec.js
+++ b/spec/frontend/default/components/navigation_toggle_spec.js
@@ -3,6 +3,7 @@
*/
import { mount } from '@vue/test-utils';
+import '../../__mocks__/match_media_mock';
import NavigationToggle from '../../../../content/frontend/default/components/navigation_toggle.vue';
describe('component: Navigation Toggle', () => {
@@ -24,10 +25,6 @@ describe('component: Navigation Toggle', () => {
expect(wrapper.find('.label').text()).toEqual('Collapse sidebar');
});
- it('renders two arrow icons', () => {
- expect(wrapper.findAll('.arrow').length).toEqual(2);
- });
-
it('toggles the navigation when the navigation toggle is clicked', () => {
const findMenu = () => document.querySelector(`.${className}`);
jest.spyOn(findMenu().classList, 'toggle');
@@ -35,4 +32,26 @@ describe('component: Navigation Toggle', () => {
wrapper.find('.nav-toggle').trigger('click');
expect(findMenu().classList.toggle).toHaveBeenCalledWith('active');
});
+
+ it('toggles the navigation when changing breakpoints', () => {
+ // Mock an event of the media query returning negative.
+ // This represents the browser not matching "max-width: 1199px,"
+ // meaning we have rezised up to a large window.
+ wrapper.setData({ width: 500 }); // Mock the starting width.
+ let mockChangeMatchMediaEvent = {
+ matches: false,
+ };
+ // Expect an open menu for large windows.
+ wrapper.vm.responsiveToggle(mockChangeMatchMediaEvent);
+ expect(wrapper.vm.open).toBe(true);
+
+ // Mock resizing down to a small window, where max-width:1199px is true.
+ wrapper.setData({ width: 1200 }); // Mock starting width.
+ mockChangeMatchMediaEvent = {
+ matches: true,
+ };
+ // The menu should be closed.
+ wrapper.vm.responsiveToggle(mockChangeMatchMediaEvent);
+ expect(wrapper.vm.open).toBe(false);
+ });
});