jointrashposs/components/g/Nav.vue

113 lines
5.2 KiB
Vue
Raw Normal View History

2023-07-08 10:36:02 +02:00
<template>
2023-09-09 08:09:04 +02:00
<div :class="['sticky top-0 z-[9900] transition', { 'backdrop-blur-lg shadow bg-opacity-75': (!disableShadow && scrollPos <= -40), 'bg-white dark:bg-gray-950': (disableShadow || scrollPos <= -40)}, (slim ? 'h-16 border-b border-slate-300' : 'h-16 lg:h-20')]">
<nav :class="['container mx-auto max-w-screen-xl grid items-center grid-cols-2 md:grid-cols-4 lg:grid-cols-6 p-4 h-full transition-[height]']">
2023-07-09 20:09:50 +02:00
<div class="">
<GNuxtLink :to="localePath('/')" class="flex items-center space-x-2 hover:opacity-80">
<MiIcon class="h-8 w-8" />
<div class="font-title font-bold text-lg">{{ $t('_seo.siteName') }}</div>
2023-07-09 11:58:53 +02:00
</GNuxtLink>
2023-07-09 20:09:50 +02:00
</div>
<ul class="hidden lg:col-span-4 lg:space-x-8 xl:space-x-10 lg:flex justify-center">
<li v-for="item in NavData.center">
2023-09-09 08:09:04 +02:00
<GNuxtLink :to="localePath(item.to)" :class="['rounded-full px-4 py-1.5 hover:bg-slate-300 dark:hover:bg-slate-800 hover:bg-opacity-50 bg-blend-multiply', { 'bg-slate-200 dark:bg-slate-800 font-bold': currentPath.replace(/\/$/, '').includes(localePath(item.to).replace(/\/$/, '')) }]">
2023-07-09 11:58:53 +02:00
<component v-if="item.icon" :is="item.icon" class="h-5 w-5" />
<template v-else>
{{ $t(item.i18n) }}
</template>
</GNuxtLink>
</li>
</ul>
2023-07-09 20:09:50 +02:00
<div>
<ul class="hidden lg:col-span-4 lg:space-x-4 lg:flex justify-center">
<li>
2023-07-15 10:34:06 +02:00
<button :class="['hover:opacity-80 transition-colors', { 'text-white': (landing && scrollPos >= -40) }]" @click="rotateColorMode()" aria-label="Change Color Mode">
2023-07-09 20:09:50 +02:00
<ClientOnly>
<SunIcon class="h-5 w-5" v-if="colorMode.preference === 'light'" />
<MoonIcon class="h-5 w-5" v-else-if="colorMode.preference === 'dark'" />
<DisplayIcon class="h-5 w-5" v-else />
2023-07-09 20:09:50 +02:00
</ClientOnly>
</button>
</li>
2023-07-16 10:53:42 +02:00
<li class="relative group">
<a class="hover:opacity-80" href="#"><I18nIcon :class="['h-5 w-5 transition-colors', { 'text-white': (landing && scrollPos >= -40) }]" /><span class="sr-only">{{ $t('_nav.switchLang') }}</span></a>
<div class="absolute top-6 right-0 hidden group-hover:block z-[9955]">
2023-07-09 20:09:50 +02:00
<ul class="px-4 py-2 bg-slate-50 dark:bg-slate-800 rounded-lg shadow-lg space-y-1">
<li v-for="locale in locales">
<GNuxtLink :to="switchLocalePath(locale.code)" :class="['hover:text-accent-600 py-1', {'text-accent-600 font-bold': currentLocale === locale.code}]">
{{ locale.name }}
</GNuxtLink>
</li>
</ul>
</div>
</li>
<li class="border-l"></li>
2023-07-15 10:34:06 +02:00
<li v-for="item in NavData.right" :class="['transition-colors', { 'text-white': (landing && scrollPos >= -40) }]">
2023-07-09 20:09:50 +02:00
<GNuxtLink :to="item.to" class="hover:opacity-80">
<component v-if="item.icon" :is="item.icon" class="h-5 w-5" />
<template v-else>
{{ $t(item.i18n) }}
</template>
</GNuxtLink>
</li>
</ul>
</div>
</nav>
</div>
2023-07-08 10:36:02 +02:00
</template>
2023-07-11 19:19:32 +02:00
<script setup lang="ts">
2023-07-09 11:58:53 +02:00
import MiIcon from '@/assets/svg/misskey_mi_bi.svg';
import I18nIcon from 'bi/translate.svg';
import SunIcon from 'bi/sun.svg';
import MoonIcon from 'bi/moon-stars.svg';
import DisplayIcon from 'bi/display.svg';
2023-07-09 11:58:53 +02:00
import NavData from '@/assets/data/nav';
2023-07-08 10:36:02 +02:00
2023-07-11 19:19:32 +02:00
const props = withDefaults(defineProps<{
disableShadow?: boolean;
slim?: boolean;
2023-07-15 10:34:06 +02:00
landing?: boolean;
2023-07-11 19:19:32 +02:00
}>(), {
disableShadow: false,
slim: false,
2023-07-15 10:34:06 +02:00
landing: false,
2023-07-11 19:19:32 +02:00
});
2023-07-09 20:09:50 +02:00
const { locales, locale: currentLocale } = useI18n();
2023-07-09 11:58:53 +02:00
const { path } = useRoute();
2023-09-09 08:09:04 +02:00
const { afterEach } = useRouter();
const currentPath = ref(path);
afterEach((to) => {
currentPath.value = to.path;
})
2023-07-09 11:58:53 +02:00
const switchLocalePath = useSwitchLocalePath();
const localePath = useLocalePath();
2023-07-09 20:09:50 +02:00
const colorMode = useColorMode();
function rotateColorMode() {
const values = ['system', 'light', 'dark'];
const index = values.indexOf(colorMode.preference);
const next = (index + 1) % values.length;
colorMode.preference = values[next];
}
const scrollPos = ref(0);
2023-07-10 05:55:57 +02:00
async function updatePos() {
scrollPos.value = document.body.getBoundingClientRect().y;
}
2023-07-11 19:19:32 +02:00
if (process.client && !props.disableShadow) {
2023-07-10 05:55:57 +02:00
window.addEventListener('scroll', updatePos);
window.addEventListener('resize', updatePos);
2023-07-09 20:09:50 +02:00
}
onUnmounted(() => {
2023-07-11 19:19:32 +02:00
if (process.client && !props.disableShadow) {
2023-07-10 05:55:57 +02:00
window.removeEventListener('scroll', updatePos);
window.removeEventListener('resize', updatePos);
2023-07-09 20:09:50 +02:00
}
});
2023-07-09 11:58:53 +02:00
</script>