add mobile nav

This commit is contained in:
Philipp Kühn
2020-10-12 18:42:47 +02:00
parent f0cfd8e877
commit 9797a0b7a8
6 changed files with 141 additions and 40 deletions

View File

@@ -16,6 +16,7 @@
"globby": "^11.0.0",
"gridsome": "0.7.21",
"gridsome-plugin-simple-analytics": "^1.1.0",
"portal-vue": "^2.1.7",
"raw-loader": "^4.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",

View File

@@ -10,7 +10,7 @@
&:hover {
color: $colorWhite;
background-color: rgba($colorWhite, 0.1);
background-color: rgba($colorWhite, 0.05);
}
}
}

View File

@@ -96,34 +96,30 @@
</g-link>
</div>
<nav class="app__navigation">
<div class="app__link-group" v-for="(linkGroup, i) in linkGroups" :key="i">
<div class="app__link-group-title">
{{ linkGroup.title }}
</div>
<ul class="app__link-list">
<li v-for="(item, j) in linkGroup.items" :key="j">
<g-link :class="{ 'app__link': true, 'app__link--draft': item.draft === true, 'app__link--with-children': item.items }" :to="item.link" :exact="item.link === '/'">
{{ item.title }}
</g-link>
<ul v-if="item.items" class="app__link-list">
<li v-for="(item, k) in item.items" :key="k">
<g-link :class="{ 'app__link': true, 'app__link--draft': item.draft === true }" :to="item.link" exact>
{{ item.title }}
</g-link>
</li>
</ul>
</li>
</ul>
</div>
</nav>
<portal-target name="desktop-nav" />
</div>
<div class="app__content">
<div class="app__top-bar">
<div class="app__inner">
<div class="app__inner app__top-bar-inner">
<input class="app__search" type="search" placeholder="Search">
<button
class="app__menu-icon"
@click="menuIsVisible = true"
v-if="!menuIsVisible"
>
<icon name="menu" />
</button>
<button
class="app__close-icon"
@click="menuIsVisible = false"
v-if="menuIsVisible"
>
<icon name="close" />
</button>
</div>
<div class="app__mobile-nav" v-if="menuIsVisible">
<portal-target name="mobile-nav" />
</div>
</div>
<main class="app__main">
@@ -146,6 +142,31 @@
</div>
</div>
</div>
<portal :to="portal">
<nav class="app__navigation">
<div class="app__link-group" v-for="(linkGroup, i) in linkGroups" :key="i">
<div class="app__link-group-title">
{{ linkGroup.title }}
</div>
<ul class="app__link-list">
<li v-for="(item, j) in linkGroup.items" :key="j">
<g-link :class="{ 'app__link': true, 'app__link--draft': item.draft === true, 'app__link--with-children': item.items }" :to="item.link" :exact="item.link === '/'">
{{ item.title }}
</g-link>
<ul v-if="item.items" class="app__link-list">
<li v-for="(item, k) in item.items" :key="k">
<g-link :class="{ 'app__link': true, 'app__link--draft': item.draft === true }" :to="item.link" exact>
{{ item.title }}
</g-link>
</li>
</ul>
</li>
</ul>
</div>
</nav>
</portal>
</div>
</template>
@@ -159,13 +180,13 @@ query {
<script>
import linkGroups from '@/links.yaml'
// import Icon from '@/components/Icon'
import Icon from '@/components/Icon'
import PageNavigation from '@/components/PageNavigation'
// import GithubButton from 'vue-github-button'
export default {
components: {
// Icon,
Icon,
PageNavigation,
// GithubButton,
},
@@ -174,13 +195,23 @@ export default {
return {
linkGroups,
menuIsVisible: false,
windowWidth: null,
}
},
computed: {
portal() {
if (this.windowWidth && this.windowWidth < 800) {
return 'mobile-nav'
}
return 'desktop-nav'
},
currentPath() {
return this.$route.matched[0].path
},
editLink() {
const { currentPath } = this
const filePath = currentPath === '' ? '/introduction' : currentPath
@@ -189,6 +220,12 @@ export default {
},
},
watch: {
$route() {
this.menuIsVisible = false
},
},
methods: {
initSearch() {
// eslint-disable-next-line
@@ -199,10 +236,21 @@ export default {
debug: false,
})
},
handleResize() {
this.windowWidth = window.innerWidth
},
},
mounted() {
this.initSearch()
this.handleResize()
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize)
},
}
</script>

View File

@@ -1,5 +1,5 @@
$navHeight: 4.5rem;
$menuBreakPoint: 750px;
$menuBreakPoint: 800px;
.app {
display: flex;
@@ -30,8 +30,8 @@ $menuBreakPoint: 750px;
&__search {
display: block;
width: 100%;
background-color: rgba($colorWhite, 0.08);
border: 1px solid rgba($colorWhite, 0.08);
background-color: transparent;
border: 1px solid rgba($colorWhite, 0.1);
border-radius: 0.5rem;
font: inherit;
color: $colorWhite;
@@ -39,16 +39,23 @@ $menuBreakPoint: 750px;
}
&__sidebar {
width: 20rem;
flex: 0 0 auto;
position: sticky;
top: 0;
align-self: flex-start;
padding: 2rem;
height: 100vh;
overflow: auto;
overscroll-behavior: contain;
border-right: 1px solid rgba($colorWhite, 0.1);
display: none;
@media (min-width: $menuBreakPoint) {
display: block;
width: 20rem;
flex: 0 0 auto;
position: sticky;
top: 0;
align-self: flex-start;
padding: 2rem;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
border-right: 1px solid rgba($colorWhite, 0.1);
}
}
&__content {
@@ -57,11 +64,14 @@ $menuBreakPoint: 750px;
}
&__top-bar {
display: flex;
flex-direction: column;
padding: 1rem 0;
position: sticky;
z-index: 2;
top: 0;
backdrop-filter: blur(10px);
max-height: 100vh;
&::after {
content: '';
@@ -78,6 +88,32 @@ $menuBreakPoint: 750px;
}
}
&__top-bar-inner {
width: 100%;
display: flex;
align-items: center;
flex: 0 0 auto;
}
&__menu-icon,
&__close-icon {
display: flex;
flex: 0 0 auto;
background: transparent;
border: 0;
color: $colorText;
margin-left: 1rem;
transition: color 0.2s $ease;
&:hover {
color: $colorWhite;
}
@media (min-width: $menuBreakPoint) {
display: none;
}
}
&__inner {
margin: 0 auto;
max-width: 50rem;
@@ -123,7 +159,7 @@ $menuBreakPoint: 750px;
&.active {
color: $colorWhite;
background-color: rgba($colorWhite, 0.08);
background-color: rgba($colorWhite, 0.05);
}
&--draft {
@@ -143,4 +179,13 @@ $menuBreakPoint: 750px;
&__page-navigation {
border-top: 1px solid rgba($colorWhite, 0.1);
}
&__mobile-nav {
padding: 1rem 2rem;
flex: 1 1 auto;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
}
}

View File

@@ -2,9 +2,11 @@
import Prism from 'prismjs'
import 'prismjs/components/prism-jsx.js'
import 'prismjs/components/prism-scss.js'
import PortalVue from 'portal-vue'
import App from '~/layouts/App'
export default function (Vue) {
Vue.use(PortalVue)
Vue.component('Layout', App)
Vue.component('Demo', () => import(/* webpackChunkName: "demo" */ '~/components/Demo'))
Vue.component('LiveDemo', () => import(/* webpackChunkName: "live-demo" */ '~/components/LiveDemo'))

View File

@@ -10756,6 +10756,11 @@ pngquant-bin@^5.0.0:
execa "^0.10.0"
logalot "^2.0.0"
portal-vue@^2.1.7:
version "2.1.7"
resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
integrity sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==
portfinder@^1.0.20:
version "1.0.28"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"