Made responsive menu and dropdown
This commit is contained in:
parent
fd1c4ee14d
commit
c63ace6f08
8
client/src/assets/js/menu-toggle.js
Normal file
8
client/src/assets/js/menu-toggle.js
Normal file
@ -0,0 +1,8 @@
|
||||
const menuButton = document.getElementById('menu-btn')
|
||||
const mobileNav = document.getElementById('mobile-nav')
|
||||
|
||||
menuButton.addEventListener('click', ()=> {
|
||||
menuButton.classList.toggle('menu-active')
|
||||
mobileNav.classList.toggle('flex')
|
||||
mobileNav.classList.toggle('hidden')
|
||||
})
|
@ -1,19 +1,30 @@
|
||||
<script>
|
||||
import { mdiAccountQuestion, mdiHome, mdiInformation } from '@mdi/js'
|
||||
import mdiMenu from '@/components/icons/Menu.vue'
|
||||
import MobileLink from '@/components/navbar/MobileLink.vue'
|
||||
import Navlink from '@/components/navbar/Navlink.vue'
|
||||
export default {
|
||||
name: 'Navbar',
|
||||
components: {
|
||||
mdiMenu,
|
||||
MobileLink,
|
||||
Navlink
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menuActive: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleMenu() {
|
||||
this.menuActive = !this.menuActive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<nav class="fixed bg-lime-900 text-white shadow-xl w-full">
|
||||
<div class="flex relative px-2 max-w-5xl mx-auto items-center justify-between">
|
||||
<nav class="fixed bg-lime-900 text-white shadow-xl w-full z-50">
|
||||
<div class="flex relative px-2 max-w-5xl mx-auto items-center justify-between z-50">
|
||||
<!-- Logo -->
|
||||
<div class="inline-flex justify-center items-center">
|
||||
<img src="@/assets/vue.svg" class="p-2" alt="Vite Logo" >
|
||||
@ -23,16 +34,68 @@
|
||||
<div class="hidden md:flex space-x-3 justify-center items-center">
|
||||
<Navlink :svgPath="route.meta.svgPath" :text="route.meta.title" :to="route.path" v-for="route in $router.options.routes" :key="route.path" />
|
||||
</div>
|
||||
<button id="menu-btn" class="block md:hidden focus:outline-none">
|
||||
<mdiMenu />
|
||||
<button id="menu-btn" title="Toggle Menu" aria-title="Toggle Menu" class="block focus:ring relative menu-toggle md:hidden focus:outline-none" :class="{'menu-active': menuActive}" @click="toggleMenu">
|
||||
<span class="menu-toggle-top"></span>
|
||||
<span class="menu-toggle-middle"></span>
|
||||
<span class="menu-toggle-bottom"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hidden md:hidden">
|
||||
<div id="menu" class="absolute flex flex-col self-end font-bold sm:w-auto drop-shadow-md">
|
||||
<Navlink :svgPath="route.meta.svgPath" :text="route.meta.title" :to="route.path" v-for="route in $router.options.routes" :key="route.path" />
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-200 ease-in"
|
||||
enter-from-class="opacity-0 -translate-y-1/3"
|
||||
leave-active-class="transition-all duration-200 ease-out"
|
||||
leave-to-class="opacity-0 -translate-y-1/3"
|
||||
>
|
||||
<div id="mobile-nav" class="z-0 w-full bg-lime-700 p-2 space-y-1 absolute flex-col self-end self-center font-bold drop-shadow-md flex md:hidden" v-if="menuActive">
|
||||
<MobileLink :svgPath="route.meta.svgPath" :text="route.meta.title" :to="route.path" v-for="route in $router.options.routes" :key="route.path" @optionSelected="toggleMenu" />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</nav>
|
||||
</template>
|
||||
<style scoped>
|
||||
.menu-toggle {
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transition: all 0.3s;
|
||||
position: relative;
|
||||
}
|
||||
.menu-toggle-top, .menu-toggle-middle, .menu-toggle-bottom {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 24px;
|
||||
height: 2px;
|
||||
@apply bg-white;
|
||||
transform: rotate(0);
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.menu-toggle-top {
|
||||
transform: translateY(4px);
|
||||
}
|
||||
|
||||
.menu-toggle-middle {
|
||||
transform: translateY(11px);
|
||||
}
|
||||
|
||||
.menu-toggle-bottom {
|
||||
transform: translateY(18px);
|
||||
}
|
||||
|
||||
.menu-active {
|
||||
transform: rotate(90deg) translateY(0px);
|
||||
}
|
||||
|
||||
.menu-active .menu-toggle-top {
|
||||
transform: rotate(45deg) translateX(6px) translateY(6px);
|
||||
}
|
||||
|
||||
.menu-active .menu-toggle-middle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-active .menu-toggle-bottom {
|
||||
transform: rotate(-45deg) translateX(-6px) translateY(6px);
|
||||
}
|
||||
</style>
|
@ -6,36 +6,39 @@ export default {
|
||||
components: {
|
||||
SvgIcon
|
||||
},
|
||||
methods: {
|
||||
optionSelected() {
|
||||
this.$emit('optionSelected')
|
||||
}
|
||||
},
|
||||
props: [
|
||||
"path",
|
||||
"svgPath",
|
||||
"text",
|
||||
"to"
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<a :href="to" class="navlink" target="_blank" rel="noopener noreferrer" v-if="to.startsWith('http')">
|
||||
<div class="inline-flex px-3 py-1">
|
||||
<a :href="to" class="navlink w-full" target="_blank" rel="noopener noreferrer" v-if="to.startsWith('http')" v-on:click="optionSelected">
|
||||
<div class="inline-flex px-3 py-1 space-x-1">
|
||||
<span class="scale-75">
|
||||
<svg-icon type="mdi" :path="path"></svg-icon>
|
||||
<svg-icon type="mdi" :path="svgPath"></svg-icon>
|
||||
</span>
|
||||
<span>{{ text }}</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="relative flex" v-else>
|
||||
<div class="relative flex">
|
||||
<router-link active-class="active-link" class="navlink" :to="to">
|
||||
<div class="inline-flex px-3 py-1">
|
||||
<span class="scale-75">
|
||||
<svg-icon type="mdi" :path="path"></svg-icon>
|
||||
</span>
|
||||
<span>{{ text }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
<router-link active-class="active-link" class="navlink w-full" :to="to" v-on:click="optionSelected">
|
||||
<div class="inline-flex px-3 py-1 space-x-1">
|
||||
<span class="scale-75">
|
||||
<svg-icon type="mdi" :path="svgPath"></svg-icon>
|
||||
</span>
|
||||
<span>{{ text }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
<style scoped>
|
||||
.navlink.active-link, .navlink.exact-active-link {
|
||||
@apply bg-orange-500;
|
||||
@apply text-white;
|
||||
@ -44,7 +47,6 @@ export default {
|
||||
}
|
||||
.navlink {
|
||||
@apply hover:text-orange-300;
|
||||
@apply bg-lime-800;
|
||||
@apply active:text-orange-500;
|
||||
@apply rounded-lg;
|
||||
@apply h-fit;
|
||||
|
@ -102,12 +102,12 @@ Router.beforeEach((to, from, next) => {
|
||||
Router.afterEach( (to, from) => {
|
||||
const enterActiveClass = 'transition-all duration-300 ease-in'
|
||||
const leaveActiveClass = 'transition-all duration-300 ease-out'
|
||||
const baseFromClass = 'transform opacity-0 scale-75'
|
||||
const baseFromClass = 'transform opacity-0 md:scale-75'
|
||||
if ( to.fullPath.split('/')[1] !== from.fullPath.split('/')[1] || !from.matched.length ) {
|
||||
const fromIndex = from.meta.parentIndex ? from.meta.parentIndex : from.meta.index
|
||||
const toIndex = to.meta.parentIndex ? to.meta.parentIndex : to.meta.index
|
||||
const slideInDirection = toIndex < fromIndex ? '-translate-x-1/3' : 'translate-x-1/3'
|
||||
const slideOutDirection = toIndex < fromIndex ? 'translate-x-1/3' : '-translate-x-1/3'
|
||||
const slideInDirection = toIndex < fromIndex ? 'md:-translate-x-1/3' : 'md:translate-x-1/3'
|
||||
const slideOutDirection = toIndex < fromIndex ? 'md:translate-x-1/3' : 'md:-translate-x-1/3'
|
||||
to.meta.mainEnterActiveClass = enterActiveClass
|
||||
to.meta.mainLeaveActiveClass = leaveActiveClass
|
||||
to.meta.mainEnterFromClass = baseFromClass + ' ' + slideInDirection
|
||||
@ -115,8 +115,8 @@ Router.afterEach( (to, from) => {
|
||||
} else if ( to.fullPath.split('/')[1] == from.fullPath.split('/')[1] && from.matched.length ) {
|
||||
const fromIndex = from.meta.index
|
||||
const toIndex = to.meta.index
|
||||
const slideInDirection = toIndex < fromIndex ? '-translate-y-1/3' : 'translate-y-1/3'
|
||||
const slideOutDirection = toIndex < fromIndex ? 'translate-y-1/3' : '-translate-y-1/3'
|
||||
const slideInDirection = toIndex < fromIndex ? 'md:-translate-y-1/3' : 'md:translate-y-1/3'
|
||||
const slideOutDirection = toIndex < fromIndex ? 'md:translate-y-1/3' : 'md:-translate-y-1/3'
|
||||
to.meta.panelEnterActiveClass = enterActiveClass
|
||||
to.meta.panelLeaveActiveClass = leaveActiveClass
|
||||
to.meta.panelEnterFromClass = baseFromClass + ' ' + slideInDirection
|
||||
|
@ -10,7 +10,7 @@
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex flex-col md:flex-row space-x-6">
|
||||
<div class="flex flex-col space-y-3 md:flex-row md:space-x-6 md:space-y-0">
|
||||
<div class="flex flex-col w-full md:w-1/3 h-fit">
|
||||
<Sidebar :prefix="$router.options.routes[2].path" :routes="$router.options.routes[2].children">
|
||||
<template v-slot:header>
|
||||
|
Loading…
Reference in New Issue
Block a user