164 lines
4.3 KiB
Vue
164 lines
4.3 KiB
Vue
<template>
|
|
<div class="menu">
|
|
<div class="menu__navigation">
|
|
<div class="menu__navigation-container">
|
|
<div
|
|
class="menu__navigation-item"
|
|
v-for="category in menuStore.categories"
|
|
:class="{ 'menu__navigation-item--active': selectedCategory === category }"
|
|
:key="category.id"
|
|
@click="changeCategory(category)"
|
|
:ref="(el)=>refCategories.push(el as Element)"
|
|
>
|
|
{{ category.title }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="menu__list" ref="refMenuList">
|
|
<TransitionGroup name="menu__list-item--transition">
|
|
<MenuItem
|
|
class="menu__list-item"
|
|
v-for="item in selectedMenuItems"
|
|
:key="Math.random() * (item.id + 1)"
|
|
:item="item"
|
|
></MenuItem>
|
|
</TransitionGroup>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref } from "vue";
|
|
import { category } from "@/types";
|
|
import { useMenuApi } from "@/composables/api";
|
|
import { useMenuStore } from "@/store";
|
|
import MenuItem from "./MenuItem.vue";
|
|
|
|
const menuStore = useMenuStore();
|
|
const menuApi = useMenuApi();
|
|
|
|
const refCategories = ref<Element[]>([]);
|
|
const refMenuList = ref<Element>();
|
|
|
|
init();
|
|
function init() {
|
|
menuStore.categories = menuApi.getCategories();
|
|
menuStore.menuItems = menuApi.getMenuItems();
|
|
}
|
|
|
|
const selectedMenuItems = computed(() =>
|
|
selectedCategory.value == null ? menuStore.menuItems : menuStore.menuItems.filter((x) => x.categoryId === selectedCategory.value?.id)
|
|
);
|
|
const selectedCategory = ref<category | undefined>(undefined);
|
|
|
|
function changeCategory(category: category) {
|
|
if (selectedCategory.value === category) {
|
|
selectedCategory.value = undefined;
|
|
} else {
|
|
selectedCategory.value = category;
|
|
const selectedCategoryElement = refCategories.value[menuStore.categories.indexOf(selectedCategory.value)];
|
|
selectedCategoryElement.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
|
|
}
|
|
setTimeout(() => {
|
|
refMenuList.value?.scroll(0, 0);
|
|
}, 180);
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.menu {
|
|
position: absolute;
|
|
top: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
|
|
&__navigation {
|
|
position: relative;
|
|
flex: 0 1 auto;
|
|
background: color("main-background");
|
|
box-shadow: 0 r(4) r(18) 0 rgba(0, 0, 0, 0.12), 0 r(7) r(10) r(-5) rgba(0, 0, 0, 0.15);
|
|
z-index: 1;
|
|
user-select: none;
|
|
}
|
|
|
|
&__navigation-container {
|
|
display: flex;
|
|
overflow-x: auto;
|
|
padding: 0 r(35);
|
|
|
|
@media (max-width: $mobileWidth) {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
&__navigation-item {
|
|
position: relative;
|
|
padding: r(15);
|
|
font-size: r(24);
|
|
font-weight: 300;
|
|
text-transform: capitalize;
|
|
white-space: nowrap;
|
|
|
|
cursor: pointer;
|
|
|
|
&::after {
|
|
content: "";
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: r(4);
|
|
border-radius: r(2);
|
|
background: color("theme-color");
|
|
opacity: 0;
|
|
z-index: 1;
|
|
transition: opacity 0.18s ease;
|
|
}
|
|
|
|
&--active {
|
|
&::after {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
&__list {
|
|
flex: 1;
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: r(10) 0 r(20) 0;
|
|
overflow: auto;
|
|
}
|
|
|
|
&__list-item {
|
|
flex: 0 0 auto;
|
|
|
|
--transition-duration: 0.18s;
|
|
|
|
&--transition {
|
|
&-enter-active {
|
|
transition: opacity var(--transition-duration) var(--transition-duration) ease;
|
|
}
|
|
&-leave-active {
|
|
transition: opacity var(--transition-duration) ease;
|
|
}
|
|
|
|
&-enter-from,
|
|
&-leave-to {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|