186 lines
5.4 KiB
Svelte
186 lines
5.4 KiB
Svelte
<script lang="ts">
|
|
import MenuHome from '@assets/img/menu-home.webp';
|
|
import MenuSignup from '@assets/img/menu-signup.webp';
|
|
import MenuRules from '@assets/img/menu-rules.webp';
|
|
import MenuFaq from '@assets/img/menu-faq.webp';
|
|
import MenuFeedback from '@assets/img/menu-feedback.webp';
|
|
import MenuAdmins from '@assets/img/menu-admins.webp';
|
|
import MenuButton from '@assets/img/menu-button.webp';
|
|
import MenuInventoryBar from '@assets/img/menu-inventory-bar.webp';
|
|
import MenuSelectedFrame from '@assets/img/menu-selected-frame.webp';
|
|
import { isBrowser } from '@antfu/utils';
|
|
import { navigate } from 'astro:transitions/client';
|
|
import { onMount } from 'svelte';
|
|
|
|
// html bindings
|
|
let navElem: HTMLDivElement;
|
|
|
|
// states
|
|
let navPaths = $state([
|
|
{
|
|
name: 'Startseite',
|
|
sprite: MenuHome.src,
|
|
href: '',
|
|
active: false
|
|
},
|
|
{
|
|
name: 'Registrieren',
|
|
sprite: MenuSignup.src,
|
|
href: 'signup',
|
|
active: false
|
|
},
|
|
{
|
|
name: 'Regeln',
|
|
sprite: MenuRules.src,
|
|
href: 'rules',
|
|
active: false
|
|
},
|
|
{
|
|
name: 'FAQ',
|
|
sprite: MenuFaq.src,
|
|
href: 'faq',
|
|
active: false
|
|
},
|
|
{
|
|
name: 'Feedback & Kontakt',
|
|
sprite: MenuFeedback.src,
|
|
href: 'feedback',
|
|
active: false
|
|
},
|
|
{
|
|
name: 'Admins',
|
|
sprite: MenuAdmins.src,
|
|
href: 'admins',
|
|
active: false
|
|
}
|
|
]);
|
|
|
|
let showMenuPermanent = $state(isBrowser ? localStorage.getItem('showMenuPermanent') === 'true' : false);
|
|
let isTouch = $state(false);
|
|
let isOpen = $state(false);
|
|
let windowHeight = $state(0);
|
|
|
|
// lifecycle
|
|
$effect(() => {
|
|
localStorage.setItem('showMenuPermanent', `${showMenuPermanent}`);
|
|
});
|
|
|
|
onMount(() => {
|
|
updateActiveNavPath();
|
|
new MutationObserver(updateActiveNavPath).observe(document.head, { childList: true });
|
|
});
|
|
|
|
// functions
|
|
function updateActiveNavPath() {
|
|
for (let i = 0; i < navPaths.length; i++) {
|
|
navPaths[i].active = new URL(document.baseURI).pathname + navPaths[i].href === window.location.pathname;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:window bind:innerHeight={windowHeight} />
|
|
<svelte:body
|
|
ontouchend={(e) => {
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
if (isTouch && !navElem.contains(e.target)) showMenuPermanent = false;
|
|
}}
|
|
/>
|
|
|
|
<div
|
|
class="fixed bottom-4 right-4 sm:left-4 sm:right-[initial] group/menu-bar flex flex-col-reverse justify-center items-center z-50 main-menu"
|
|
bind:this={navElem}
|
|
>
|
|
<button
|
|
class={isTouch ? 'btn btn-square relative w-16 h-16' : 'btn btn-square group/menu-button relative w-16 h-16'}
|
|
onclick={() => {
|
|
if (!isTouch) {
|
|
let activePath = navPaths.find((path) => path.active);
|
|
if (activePath !== undefined) {
|
|
navigate(activePath.href);
|
|
}
|
|
showMenuPermanent = !showMenuPermanent;
|
|
}
|
|
}}
|
|
ontouchend={() => {
|
|
isTouch = true;
|
|
showMenuPermanent = !showMenuPermanent;
|
|
}}
|
|
>
|
|
<img class="absolute w-full h-full p-1 pixelated" src={MenuButton.src} alt="menu" />
|
|
<img
|
|
class="opacity-0 transition-opacity delay-50 group-hover/menu-button:opacity-100 absolute w-full h-full p-[3px] pixelated"
|
|
class:opacity-100={isOpen || (isTouch && showMenuPermanent)}
|
|
src={MenuSelectedFrame.src}
|
|
alt="menu hover"
|
|
/>
|
|
</button>
|
|
<div
|
|
class:hidden={!(isOpen || showMenuPermanent)}
|
|
class={isTouch ? 'pb-3' : 'group-hover/menu-bar:block pb-3'}
|
|
onmouseenter={() => (isOpen = true)}
|
|
onmouseleave={() => (isOpen = false)}
|
|
>
|
|
<ul class="bg-base-200 rounded">
|
|
{#each navPaths as navPath, i (navPath.href)}
|
|
<li
|
|
class="flex justify-center tooltip"
|
|
class:tooltip-left={windowHeight > 450}
|
|
class:sm:tooltip-right={windowHeight > 450}
|
|
class:tooltip-top={windowHeight <= 450}
|
|
class:tooltip-open={isTouch || windowHeight <= 450}
|
|
data-tip={navPath.name}
|
|
>
|
|
<a
|
|
class="btn btn-square border-none group/menu-item relative w-[3.5rem] h-[3.5rem] flex justify-center items-center"
|
|
href={navPath.href}
|
|
onclick={() => navigate(navPath.href)}
|
|
>
|
|
<div
|
|
style="background-image: url({MenuInventoryBar.src}); background-position: -{i * 3.5}rem 0;"
|
|
class="block w-full h-full bg-no-repeat bg-horizontal-sprite pixelated"
|
|
></div>
|
|
<div class="absolute flex justify-center items-center w-full h-full">
|
|
<img class="w-1/2 h-1/2 pixelated" src={navPath.sprite} alt={navPath.name} />
|
|
</div>
|
|
<img
|
|
class="transition-opacity delay-50 group-hover/menu-item:opacity-100 absolute w-full h-full pixelated scale-110 z-10"
|
|
class:opacity-0={!navPath.active}
|
|
src={MenuSelectedFrame.src}
|
|
alt="menu hover"
|
|
/>
|
|
</a>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
@media (max-height: 450px) {
|
|
.main-menu {
|
|
flex-direction: row;
|
|
}
|
|
.main-menu > div {
|
|
padding: 0.25rem 0 0 0.5rem;
|
|
}
|
|
.main-menu li {
|
|
display: inline-block;
|
|
|
|
&::before {
|
|
transform-origin: 0;
|
|
transform: rotate(-90deg);
|
|
margin-bottom: -0.5rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pixelated {
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
.bg-horizontal-sprite {
|
|
background-size: auto 100%;
|
|
}
|
|
</style>
|