add mobile nav
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
&:hover {
|
||||
color: $colorWhite;
|
||||
background-color: rgba($colorWhite, 0.1);
|
||||
background-color: rgba($colorWhite, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'))
|
||||
|
||||
Reference in New Issue
Block a user