- Correction du dropdown toolbar : prop align (left/right) pour éviter le débordement hors écran côté droit - Filtre de collection par statut (all/completed/ongoing) persisté dans userPreferencesStore - toolbarConfig rendu réactif (computed) avec isSelected sur Filter, Sort et View - Modale Options d'affichage par vue (Grille, Overview, Table) avec toggles persistés - Composant ToggleRow réutilisable - Normalisation author → authors dans l'entité Manga (l'API renvoie author string)
77 lines
2.7 KiB
Vue
77 lines
2.7 KiB
Vue
<template>
|
|
<Menu as="div" class="relative inline-block h-full">
|
|
<div class="h-full">
|
|
<MenuButton
|
|
:class="[
|
|
'flex flex-col items-center justify-center min-h-12 sm:min-h-14 w-min px-2 sm:ml-4 ml-1 rounded group text-white hover:text-green-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75',
|
|
active ? 'text-green-500' : ''
|
|
]"
|
|
:aria-label="label || 'Options'">
|
|
<component v-if="icon" :is="icon" class="h-5 w-5 sm:h-6 sm:w-6" aria-hidden="true" />
|
|
<ToolbarLabel :label="label" />
|
|
</MenuButton>
|
|
</div>
|
|
|
|
<MenuItems
|
|
:class="[
|
|
'absolute mt-2 w-max rounded-sm bg-gray-800 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-10',
|
|
align === 'right' ? 'right-0 origin-top-right' : 'left-0 origin-top-left'
|
|
]">
|
|
<div class="px-1 py-1">
|
|
<MenuItem v-for="(item, index) in items" :key="index" v-slot="{ active }" :disabled="item.disabled">
|
|
<button
|
|
:class="[
|
|
item.isSelected ? 'text-green-500' : active ? 'text-green-500' : 'text-white',
|
|
'group flex w-full items-center rounded-sm px-3 py-2 text-sm',
|
|
item.disabled ? 'opacity-50 cursor-not-allowed' : ''
|
|
]"
|
|
@click="item.onClick">
|
|
{{ item.label }}
|
|
</button>
|
|
</MenuItem>
|
|
</div>
|
|
</MenuItems>
|
|
</Menu>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue';
|
|
import ToolbarLabel from './ToolbarLabel.vue';
|
|
|
|
defineProps({
|
|
icon: {
|
|
type: [Object, Function],
|
|
required: false,
|
|
default: null
|
|
},
|
|
label: {
|
|
type: String,
|
|
required: false,
|
|
default: ''
|
|
},
|
|
active: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
align: {
|
|
type: String,
|
|
default: 'left',
|
|
validator: v => ['left', 'right'].includes(v)
|
|
},
|
|
items: {
|
|
type: Array,
|
|
required: true,
|
|
default: () => [],
|
|
validator: items => {
|
|
return items.every(
|
|
item =>
|
|
item &&
|
|
item.label &&
|
|
typeof item.onClick === 'function' &&
|
|
(item.isSelected === undefined || typeof item.isSelected === 'boolean')
|
|
);
|
|
}
|
|
}
|
|
});
|
|
</script>
|