diff options
author | 2022-04-15 12:21:09 +0200 | |
---|---|---|
committer | 2022-04-15 12:21:09 +0200 | |
commit | 1e67fa6e0bede8c055d9e4cb9bf7f97423bc9bdf (patch) | |
tree | 5b7874b3258b6872966b8453839cb72317c494e2 | |
parent | f872972e69aeb4fde4c17f0c122ca3fd4aa1c56c (diff) | |
download | it-tools-1e67fa6e0bede8c055d9e4cb9bf7f97423bc9bdf.tar.gz it-tools-1e67fa6e0bede8c055d9e4cb9bf7f97423bc9bdf.tar.zst it-tools-1e67fa6e0bede8c055d9e4cb9bf7f97423bc9bdf.zip |
feat: mobile friendly menu
-rw-r--r-- | src/components/MenuLayout.vue | 47 | ||||
-rw-r--r-- | src/layouts/base.layout.vue | 97 | ||||
-rw-r--r-- | src/layouts/tool.layout.vue | 6 | ||||
-rw-r--r-- | src/stores/style.store.ts | 6 |
4 files changed, 121 insertions, 35 deletions
diff --git a/src/components/MenuLayout.vue b/src/components/MenuLayout.vue new file mode 100644 index 0000000..48150c1 --- /dev/null +++ b/src/components/MenuLayout.vue @@ -0,0 +1,47 @@ +<template> + <n-layout has-sider> + <n-layout-sider bordered collapse-mode="width" :collapsed-width="0" :width="240" :collapsed="isMenuCollapsed" + @collapse="isMenuCollapsed = true" @expand="isMenuCollapsed = false" :show-trigger="false" + :native-scrollbar="false" :position="siderPosition"> + <slot name="sider" /> + </n-layout-sider> + <n-layout class="content"> + <slot name="content" /> + <div class="overlay" v-show="isSmallScreen && !isMenuCollapsed" @click="isMenuCollapsed = true" /> + </n-layout> + </n-layout> +</template> + +<script setup lang="ts"> +import { useStyleStore } from '@/stores/style.store'; +import { toRefs } from 'vue'; +import { computed } from 'vue'; + +const styleStore = useStyleStore() +const { isMenuCollapsed, isSmallScreen } = toRefs(styleStore) +const siderPosition = computed(() => isSmallScreen.value ? 'absolute' : 'static') +</script> + +<style lang="less" scoped> +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #00000080; + cursor: pointer; +} + +.content { + + // background-color: #f1f5f9; + ::v-deep(.n-layout-scroll-container) { + padding: 26px; + } +} + +.n-layout { + height: 100vh; +} +</style>
\ No newline at end of file diff --git a/src/layouts/base.layout.vue b/src/layouts/base.layout.vue index 1d1480c..d20e4a0 100644 --- a/src/layouts/base.layout.vue +++ b/src/layouts/base.layout.vue @@ -2,15 +2,15 @@ import { NIcon } from 'naive-ui'; import { h, ref, type Component } from 'vue'; import { RouterLink, useRoute } from 'vue-router'; -import { Heart, BrandGithub, BrandTwitter, Moon, Sun } from '@vicons/tabler' +import { Heart, BrandGithub, BrandTwitter, Moon, Sun, Menu2, Home2 } from '@vicons/tabler' import { toolsByCategory } from '@/tools'; import SearchBar from '../components/SearchBar.vue'; import { useStyleStore } from '@/stores/style.store'; import HeroGradient from '../assets/hero-gradient.svg?component' import { useThemeVars } from 'naive-ui' +import MenuLayout from '../components/MenuLayout.vue' const themeVars = useThemeVars() -const collapsed = ref(false) const activeKey = ref(null) const route = useRoute() const styleStore = useStyleStore() @@ -32,10 +32,9 @@ const m = toolsByCategory.map(category => ({ </script> <template> - <n-layout has-sider> - <n-layout-sider bordered collapse-mode="width" :collapsed-width="64" :width="260" :collapsed="collapsed" - @collapse="collapsed = true" @expand="collapsed = false" :show-trigger="false" :native-scrollbar="false"> + <menu-layout class="menu-layout" :class="{ isSmallScreen: styleStore.isSmallScreen }"> + <template v-slot:sider> <router-link to="/" class="hero-wrapper"> <hero-gradient class="gradient" /> <div class="text-wrapper"> @@ -45,34 +44,72 @@ const m = toolsByCategory.map(category => ({ </div> </router-link> - <n-menu :value="route.name" class="menu" :collapsed="collapsed" :collapsed-width="64" - :collapsed-icon-size="22" :options="m" v-model:value="activeKey" /> + <div class="sider-content"> + <n-space v-if="styleStore.isSmallScreen" justify="center"> + <n-button size="large" circle quaternary tag="a" href="https://github.com/CorentinTh/it-tools" + rel="noopener" target="_blank"> + <n-icon size="25" :component="BrandGithub" /> + </n-button> + <n-button size="large" circle quaternary tag="a" href="https://twitter.com/cthmsst" rel="noopener" + target="_blank"> + <n-icon size="25" :component="BrandTwitter" /> + </n-button> + <n-button size="large" circle quaternary @click="styleStore.isDarkTheme = !styleStore.isDarkTheme"> + <n-icon size="25" v-if="styleStore.isDarkTheme" :component="Sun" /> + <n-icon size="25" v-else :component="Moon" /> + </n-button> + </n-space> + + <n-menu :value="route.name" class="menu" :collapsed-width="64" :collapsed-icon-size="22" :options="m" + v-model:value="activeKey" :indent="20" /> + + </div> + + + </template> + + <template v-slot:content> + <div class="navigation"> + <n-button :size="styleStore.isSmallScreen ? 'medium' : 'large'" circle quaternary + @click="styleStore.isMenuCollapsed = !styleStore.isMenuCollapsed"> + <n-icon size="25" :component="Menu2" /> + </n-button> + + <router-link to="/" #="{ navigate, href }" custom> + <n-button tag="a" :href="href" @click="navigate" + :size="styleStore.isSmallScreen ? 'medium' : 'large'" circle quaternary> + <n-icon size="25" :component="Home2" /> + </n-button> + </router-link> - </n-layout-sider> - <n-layout class="content"> - <div class="bar-wrapper"> <search-bar /> + + <n-button type="primary" tag="a" href="https://github.com/sponsors/CorentinTh" rel="noopener" target="_blank"> - <n-icon :component="Heart" /> + <n-icon :component="Heart" style="margin-right: 5px;" v-if="!styleStore.isSmallScreen" /> Sponsor </n-button> <n-button size="large" circle quaternary tag="a" href="https://github.com/CorentinTh/it-tools" - rel="noopener" target="_blank"> + rel="noopener" target="_blank" v-if="!styleStore.isSmallScreen"> <n-icon size="25" :component="BrandGithub" /> </n-button> <n-button size="large" circle quaternary tag="a" href="https://twitter.com/cthmsst" rel="noopener" - target="_blank"> + target="_blank" v-if="!styleStore.isSmallScreen"> <n-icon size="25" :component="BrandTwitter" /> </n-button> - <n-button size="large" circle quaternary @click="styleStore.isDarkTheme = !styleStore.isDarkTheme"> + <n-button size="large" circle quaternary @click="styleStore.isDarkTheme = !styleStore.isDarkTheme" + v-if="!styleStore.isSmallScreen"> <n-icon size="25" v-if="styleStore.isDarkTheme" :component="Sun" /> <n-icon size="25" v-else :component="Moon" /> </n-button> + </div> <slot /> - </n-layout> - </n-layout> + + </template> + + </menu-layout> </template> <style lang="less" scoped> @@ -87,7 +124,7 @@ const m = toolsByCategory.map(category => ({ // background-size: @size @size; // } -.n-menu { +.sider-content { padding-top: 160px; padding-bottom: 200px; } @@ -99,9 +136,10 @@ const m = toolsByCategory.map(category => ({ left: 0; width: 100%; z-index: 10; + overflow: hidden; .gradient { - margin-top: -80px; + margin-top: -65px; } .text-wrapper { @@ -131,29 +169,24 @@ const m = toolsByCategory.map(category => ({ } } -.bar-wrapper { +.navigation { display: flex; align-items: center; justify-content: center; + flex-direction: row; &>*:not(:first-child) { - margin-left: 15px; - } + margin-left: 10px; - .search-bar { - flex-grow: 1; + .isSmallScreen & { + margin-left: 5px; + } } -} -.content { - // background-color: #f1f5f9; - ::v-deep(.n-layout-scroll-container) { - padding: 26px; + .search-bar { + // width: 100%; + flex-grow: 1; } } - -.n-layout { - height: 100vh; -} </style>
\ No newline at end of file diff --git a/src/layouts/tool.layout.vue b/src/layouts/tool.layout.vue index 01c8cc1..2705a50 100644 --- a/src/layouts/tool.layout.vue +++ b/src/layouts/tool.layout.vue @@ -45,19 +45,23 @@ useHead(head) .tool-header { padding: 40px 0; + .n-h1 { opacity: 0.9; font-size: 40px; font-weight: 400; margin: 0; + line-height: 1; } + .separator { width: 200px; height: 2px; background: rgb(161, 161, 161); - margin-bottom: 10px; + margin: 10px 0; } + .description { margin: 0; diff --git a/src/stores/style.store.ts b/src/stores/style.store.ts index 6026d8b..79c372c 100644 --- a/src/stores/style.store.ts +++ b/src/stores/style.store.ts @@ -1,9 +1,11 @@ -import { useStorage } from '@vueuse/core'; +import { useMediaQuery, useStorage } from '@vueuse/core'; import { defineStore } from 'pinia'; import type { Ref } from 'vue'; export const useStyleStore = defineStore('style', { state: () => ({ - isDarkTheme: useStorage('useDarkTheme', false) as Ref<boolean>, + isDarkTheme: useStorage('isDarkTheme', true) as Ref<boolean>, + isMenuCollapsed: useStorage('isMenuCollapsed', false) as Ref<boolean>, + isSmallScreen: useMediaQuery('(max-width: 700px)'), }), }); |