d6a40e4843
Déconnexion déplacée du menu vers le footer (compte connecté au survol + version). useLogout() appelle clearSession() (reset des stores singletons via onAuthSessionCleared) puis redirige vers /login, sans page /logout intermédiaire.
126 lines
5.8 KiB
Vue
126 lines
5.8 KiB
Vue
<!--
|
|
Valeurs en dur issues de la maquette Figma (design Starseed) :
|
|
- sidebar depliee : 232px (w-[232px], repli laisse par defaut 72px)
|
|
- marge horizontale du contenu sur desktop : 170px (xl:px-[170px])
|
|
La marge haute du contenu (44px) vit desormais DANS l'entete (PageHeader,
|
|
pt-11) et non sur le <main> : sinon, l'entete etant sticky, ce padding
|
|
laissait un trou blanc entre le SiteSelector et l'entete.
|
|
A faire evoluer uniquement avec une mise a jour de maquette.
|
|
-->
|
|
<template>
|
|
<div class="h-screen overflow-hidden">
|
|
<div class="flex h-full">
|
|
<MalioSidebar
|
|
v-model="ui.sidebarCollapsed"
|
|
:sections="translatedSections"
|
|
:sidebar-class="ui.sidebarCollapsed ? '' : 'w-[232px]'"
|
|
>
|
|
<template #logo>
|
|
<img src="/LOGO_MALIO.png" alt="Malio"/>
|
|
</template>
|
|
<template #logo-collapsed>
|
|
<img src="/LOGO_MALIO_COLLAPSED.png" alt="Malio"/>
|
|
</template>
|
|
|
|
<!-- Footer deplie : compte connecte (survol -> deconnexion) + version. -->
|
|
<template #footer>
|
|
<div class="flex flex-col gap-2">
|
|
<!-- Bloc compte : au survol, un menu de deconnexion s'ouvre vers
|
|
le haut (le footer etant colle en bas de la sidebar). -->
|
|
<div class="group relative" data-test="sidebar-account">
|
|
<button
|
|
type="button"
|
|
data-test="sidebar-logout"
|
|
class="invisible absolute bottom-full left-0 right-0 mb-2 flex items-center gap-2 rounded-md bg-white px-3 py-2 text-[14px] font-semibold text-m-danger opacity-0 shadow-lg ring-1 ring-m-border transition-all duration-150 hover:bg-m-danger hover:text-white group-hover:visible group-hover:opacity-100"
|
|
@click="onLogout"
|
|
>
|
|
<Icon name="mdi:logout" class="size-[18px] shrink-0"/>
|
|
<span>{{ t('sidebar.account.logout') }}</span>
|
|
</button>
|
|
<div class="flex items-center gap-2 rounded-md p-1.5 text-black transition-colors group-hover:bg-m-primary/10 group-hover:font-semibold group-hover:text-m-primary">
|
|
<span class="flex size-9 shrink-0 items-center justify-center rounded-full bg-m-primary text-[13px] font-bold uppercase text-white">{{ initials }}</span>
|
|
<span class="min-w-0 flex-1 truncate text-[14px] font-semibold">{{ username }}</span>
|
|
<Icon name="mdi:chevron-up" class="size-[18px] shrink-0"/>
|
|
</div>
|
|
</div>
|
|
<p v-if="version" class="text-center text-[12px] font-bold text-m-muted">v {{ version }}</p>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Footer replie : pastille initiale, survol -> icone deconnexion. -->
|
|
<template #footer-collapsed>
|
|
<button
|
|
type="button"
|
|
data-test="sidebar-logout"
|
|
:title="`${username} — ${t('sidebar.account.logout')}`"
|
|
class="group mx-auto flex size-9 items-center justify-center rounded-full bg-m-primary text-[13px] font-bold uppercase text-white transition-colors hover:bg-m-danger"
|
|
@click="onLogout"
|
|
>
|
|
<span class="group-hover:hidden">{{ initials }}</span>
|
|
<Icon name="mdi:logout" class="hidden size-[18px] group-hover:block"/>
|
|
</button>
|
|
</template>
|
|
</MalioSidebar>
|
|
|
|
<div class="h-full flex-1 flex flex-col min-h-0 min-w-0">
|
|
<SiteSelector v-if="showSiteSelector"/>
|
|
<main
|
|
class="flex flex-1 flex-col overflow-y-auto overflow-x-hidden bg-white px-4 pb-10 sm:px-6 lg:px-12 xl:px-11">
|
|
<slot/>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const {t} = useI18n()
|
|
const ui = useUiStore()
|
|
const {sections} = useSidebar()
|
|
const {isModuleActive} = useModules()
|
|
const auth = useAuthStore()
|
|
const route = useRoute()
|
|
|
|
// Footer de la sidebar : compte connecte + deconnexion inline + version.
|
|
const {logout: onLogout} = useLogout()
|
|
const {version, load: loadAppVersion} = useAppVersion()
|
|
|
|
const username = computed(() => auth.user?.username ?? '')
|
|
// Pastille avatar : 1re lettre du compte (meme convention que la maquette Malio).
|
|
const initials = computed(() => username.value.charAt(0).toUpperCase() || '?')
|
|
|
|
onMounted(() => {
|
|
void loadAppVersion()
|
|
})
|
|
|
|
// Le SiteSelector est rendu si :
|
|
// - le module Sites est actif dans config/modules.php (sinon la feature
|
|
// n'a pas de sens, cf. ticket 3 spec criteres d'acceptation) ;
|
|
// - ET l'user connecte a au moins un site autorise (sinon "barre vide"
|
|
// sans tile cliquable).
|
|
// Les deux flags sont resolus par le middleware auth.global.ts avant
|
|
// que le layout ne soit rendu (plan load parallele), donc pas de flash.
|
|
const showSiteSelector = computed(() =>
|
|
isModuleActive('sites') && (auth.user?.sites?.length ?? 0) > 0,
|
|
)
|
|
|
|
const translatedSections = computed(() =>
|
|
sections.value.map(section => ({
|
|
label: t(section.label),
|
|
icon: section.icon,
|
|
items: section.items.map(item => ({
|
|
label: t(item.label),
|
|
to: item.to,
|
|
})),
|
|
}))
|
|
)
|
|
|
|
watch(() => route.path, () => {
|
|
ui.closeMobileSidebar()
|
|
})
|
|
|
|
useHead({
|
|
titleTemplate: (title) => title || 'Starseed',
|
|
})
|
|
</script>
|