Skip to content

Commit 3c8881d

Browse files
committed
Add mobile navigation
1 parent 3bf4a38 commit 3c8881d

File tree

8 files changed

+121
-30
lines changed

8 files changed

+121
-30
lines changed

components/GvdHeader.vue

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
<script setup lang="ts">
2+
import { useIsDesktop } from '~/composables/useIsDesktop'
3+
4+
const isDesktop = useIsDesktop()
5+
const showMobileNav = ref(false)
6+
7+
function toggleMobileNav() {
8+
showMobileNav.value = !showMobileNav.value
9+
}
10+
11+
onBeforeRouteLeave((to, from, next) => {
12+
showMobileNav.value = false;
13+
next()
14+
})
15+
</script>
16+
117
<template>
218
<header class="govuk-header gvd-header" role="banner">
319
<div class="govuk-header__container govuk-width-container gvd-header__container gvd-width-container">
@@ -19,8 +35,12 @@
1935
</span>
2036
</a>
2137
</div>
38+
<button v-if="!isDesktop" class="govuk-header__menu-button" :class="{ 'govuk-header__menu-button--open': showMobileNav }" aria-controls="gvd-navigation" :aria-expanded="showMobileNav" @click="toggleMobileNav">
39+
Menu
40+
</button>
2241
</div>
2342
</header>
43+
<gvd-navigation :show-mobile-nav="showMobileNav"/>
2444
</template>
2545

2646
<style lang="scss" scoped>

components/GvdNavigation.vue

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,47 @@
11
<script setup lang="ts">
2+
import { useIsDesktop } from '~/composables/useIsDesktop'
3+
24
const props = defineProps({
3-
to: String
5+
showMobileNav: Boolean
46
})
57
68
const currentPath = useRoute().path
9+
const isDesktop = useIsDesktop()
10+
11+
const expandedSections = ref(new Array<string>)
12+
13+
function pathToSubnavId(path: string) {
14+
return `subnav-${path.replaceAll('/','')}`;
15+
}
16+
17+
function toggleSection(path: string) {
18+
if(expandedSections.value.includes(path)) {
19+
expandedSections.value = expandedSections.value.filter(s => s !== path)
20+
} else {
21+
expandedSections.value.push(path)
22+
}
23+
}
724
</script>
825

926
<template>
10-
<nav id="gvd-navigation" class="gvd-navigation govuk-clearfix" role="navigation" aria-labelledby="gvd-navigation-heading">
27+
<nav id="gvd-navigation" class="gvd-navigation govuk-clearfix" role="navigation" aria-labelledby="gvd-navigation-heading" :hidden="!showMobileNav && !isDesktop">
1128
<h1 class="govuk-visually-hidden" id="gvd-navigation-heading">Menu</h1>
1229
<ContentNavigation v-slot="{ navigation }">
1330
<ul class="gvd-navigation__list gvd-width-container">
1431
<li v-for="link of navigation.filter(n => n.title != 'Example page')" :key="link._path" class="gvd-navigation__list-item" :class="{'gvd-navigation__list-item--current': currentPath.startsWith(link._path)}">
15-
<NuxtLink :to="link._path" class="govuk-link govuk-link--no-visited-state govuk-link--no-underline app-navigation__link js-app-navigation__link">
32+
<NuxtLink v-if="isDesktop" :to="link._path" class="govuk-link govuk-link--no-visited-state govuk-link--no-underline app-navigation__link js-app-navigation__link">
1633
{{ link.title }}
1734
</NuxtLink>
35+
<button v-if="!isDesktop" class="gvd-navigation__button" :aria-expanded="expandedSections.includes(link._path)" :aria-controls="pathToSubnavId(link._path)" @click="toggleSection(link._path)">
36+
{{ link.title }}
37+
</button>
38+
<ul v-if="!isDesktop" class="gvd-navigation__subnav" :aria-label="link.title" :id="pathToSubnavId(link._path)" :hidden="!expandedSections.includes(link._path)">
39+
<li v-for="child of link.children" class="gvd-navigation__subnav-item">
40+
<NuxtLink :to="child._path" class="govuk-link govuk-link--no-visited-state govuk-link--no-underline">
41+
{{ child.title }} <template v-if="child._path === link._path">overview</template>
42+
</NuxtLink>
43+
</li>
44+
</ul>
1845
</li>
1946
</ul>
2047
</ContentNavigation>
@@ -46,6 +73,10 @@ $app-light-grey: #f8f8f8;
4673
.gvd-navigation {
4774
border-bottom: 1px solid $govuk-border-colour;
4875
background-color: $app-light-grey;
76+
77+
&[hidden] {
78+
display: none;
79+
}
4980
}
5081
5182
.gvd-navigation__list {

components/GvdPageWrapper.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<template>
22
<gvd-header/>
3-
<gvd-navigation/>
43
<div class="gvd-phase-banner-wrapper">
54
<gv-phase-banner tag="alpha" tag-colour="red" class="gvd-phase-banner">GOV.UK Vue is in alpha, and some documentation is not complete - your <nuxt-link to="/support" class="govuk-link">feedback</nuxt-link> will help to improve it.</gv-phase-banner>
65
</div>

composables/useIsDesktop.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ref, onMounted, onUnmounted } from 'vue'
2+
3+
export function useIsDesktop() {
4+
let mediaQuery: MediaQueryList
5+
const isDesktop = ref(false)
6+
7+
function updateIsDesktop() {
8+
isDesktop.value = mediaQuery.matches
9+
}
10+
11+
onMounted(() => {
12+
// Set up mediaQuery in onMounted so that we know we're running on the client, not SSR
13+
// min-width is the govuk-frontend desktop breakpoint
14+
mediaQuery = window.matchMedia('(min-width: 48.0625em)')
15+
updateIsDesktop()
16+
mediaQuery.addEventListener('change', updateIsDesktop)
17+
})
18+
19+
onUnmounted(() => {
20+
mediaQuery.removeEventListener('change', updateIsDesktop)
21+
})
22+
23+
return isDesktop
24+
}
Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
---
2-
layout: getstarted
3-
---
4-
5-
# Get started
6-
7-
## Install GOV.UK Vue
8-
9-
It's easy to add GOV.UK Vue to both new and existing projects. Find out [how to install GOV.UK Vue](/get-started/installing-govuk-vue).
10-
11-
You can [get help](/support) if you need support getting started.
12-
13-
## Using GOV.UK Vue with Nuxt
14-
15-
Find out [how to use GOV.UK Vue with Nuxt](/get-started/using-govuk-vue-with-nuxt).
16-
17-
## Using `router-link` or `nuxt-link`
18-
19-
If you're using Vue Router or Nuxt, find out [how to use router-link or nuxt-link](/get-started/using-router-link-or-nuxt-link) with GOV.UK Vue components.
20-
21-
## Differences to GOV.UK Frontend
22-
23-
If you've used [GOV.UK Frontend](https://frontend.design-system.service.gov.uk/) before, there are some
24-
[differences between GOV.UK Vue and GOV.UK Frontend](/get-started/differences-to-govuk-frontend) that you should be aware of.
1+
---
2+
layout: getstarted
3+
---
4+
5+
# Get started
6+
7+
## Install GOV.UK Vue
8+
9+
It's easy to add GOV.UK Vue to both new and existing projects. Find out [how to install GOV.UK Vue](/get-started/installing-govuk-vue).
10+
11+
You can [get help](/support) if you need support getting started.
12+
13+
## Using GOV.UK Vue with Nuxt
14+
15+
Find out [how to use GOV.UK Vue with Nuxt](/get-started/using-govuk-vue-with-nuxt).
16+
17+
## Using `router-link` or `nuxt-link`
18+
19+
If you're using Vue Router or Nuxt, find out [how to use router-link or nuxt-link](/get-started/using-router-link-or-nuxt-link) with GOV.UK Vue components.
20+
21+
## Differences to GOV.UK Frontend
22+
23+
If you've used [GOV.UK Frontend](https://frontend.design-system.service.gov.uk/) before, there are some
24+
[differences between GOV.UK Vue and GOV.UK Frontend](/get-started/differences-to-govuk-frontend) that you should be aware of.
File renamed without changes.

layouts/component.vue

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<gvd-page-wrapper>
33
<div class="govuk-grid-row">
4-
<div class="govuk-grid-column-one-quarter">
4+
<div class="govuk-grid-column-one-quarter" v-if="isDesktop">
55
<GvdSubNav>
66
<ContentNavigation v-slot="{ navigation }" :query="componentsQuery">
77
<GvdSubNavSection>
@@ -15,6 +15,18 @@
1515
<div class="govuk-grid-column-three-quarters">
1616
<span class="govuk-caption-xl" v-if="page.title != 'Components'">Components</span>
1717
<ContentDoc/>
18+
19+
<ContentNavigation v-slot="{ navigation }" :query="componentsQuery" v-if="page.title === 'Components'">
20+
<nav>
21+
<ul class="govuk-list">
22+
<li class="govuk-!-margin-bottom-2" v-for="link in navigation[0].children" :key="link._path">
23+
<NuxtLink :to="link._path" class="govuk-link">
24+
{{ link.title }}
25+
</NuxtLink>
26+
</li>
27+
</ul>
28+
</nav>
29+
</ContentNavigation>
1830
</div>
1931
</div>
2032

@@ -23,6 +35,8 @@
2335

2436
<script setup lang="ts">
2537
const { page } = useContent()
38+
import { useIsDesktop } from '~/composables/useIsDesktop'
2639
40+
const isDesktop = useIsDesktop()
2741
const componentsQuery = queryContent('components').where({ title: { $ne: 'Components' } })
2842
</script>

layouts/getstarted.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
12
<template>
23
<gvd-page-wrapper>
34
<div class="govuk-grid-row">
4-
<div class="govuk-grid-column-one-quarter">
5+
<div class="govuk-grid-column-one-quarter" v-if="isDesktop">
56
<GvdSubNav>
67
<ContentNavigation v-slot="{ navigation }" :query="getStartedQuery">
78
<GvdSubNavSection>
@@ -22,6 +23,8 @@
2223

2324
<script setup lang="ts">
2425
const { page } = useContent()
26+
import { useIsDesktop } from '~/composables/useIsDesktop'
2527
28+
const isDesktop = useIsDesktop()
2629
const getStartedQuery = queryContent('get-started').where({ title: { $ne: 'Get started' } })
2730
</script>

0 commit comments

Comments
 (0)