Incorporated headlessui/vue

Made a better accessible collapsed menu
This commit is contained in:
Vivek Santayana 2022-08-28 12:19:04 +01:00
parent c63ace6f08
commit 66e30eaf69
4 changed files with 61 additions and 76 deletions

View File

@ -8,6 +8,7 @@
"name": "client", "name": "client",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@headlessui/vue": "^1.6.7",
"@jamescoyle/vue-icon": "^0.1.2", "@jamescoyle/vue-icon": "^0.1.2",
"@mdi/js": "^7.0.96", "@mdi/js": "^7.0.96",
"vue": "^3.2.37", "vue": "^3.2.37",
@ -49,6 +50,17 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@headlessui/vue": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.6.7.tgz",
"integrity": "sha512-5sTCBpkUoFE7zhANn/6Z+pf3PUA7MD6BBaTsJcQybq9E4fnNiMM9agOJI9meXbtcawE6Dm8EeB5A8HAJEnZCbQ==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/@jamescoyle/vue-icon": { "node_modules/@jamescoyle/vue-icon": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/@jamescoyle/vue-icon/-/vue-icon-0.1.2.tgz", "resolved": "https://registry.npmjs.org/@jamescoyle/vue-icon/-/vue-icon-0.1.2.tgz",
@ -1618,6 +1630,12 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"@headlessui/vue": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.6.7.tgz",
"integrity": "sha512-5sTCBpkUoFE7zhANn/6Z+pf3PUA7MD6BBaTsJcQybq9E4fnNiMM9agOJI9meXbtcawE6Dm8EeB5A8HAJEnZCbQ==",
"requires": {}
},
"@jamescoyle/vue-icon": { "@jamescoyle/vue-icon": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/@jamescoyle/vue-icon/-/vue-icon-0.1.2.tgz", "resolved": "https://registry.npmjs.org/@jamescoyle/vue-icon/-/vue-icon-0.1.2.tgz",

View File

@ -9,6 +9,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@headlessui/vue": "^1.6.7",
"@jamescoyle/vue-icon": "^0.1.2", "@jamescoyle/vue-icon": "^0.1.2",
"@mdi/js": "^7.0.96", "@mdi/js": "^7.0.96",
"vue": "^3.2.37", "vue": "^3.2.37",

View File

@ -1,13 +1,19 @@
<script> <script>
import mdiMenu from '@/components/icons/Menu.vue' import mdiMenu from '@/components/icons/Menu.vue'
import MobileLink from '@/components/navbar/MobileLink.vue' import SvgIcon from '@jamescoyle/vue-icon'
import Navlink from '@/components/navbar/Navlink.vue' import Navlink from '@/components/navbar/Navlink.vue'
import {Menu, MenuButton, MenuItem, MenuItems} from '@headlessui/vue'
export default { export default {
name: 'Navbar', name: 'Navbar',
components: { components: {
mdiMenu, mdiMenu,
MobileLink, MobileLink,
Navlink Navlink,
Menu,
MenuButton,
MenuItem,
MenuItems,
SvgIcon
}, },
data() { data() {
return { return {
@ -24,7 +30,7 @@
</script> </script>
<template> <template>
<nav class="fixed bg-lime-900 text-white shadow-xl w-full z-50"> <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"> <div class="flex relative px-2 max-w-5xl mx-auto items-center justify-between">
<!-- Logo --> <!-- Logo -->
<div class="inline-flex justify-center items-center"> <div class="inline-flex justify-center items-center">
<img src="@/assets/vue.svg" class="p-2" alt="Vite Logo" > <img src="@/assets/vue.svg" class="p-2" alt="Vite Logo" >
@ -34,22 +40,40 @@
<div class="hidden md:flex space-x-3 justify-center items-center"> <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" /> <Navlink :svgPath="route.meta.svgPath" :text="route.meta.title" :to="route.path" v-for="route in $router.options.routes" :key="route.path" />
</div> </div>
<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"> <Menu v-slot="{ open }" as="div" class="relative inline-block text-left md:hidden">
<span class="menu-toggle-top"></span> <div>
<span class="menu-toggle-middle"></span> <MenuButton class="inline-flex justify-center w-full rounded-md shadow-sm px-4 py-2 bg-lime-800 text-white hover:bg-lime-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500">
<span class="menu-toggle-bottom"></span> <span class="scale-150">
</button> <mdiMenu/>
</div> </span>
<Transition </MenuButton>
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> <transition enter-active-class="transition ease-out duration-100" enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100" leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
<MenuItems class="origin-top-right absolute right-0 mt-2 p-1 space-y-2 w-56 rounded-md shadow-lg bg-lime-700 ring-1 ring-black ring-opacity-5 focus:outline-none">
<div class="py-1">
<MenuItem v-slot="{ active }" v-for="route in $router.options.routes" :key="route.path" >
<a :href="route.path" target="_blank" rel="noopener noreferrer" :class="[active ? 'text-orange-300' : 'text-white', 'flex px-4 py-2 active:text-orange-500 rounded-lg h-fit align-middle transition-all ease-in-out duration-500']" v-if="route.path.startsWith('http')">
<div class="inline-flex px-3 py-1 space-x-1">
<span class="scale-75">
<svg-icon type="mdi" :path="route.meta.svgPath"></svg-icon>
</span>
<span>{{ route.meta.title }}</span>
</div>
</a>
<router-link :to="route.path" :class="[active ? 'text-white bg-lime-600' : 'text-white', 'flex px-4 py-2 active:text-orange-500 rounded-lg h-fit align-middle transition-all ease-in-out duration-500', this.$route.fullPath == route.path ? 'bg-orange-500 text-white hover:bg-orange-600 hover:text-white' : '']" v-else>
<div class="inline-flex px-3 py-1 space-x-1">
<span class="scale-75">
<svg-icon type="mdi" :path="route.meta.svgPath"></svg-icon>
</span>
<span>{{ route.meta.title }}</span>
</div>
</router-link>
</MenuItem>
</div>
</MenuItems>
</transition>
</Menu>
</div>
</nav> </nav>
</template> </template>
<style scoped> <style scoped>

View File

@ -1,58 +0,0 @@
<script>
import SvgIcon from '@jamescoyle/vue-icon'
export default {
name: "MobileLink",
components: {
SvgIcon
},
methods: {
optionSelected() {
this.$emit('optionSelected')
}
},
props: [
"svgPath",
"text",
"to"
]
}
</script>
<template>
<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="svgPath"></svg-icon>
</span>
<span>{{ text }}</span>
</div>
</a>
<div class="relative flex" v-else>
<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 scoped>
.navlink.active-link, .navlink.exact-active-link {
@apply bg-orange-500;
@apply text-white;
@apply hover:bg-orange-600;
@apply hover:text-white;
}
.navlink {
@apply hover:text-orange-300;
@apply active:text-orange-500;
@apply rounded-lg;
@apply h-fit;
@apply align-middle;
@apply transition-all;
@apply ease-in-out;
@apply duration-500;
}
</style>