Files
leim-maps/src/components/maps/overlay/SearchMapSwitch.vue
2025-04-03 16:47:33 +02:00

216 lines
8.3 KiB
Vue

<script lang="ts" setup>
import { computed, onUpdated, ref, watch } from 'vue';
import { useElementHover, useFocus } from '@vueuse/core'
import { PopoverArrow, PopoverContent, PopoverRoot, PopoverTrigger } from 'radix-vue'
import { useStore } from '@nanostores/vue';
import { currentLang } from '@/i18n/store';
import { t } from '@/i18n/store';
const $currentLang = useStore(currentLang);
const navModel = ref(false);
const wrapper = ref<HTMLDivElement | null>(null)
const buttonRef = ref<HTMLButtonElement | null>(null)
const wrapperHovered = useElementHover(wrapper, { delayEnter: 100, delayLeave: 500 })
const { focused: buttonFocused } = useFocus(buttonRef)
const isNavOpened = computed(() => navModel.value || wrapperHovered.value)
watch([wrapperHovered, buttonFocused], (value) => {
// Check if all values from array are false
if (!value.some(Boolean)) {
navModel.value = false
}
})
let url: URL | null = null;
onUpdated(() => {
url = new URL(window.location.href)
})
interface Menu {
name: string,
items: MenuItem[]
}
interface MenuItem {
name: string,
img: string,
url: string,
newItem?: boolean
}
const menus: Menu[] = [
{
name: t('continents'),
items: [
{
name: 'Aldys',
img: '/images/aldys-cover.png',
url: `/${$currentLang.value}/`
},
{
name: 'Bamast',
img: '/images/bamast-cover.png',
url: `/${$currentLang.value}/bamast`
}
]
},
{
name: t('cities'),
items: [
{
name: 'Borélis',
img: '/images/aldys-borelis-cover.png',
url: `/${$currentLang.value}/aldys/borelis`
},
{
name: 'Cantane',
img: '/images/aldys-cantane-cover.png',
url: `/${$currentLang.value}/aldys/cantane`
},
]
},
{
name: t('others'),
items: [
{
name: 'Mines Blanches',
img: '/images/aldys-cantane-mines-blanches-cover.png',
url: `/${$currentLang.value}/aldys/cantane/mines-blanches`,
newItem: true
},
]
}
]
</script>
<template>
<div class="wrapper" ref="wrapper">
<PopoverRoot :open="isNavOpened" @update:open="() => navModel = true">
<PopoverTrigger as-child>
<button ref="buttonRef" class="btn-round" :title="t('nav.map.aria-label')" :class="{ 'active': isNavOpened }">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M228.92,49.69a8,8,0,0,0-6.86-1.45L160.93,63.52,99.58,32.84a8,8,0,0,0-5.52-.6l-64,16A8,8,0,0,0,24,56V200a8,8,0,0,0,9.94,7.76l61.13-15.28,61.35,30.68A8.15,8.15,0,0,0,160,224a8,8,0,0,0,1.94-.24l64-16A8,8,0,0,0,232,200V56A8,8,0,0,0,228.92,49.69ZM96,176a8,8,0,0,0-1.94.24L40,189.75V62.25L95.07,48.48l.93.46Zm120,17.75-55.07,13.77-.93-.46V80a8,8,0,0,0,1.94-.23L216,66.25Z"/></svg>
</button>
</PopoverTrigger>
<PopoverContent side="bottom" :side-offset="6" :collision-padding="16" class="card" style="z-index: 100;">
<PopoverArrow class="card-arrow" />
<template v-for="menu in menus">
<div class="menu-title">
{{ menu.name }}
</div>
<menu class="map-menu">
<li v-for="item in menu.items" :key="item.name">
<a
:href="item.url"
:class="{ 'active': url?.pathname === item.url }"
:tabindex="url?.pathname === item.url ? -1 : 0"
:title="item.newItem ? 'Nouveau' : ''"
>
<figure>
<div class="img-wrapper">
<img :src="item.img" alt="" width="40" height="40" loading="eager">
<svg v-if="item.newItem" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 256 256">
<path class="fill" d="M112.1,255c-3.6,0-7.2-.6-10.7-1.9-8.5-3.1-15.2-9.8-18.3-18.3l-16.7-45.1-45.1-16.6c-16-5.9-24.2-23.7-18.3-39.7,3.1-8.5,9.8-15.2,18.3-18.3l45.1-16.7,16.6-45.1c4.5-12.1,16.1-20.2,29-20.2s7.2.6,10.7,1.9c2.3.8,4.5,1.9,6.5,3.3,1-11.8,10.9-21.1,22.9-21.1h1v-1c0-12.7,10.3-23,23-23s23,10.3,23,23v1h1c12.7,0,23,10.3,23,23s-.7,6.4-1.9,9.2c1-.1,1.9-.2,2.9-.2,10.5,0,19.5,7.1,22.2,16.8,9.7,2.7,16.8,11.6,16.8,22.2s-7.1,19.5-16.8,22.2c-2.7,9.7-11.6,16.8-22.2,16.8s-4.6-.3-6.7-1c3.7,5.2,5.7,11.4,5.7,18,0,12.9-8.1,24.6-20.3,29l-45.1,16.6-16.6,45.1c-4.5,12.1-16.1,20.2-29,20.2ZM202.8,114.9c.4.2.8.3,1.2.5-.9-1.6-1.7-3.4-2.2-5.2-9.7-2.7-16.8-11.6-16.8-22.2s0-2,.2-2.9c-2.8,1.2-5.9,1.9-9.2,1.9-12.7,0-23-10.3-23-23v-1h-1c-2.8,0-5.5-.5-7.9-1.4l13.6,36.7,45.1,16.6ZM199,64c0,1,0,2-.2,2.9,1-.4,2-.8,3-1.1.3-1,.6-2,1.1-3-1,.1-1.9.2-2.9.2h-1v1Z"/>
<path class="stroke" d="M176,8c4.4,0,8,3.6,8,8v16h16c4.4,0,8,3.6,8,8s-3.6,8-8,8h-16v16c0,4.4-3.6,8-8,8s-8-3.6-8-8v-16h-16c-4.4,0-8-3.6-8-8s3.6-8,8-8h16v-16c0-4.4,3.6-8,8-8M111.9,48c1.8,0,3.7.3,5.5,1,4.4,1.6,7.8,5.1,9.4,9.4l19.1,51.6,51.6,19c6.3,2.3,10.5,8.3,10.4,15,0,6.7-4.1,12.7-10.4,14.9l-51.6,19.1-19,51.6c-2.4,6.4-8.5,10.4-14.9,10.4s-3.7-.3-5.5-1c-4.4-1.6-7.8-5.1-9.4-9.4l-19.1-51.6-51.6-19c-8.3-3-12.5-12.2-9.4-20.4,1.6-4.4,5.1-7.8,9.4-9.4l51.6-19.1,19-51.6c2.4-6.4,8.5-10.4,14.9-10.4M224,64c4.4,0,8,3.6,8,8v8h8c4.4,0,8,3.6,8,8s-3.6,8-8,8h-8v8c0,4.4-3.6,8-8,8s-8-3.6-8-8v-8h-8c-4.4,0-8-3.6-8-8s3.6-8,8-8h8v-8c0-4.4,3.6-8,8-8M176-22c-16.7,0-31,10.9-36,26-8,2.7-14.8,7.9-19.5,14.8-2.8-.5-5.7-.8-8.6-.8h0c-19.2,0-36.5,12.1-43.1,30.1l-14.2,38.7-38.6,14.3c-12.6,4.7-22.6,14.6-27.2,27.2-8.7,23.8,3.5,50.2,27.2,59l38.7,14.2,14.3,38.7c4.7,12.6,14.6,22.5,27.2,27.2,5.1,1.9,10.4,2.8,15.9,2.8,19.2,0,36.5-12.1,43.1-30.1l14.2-38.6,38.5-14.2c18-6.6,30.1-23.8,30.1-43,0-1.6,0-3.1-.2-4.7,8.6-3.3,15.6-9.7,19.9-17.8,12.1-6.4,20.4-19.1,20.4-33.6s-8.3-27.3-20.4-33.6c-4.2-8-11.3-14.4-19.8-17.7-1.4-15.3-11.8-28-25.8-32.7-5-15.1-19.3-26-36-26h0Z"/>
</svg>
</div>
<figcaption>
{{ item.name }}
</figcaption>
</figure>
</a>
</li>
</menu>
</template>
</PopoverContent>
</PopoverRoot>
</div>
</template>
<style lang="scss" scoped>
.wrapper {
pointer-events: all;
@media screen and (width < 900px) {
position: absolute;
}
}
.menu-title {
font-size: .9em;
font-weight: 600;
margin-bottom: .25rem;
margin-left: .25rem;
}
.map-menu {
margin-top: .25rem;
margin-bottom: .5rem;
margin-inline: .25rem;
display: flex;
gap: 1rem;
a {
&:hover,
&:focus-visible {
figure img {
outline-color: var(--blue-500);
}
}
&.active {
pointer-events: none;
figure img {
border-width: .15rem;
border-color: var(--blue-300);
filter: grayscale(50%);
}
}
}
figure {
position: relative;
display: grid;
justify-items: center;
gap: .25rem;
.img-wrapper {
position: relative;
img {
display: block;
border-radius: .3rem;
border: .1rem solid var(--white);
outline: .15rem solid transparent;
}
svg {
position: absolute;
top: -0.3rem;
right: -0.3rem;
width: 1.15em;
z-index: 10;
pointer-events: none;
.fill { fill: var(--orange-500); }
.stroke { fill: var(--white); }
}
}
figcaption {
font-size: .75em;
text-align: center;
color: var(--slate-500);
}
}
}
</style>