salix-front/src/components/LeftMenu.vue

250 lines
8.4 KiB
Vue
Raw Normal View History

2022-03-28 07:06:36 +00:00
<script setup>
2022-11-29 13:45:48 +00:00
import axios from 'axios';
2024-02-27 13:55:45 +00:00
import { onMounted, ref, reactive } from 'vue';
import { useI18n } from 'vue-i18n';
2023-04-11 11:31:03 +00:00
import { QSeparator, useQuasar } from 'quasar';
2022-11-24 06:21:45 +00:00
import { useRoute } from 'vue-router';
2022-11-29 06:10:04 +00:00
import { useNavigationStore } from 'src/stores/useNavigationStore';
2022-11-29 13:45:48 +00:00
import { toLowerCamel } from 'src/filters';
2022-11-21 16:33:21 +00:00
import routes from 'src/router/modules';
2022-11-29 13:45:48 +00:00
import LeftMenuItem from './LeftMenuItem.vue';
import LeftMenuItemGroup from './LeftMenuItemGroup.vue';
const { t } = useI18n();
2022-11-24 06:21:45 +00:00
const route = useRoute();
2022-11-24 13:54:38 +00:00
const quasar = useQuasar();
2022-11-29 06:10:04 +00:00
const navigation = useNavigationStore();
2022-11-24 06:21:45 +00:00
const props = defineProps({
2022-11-21 16:33:21 +00:00
source: {
type: String,
default: 'main',
},
});
2024-02-27 13:55:45 +00:00
const expansionItemElements = reactive({});
2022-12-19 13:32:55 +00:00
onMounted(async () => {
await navigation.fetchPinned();
getRoutes();
2022-11-29 13:45:48 +00:00
});
2022-11-24 06:21:45 +00:00
function findMatches(search, item) {
const matches = [];
function findRoute(search, item) {
for (const child of item.children) {
2023-08-14 11:52:25 +00:00
if (search?.indexOf(child.name) > -1) {
2022-11-24 06:21:45 +00:00
matches.push(child);
} else if (child.children) {
findRoute(search, child);
}
}
}
findRoute(search, item);
return matches;
}
function addChildren(module, route, parent) {
if (route.menus) {
const mainMenus = route.menus[props.source];
const matches = findMatches(mainMenus, route);
2022-12-13 11:21:12 +00:00
2022-11-24 06:21:45 +00:00
for (const child of matches) {
2022-11-29 13:45:48 +00:00
navigation.addMenuItem(module, child, parent);
2022-11-24 06:21:45 +00:00
}
}
}
2022-12-13 11:21:12 +00:00
2022-11-24 06:21:45 +00:00
const items = ref([]);
2022-11-29 13:45:48 +00:00
function getRoutes() {
if (props.source === 'main') {
const modules = Object.assign([], navigation.getModules().value);
2022-12-13 11:21:12 +00:00
2022-11-29 13:45:48 +00:00
for (const item of modules) {
2023-04-11 11:31:03 +00:00
const moduleDef = routes.find(
(route) => toLowerCamel(route.name) === item.module
);
2022-11-29 13:45:48 +00:00
item.children = [];
2022-11-29 06:10:04 +00:00
2022-12-13 11:21:12 +00:00
if (!moduleDef) continue;
2022-11-29 13:45:48 +00:00
addChildren(item.module, moduleDef, item.children);
}
2022-11-24 06:21:45 +00:00
2022-11-29 13:45:48 +00:00
items.value = modules;
2022-11-21 16:33:21 +00:00
}
2022-11-24 06:21:45 +00:00
2022-11-29 13:45:48 +00:00
if (props.source === 'card') {
const currentRoute = route.matched[1];
const currentModule = toLowerCamel(currentRoute.name);
2023-04-11 11:31:03 +00:00
const moduleDef = routes.find(
(route) => toLowerCamel(route.name) === currentModule
);
2022-11-21 16:33:21 +00:00
2022-12-13 11:21:12 +00:00
if (!moduleDef) return;
2022-11-29 13:45:48 +00:00
addChildren(currentModule, moduleDef, items.value);
}
}
2022-11-24 06:21:45 +00:00
2022-11-29 13:45:48 +00:00
async function togglePinned(item, event) {
2022-11-29 06:10:04 +00:00
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
2022-11-29 13:45:48 +00:00
const data = { moduleName: item.module };
const response = await axios.post('StarredModules/toggleStarredModule', data);
item.isPinned = false;
if (response.data && response.data.id) {
item.isPinned = true;
}
navigation.togglePinned(item.module);
2022-11-21 16:33:21 +00:00
2022-11-24 13:54:38 +00:00
quasar.notify({
message: t('globals.dataSaved'),
type: 'positive',
});
2023-08-10 08:52:34 +00:00
}
2024-02-27 13:55:45 +00:00
const handleItemExpansion = (itemName) => {
expansionItemElements[itemName].scrollToLastElement();
};
</script>
<template>
2023-08-09 08:09:37 +00:00
<QList padding class="column-max-width">
2022-11-29 13:45:48 +00:00
<template v-if="$props.source === 'main'">
2023-08-18 12:13:49 +00:00
<template v-if="$route?.matched[1]?.name === 'Dashboard'">
2023-08-09 11:29:00 +00:00
<QItem class="header">
<QItemSection avatar>
<QIcon name="view_module" />
</QItemSection>
<QItemSection> {{ t('globals.modules') }}</QItemSection>
</QItem>
<QSeparator />
2023-08-09 11:29:00 +00:00
<template v-for="item in items" :key="item.name">
<template v-if="item.children">
<LeftMenuItem :item="item" group="modules">
<template #side>
<QBtn
v-if="item.isPinned === true"
@click="togglePinned(item, $event)"
icon="remove_circle"
size="xs"
flat
round
>
<QTooltip>
{{ t('components.leftMenu.removeFromPinned') }}
</QTooltip>
</QBtn>
<QBtn
v-if="item.isPinned === false"
@click="togglePinned(item, $event)"
icon="push_pin"
size="xs"
flat
round
>
<QTooltip>
{{ t('components.leftMenu.addToPinned') }}
</QTooltip>
</QBtn>
</template>
</LeftMenuItem>
</template>
2022-11-29 13:45:48 +00:00
</template>
2022-11-24 06:21:45 +00:00
</template>
2023-08-09 11:29:00 +00:00
<template v-for="item in items" :key="item.name">
2023-08-18 12:13:49 +00:00
<template v-if="item.name === $route?.matched[1]?.name">
2023-08-09 11:29:00 +00:00
<QItem class="header">
<QItemSection avatar v-if="item.icon">
<QIcon :name="item.icon" />
</QItemSection>
<QItemSection avatar v-if="!item.icon">
<QIcon name="disabled_by_default" />
</QItemSection>
<QItemSection>{{ t(item.title) }}</QItemSection>
<QItemSection side>
<slot name="side" :item="item" />
</QItemSection>
</QItem>
<QSeparator />
2022-11-24 13:54:38 +00:00
<template v-if="item.children">
2023-04-11 11:31:03 +00:00
<LeftMenuItemGroup :item="item" group="modules">
2022-11-29 13:45:48 +00:00
<template #side>
2023-04-11 11:31:03 +00:00
<QBtn
2022-11-29 13:45:48 +00:00
v-if="item.isPinned === true"
@click="togglePinned(item, $event)"
2023-05-09 12:05:36 +00:00
icon="remove_circle"
2022-11-29 13:45:48 +00:00
size="xs"
flat
round
>
2023-04-11 11:31:03 +00:00
<QTooltip>
{{ t('components.leftMenu.removeFromPinned') }}
</QTooltip>
</QBtn>
<QBtn
2022-11-29 13:45:48 +00:00
v-if="item.isPinned === false"
@click="togglePinned(item, $event)"
2023-05-09 12:05:36 +00:00
icon="push_pin"
2022-11-29 13:45:48 +00:00
size="xs"
flat
round
>
2023-04-11 11:31:03 +00:00
<QTooltip>
{{ t('components.leftMenu.addToPinned') }}
</QTooltip>
</QBtn>
2022-11-24 13:54:38 +00:00
</template>
2023-04-11 11:31:03 +00:00
</LeftMenuItemGroup>
2022-11-24 13:54:38 +00:00
</template>
</template>
</template>
2022-11-29 13:45:48 +00:00
</template>
<template v-if="$props.source === 'card'">
<template v-for="item in items" :key="item.name">
2023-04-11 11:31:03 +00:00
<LeftMenuItem v-if="!item.children" :item="item" />
2024-01-27 15:08:56 +00:00
<QList v-else>
<QExpansionItem
v-ripple
clickable
:icon="item.icon"
:label="t(item.title)"
2024-01-27 15:14:50 +00:00
:content-inset-level="0.5"
2024-02-27 13:55:45 +00:00
@after-show="handleItemExpansion(item.name)"
2024-01-27 15:08:56 +00:00
>
2024-02-27 13:55:45 +00:00
<LeftMenuItemGroup
:ref="(el) => (expansionItemElements[item.name] = el)"
:item="item"
/>
2024-01-27 15:08:56 +00:00
</QExpansionItem>
</QList>
2022-11-29 13:45:48 +00:00
</template>
</template>
2023-04-11 11:31:03 +00:00
</QList>
</template>
2023-08-10 08:52:34 +00:00
<style scoped>
2023-05-11 06:54:51 +00:00
.pinned .q-btn {
2022-11-29 13:45:48 +00:00
visibility: hidden;
}
2023-05-11 06:54:51 +00:00
.pinned:hover .q-btn {
2022-11-29 13:45:48 +00:00
visibility: visible;
}
2023-08-09 08:09:37 +00:00
.column-max-width {
max-width: 256px;
}
2023-08-09 11:29:00 +00:00
.header {
color: var(--vn-label-color);
2023-08-09 11:29:00 +00:00
}
2022-11-29 13:45:48 +00:00
</style>