- advanced AsideMenuList.vue, AsideMenuItem.vue
All checks were successful
CI Pipeline / japa-tests (push) Successful in 53s
All checks were successful
CI Pipeline / japa-tests (push) Successful in 53s
- npm updates - load menu in AsideMenu.vue via main.ts store for saving the satus of menu items - extended jappa tests: test also permission on dataset controller code
This commit is contained in:
parent
b6fdfbff41
commit
bf9d25ae3e
12 changed files with 417 additions and 292 deletions
|
@ -1,17 +1,22 @@
|
|||
<script setup>
|
||||
// import { reactive, computed } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
// import { usePage } from '@inertiajs/vue3'
|
||||
// import { usePage } from '@inertiajs/inertia-vue3';
|
||||
import { LayoutService } from '@/Stores/layout';
|
||||
import menu from '@/menu';
|
||||
import { MainService } from '@/Stores/main';
|
||||
// import menu from '@/menu';
|
||||
import AsideMenuLayer from '@/Components/AsideMenuLayer.vue';
|
||||
import OverlayLayer from '@/Components/OverlayLayer.vue';
|
||||
// import OverlayLayer from '@/Components/OverlayLayer.vue';
|
||||
|
||||
// let menu = reactive({});
|
||||
// menu = computed(() => usePage().props.navigation?.menu);
|
||||
|
||||
|
||||
const layoutService = LayoutService();
|
||||
const mainService =MainService();
|
||||
// let menu = reactive({});
|
||||
let menu = computed(() => mainService.menu);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -7,7 +7,7 @@ import { StyleService } from '@/Stores/style';
|
|||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||
import { getButtonColor } from '@/colors.js';
|
||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
import AsideMenuList from '@/Components/AsideMenuList.vue';
|
||||
// import AsideMenuList from '@/Components/AsideMenuList.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import type { User } from '@/Dataset';
|
||||
|
||||
|
@ -16,7 +16,11 @@ const props = defineProps({
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isDropdownList: Boolean,
|
||||
parentItem: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
// isDropdownList: Boolean,
|
||||
});
|
||||
|
||||
const user: ComputedRef<User> = computed(() => {
|
||||
|
@ -25,7 +29,7 @@ const user: ComputedRef<User> = computed(() => {
|
|||
|
||||
const itemRoute = computed(() => (props.item && props.item.route ? stardust.route(props.item.route) : ''));
|
||||
// const isCurrentRoute = computed(() => (props.item && props.item.route ? stardust.isCurrent(props.item.route): false));
|
||||
const itemHref = computed(() => (props.item && props.item.href ? props.item.href : ''));
|
||||
// const itemHref = computed(() => (props.item && props.item.href ? props.item.href : ''));
|
||||
|
||||
const emit = defineEmits(['menu-click']);
|
||||
|
||||
|
@ -33,23 +37,67 @@ const styleService = StyleService();
|
|||
|
||||
const hasColor = computed(() => props.item && props.item.color);
|
||||
|
||||
const isDropdownActive = ref(false);
|
||||
const isDropdownOpen = ref(false);
|
||||
|
||||
const isChildSelected = computed(() => {
|
||||
if (props.item.children && props.item.children.length > 0) {
|
||||
return children.value.some(childItem => stardust.isCurrent(childItem.route));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// const value = computed({
|
||||
// get: () => props.modelValue,
|
||||
// set: (value) => emit('update:modelValue', value),
|
||||
// });
|
||||
|
||||
|
||||
const hasChildren = computed(() => {
|
||||
// props.item.children?.length > 0
|
||||
if (props.item.children && props.item.children.length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const children = computed(() => {
|
||||
return props.item.children || [];
|
||||
});
|
||||
|
||||
const componentClass = computed(() => [
|
||||
props.isDropdownList ? 'py-3 px-6 text-sm font-semibold' : 'py-3 px-6',
|
||||
hasChildren ? 'py-3 px-6 text-sm font-semibold' : 'py-3 px-6',
|
||||
hasColor.value ? getButtonColor(props.item.color, false, true) : styleService.asideMenuItemStyle,
|
||||
]);
|
||||
|
||||
const hasDropdown = computed(() => props.item.children);
|
||||
|
||||
|
||||
// const toggleDropdown = () => {
|
||||
// // emit('menu-click', event, props.item);
|
||||
// // console.log(props.item);
|
||||
// if (hasChildren.value) {
|
||||
// isDropdownOpen.value = !isDropdownOpen.value;
|
||||
// }
|
||||
// // if (props.parentItem?.hasDropdown.value) {
|
||||
// // props.parentItem.isDropdownActive.value = true;
|
||||
// // }
|
||||
// };
|
||||
|
||||
const menuClick = (event) => {
|
||||
emit('menu-click', event, props.item);
|
||||
|
||||
if (hasDropdown.value) {
|
||||
isDropdownActive.value = !isDropdownActive.value;
|
||||
if (hasChildren.value) {
|
||||
// if (isChildSelected.value == false) {
|
||||
// isDropdownOpen.value = !isDropdownOpen.value;
|
||||
props.item.isOpen = !props.item.isOpen;
|
||||
// }
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// const handleChildSelected = () => {
|
||||
// isChildSelected.value = true;
|
||||
// };
|
||||
|
||||
|
||||
const activeInactiveStyle = computed(() => {
|
||||
if (props.item.route && stardust.isCurrent(props.item.route)) {
|
||||
// console.log(props.item.route);
|
||||
|
@ -85,33 +133,55 @@ const hasRoles = computed(() => {
|
|||
<template>
|
||||
<li v-if="hasRoles">
|
||||
<!-- <component :is="itemHref ? 'div' : Link" :href="itemHref ? itemHref : itemRoute" -->
|
||||
<component
|
||||
:is="is"
|
||||
:href="itemRoute ? stardust.route(props.item.route) : props.item.href"
|
||||
class="flex cursor-pointer dark:text-slate-300 dark:hover:text-white"
|
||||
:class="componentClass"
|
||||
@click="menuClick"
|
||||
v-bind:target="props.item.target ?? null"
|
||||
>
|
||||
<BaseIcon v-if="item.icon" :path="item.icon" class="flex-none" :class="activeInactiveStyle" w="w-16" :size="18" />
|
||||
<span class="grow text-ellipsis line-clamp-1" :class="activeInactiveStyle">
|
||||
{{ item.label }}
|
||||
</span>
|
||||
<component :is="is" :href="itemRoute ? stardust.route(props.item.route) : props.item.href"
|
||||
class="flex cursor-pointer dark:text-slate-300 dark:hover:text-white menu-item-wrapper" :class="componentClass"
|
||||
@click="menuClick" v-bind:target="props.item.target ?? null">
|
||||
<BaseIcon v-if="item.icon" :path="item.icon" class="flex-none menu-item-icon" :class="activeInactiveStyle"
|
||||
w="w-16" :size="18" />
|
||||
<div class="menu-item-label">
|
||||
<span class="grow text-ellipsis line-clamp-1" :class="activeInactiveStyle">
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- plus icon for expanding sub menu -->
|
||||
<BaseIcon
|
||||
v-if="hasDropdown"
|
||||
:path="isDropdownActive ? mdiMinus : mdiPlus"
|
||||
class="flex-none"
|
||||
:class="activeInactiveStyle"
|
||||
w="w-12"
|
||||
@click.prevent="menuClick"
|
||||
/>
|
||||
<BaseIcon v-if="hasChildren" :path="props.item.isOpen ? mdiMinus : mdiPlus" class="flex-none"
|
||||
:class="[activeInactiveStyle]" w="w-12" />
|
||||
</component>
|
||||
<AsideMenuList
|
||||
v-if="hasDropdown"
|
||||
:menu="item.children"
|
||||
:class="[styleService.asideMenuDropdownStyle, isDropdownActive ? 'block dark:bg-slate-800/50' : 'hidden']"
|
||||
is-dropdown-list
|
||||
/>
|
||||
<div class="menu-item-dropdown"
|
||||
:class="[styleService.asideMenuDropdownStyle, props.item.isOpen ? 'block dark:bg-slate-800/50' : 'hidden']"
|
||||
v-if="hasChildren">
|
||||
<ul>
|
||||
<!-- <li v-for="( child, index ) in children " :key="index">
|
||||
<AsideMenuItem :item="child" :key="index"> </AsideMenuItem>
|
||||
</li> -->
|
||||
<AsideMenuItem v-for="(childItem, index) in props.item.children" :key="index" :item="childItem" />
|
||||
</ul>
|
||||
</div>
|
||||
<!-- <AsideMenuList v-if="hasChildren" :items="item.children"
|
||||
:class="[styleService.asideMenuDropdownStyle, isDropdownOpen ? 'block dark:bg-slate-800/50' : 'hidden']" /> -->
|
||||
|
||||
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.menu-item-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* .menu-item-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.menu-item-label {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.menu-item-dropdown {
|
||||
margin-left: 10px;
|
||||
} */
|
||||
</style>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script setup>
|
||||
<script lang="ts" setup>
|
||||
import { router } from '@inertiajs/vue3';
|
||||
// import { Inertia } from '@inertiajs/inertia';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
|
@ -12,8 +12,8 @@ import BaseIcon from '@/Components/BaseIcon.vue';
|
|||
|
||||
defineProps({
|
||||
menu: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -56,7 +56,7 @@ const menuClick = (event, item) => {
|
|||
:class="styleStore.darkMode ? 'aside-scrollbars-[slate]' : styleStore.asideScrollbarsStyle"
|
||||
class="flex-1 overflow-y-auto overflow-x-hidden"
|
||||
>
|
||||
<AsideMenuList v-bind:menu="menu" @menu-click="menuClick" />
|
||||
<AsideMenuList :menu-items="menu" @menu-click="menuClick" />
|
||||
</div>
|
||||
<!-- <p class="menu-label">About</p>> -->
|
||||
<ul class="menu-list">
|
||||
|
|
|
@ -1,29 +1,54 @@
|
|||
<script setup lang="ts">
|
||||
import AsideMenuItem from '@/Components/AsideMenuItem.vue';
|
||||
|
||||
defineProps({
|
||||
isDropdownList: Boolean,
|
||||
menu: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
const props = defineProps({
|
||||
// isDropdownList: Boolean,
|
||||
menuItems: {
|
||||
type: Array<Object>,
|
||||
required: true,
|
||||
},
|
||||
// parentItem: {
|
||||
// type: Object,
|
||||
// required: false,
|
||||
// },
|
||||
});
|
||||
|
||||
const emit = defineEmits(['menu-click']);
|
||||
|
||||
const menuClick = (event, item) => {
|
||||
emit('menu-click', event, item);
|
||||
};
|
||||
// const menuClick = (event, item) => {
|
||||
// emit('menu-click', event, item);
|
||||
// };
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul>
|
||||
<AsideMenuItem
|
||||
v-for="(menuItem, index) in menu"
|
||||
<div class="aside-menu">
|
||||
<ul>
|
||||
<!-- <li class="menu-item"> -->
|
||||
<!-- <AsideMenuItem
|
||||
v-for="(menuItem, index) in props.items"
|
||||
:key="index"
|
||||
v-bind:item="menuItem"
|
||||
:is-dropdown-list="menuItem.children?.length > 0"
|
||||
@menu-click="menuClick"
|
||||
/>
|
||||
</ul>
|
||||
@menu-click="menuClick"
|
||||
/> -->
|
||||
<AsideMenuItem v-for="(item, index) in props.menuItems" :key="index" :item="item"> </AsideMenuItem>
|
||||
<!-- :is-dropdown-list="menuItem.children?.length > 0" -->
|
||||
<!-- </li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* .aside-menu {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 200px;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20px;
|
||||
} */
|
||||
|
||||
.menu-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -100,7 +100,7 @@ export interface Subject {
|
|||
type: string;
|
||||
value: string;
|
||||
external_key?: string;
|
||||
dataset_count: number;
|
||||
dataset_count?: number;
|
||||
}
|
||||
export interface DatasetReference {
|
||||
// id: number;
|
||||
|
|
|
@ -405,7 +405,7 @@ const onMapInitialized = (newItem) => {
|
|||
adds a new Keyword
|
||||
*/
|
||||
const addKeyword = () => {
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled', dataset_count: 0 };
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled' };
|
||||
//this.dataset.files.push(uploadedFiles[i]);
|
||||
form.subjects.push(newSubject);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import axios from 'axios';
|
||||
import { Dataset } from '@/Dataset';
|
||||
import menu from '@/menu';
|
||||
|
||||
export interface Person {
|
||||
id: number;
|
||||
|
@ -42,6 +43,8 @@ export const MainService = defineStore('main', {
|
|||
files:[],
|
||||
|
||||
dataset: {} as Dataset,
|
||||
|
||||
menu: menu,
|
||||
}),
|
||||
actions: {
|
||||
// payload = authenticated user
|
||||
|
|
|
@ -20,11 +20,13 @@ export default [
|
|||
route: 'user.index',
|
||||
icon: mdiAccountGroup,
|
||||
label: 'Users',
|
||||
roles: ['administrator'],
|
||||
},
|
||||
{
|
||||
route: 'role.index',
|
||||
icon: mdiAccountEye,
|
||||
label: 'Roles',
|
||||
roles: ['administrator'],
|
||||
},
|
||||
{
|
||||
href: '/oai',
|
||||
|
@ -36,7 +38,8 @@ export default [
|
|||
// route: 'dataset.create',
|
||||
icon: mdiDatabasePlus,
|
||||
label: 'Submitter',
|
||||
permissions: ['submitter'],
|
||||
roles: ['submitter'],
|
||||
isOpen: false,
|
||||
children: [
|
||||
{
|
||||
route: 'dataset.list',
|
||||
|
|
|
@ -3,7 +3,7 @@ export const basic = {
|
|||
asideScrollbars: 'aside-scrollbars-gray',
|
||||
asideBrand: 'bg-gray-900 text-white',
|
||||
asideMenuItem: 'text-gray-300 hover:text-white',
|
||||
asideMenuItemActive: 'font-bold text-white',
|
||||
asideMenuItemActive: 'font-bold text-cyan-300',
|
||||
asideMenuDropdown: 'bg-gray-700/50',
|
||||
navBarItemLabel: 'text-black',
|
||||
navBarItemLabelHover: 'hover:text-blue-500',
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue