feat: festival/event model frontend + topbar activeren
- Events lijst: card grid met festival/serie chips - Festival detail: programmaonderdelen grid - CreateSubEventDialog voor sub-events binnen festival - EventTabsNav: breadcrumb terug naar festival - Sessie A: festival-bewuste EventResource + children endpoint - Topbar: zoekbalk, theme switcher, shortcuts, notificaties - Schema v1.7 + BACKLOG.md toegevoegd - 121 tests groen
This commit is contained in:
@@ -7,7 +7,6 @@ import { themeConfig } from '@themeConfig'
|
||||
import Footer from '@/layouts/components/Footer.vue'
|
||||
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
|
||||
import UserProfile from '@/layouts/components/UserProfile.vue'
|
||||
import NavBarI18n from '@core/components/I18n.vue'
|
||||
import { HorizontalNavLayout } from '@layouts'
|
||||
import { VNodeRenderer } from '@layouts/components/VNodeRenderer'
|
||||
</script>
|
||||
@@ -28,11 +27,6 @@ import { VNodeRenderer } from '@layouts/components/VNodeRenderer'
|
||||
</RouterLink>
|
||||
<VSpacer />
|
||||
|
||||
<NavBarI18n
|
||||
v-if="themeConfig.app.i18n.enable && themeConfig.app.i18n.langConfig?.length"
|
||||
:languages="themeConfig.app.i18n.langConfig"
|
||||
/>
|
||||
|
||||
<NavbarThemeSwitcher class="me-2" />
|
||||
<UserProfile />
|
||||
</template>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import navItems from '@/navigation/vertical'
|
||||
import { themeConfig } from '@themeConfig'
|
||||
|
||||
// Components
|
||||
import Footer from '@/layouts/components/Footer.vue'
|
||||
import NavBarNotifications from '@/layouts/components/NavBarNotifications.vue'
|
||||
import NavSearchBar from '@/layouts/components/NavSearchBar.vue'
|
||||
import NavbarShortcuts from '@/layouts/components/NavbarShortcuts.vue'
|
||||
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
|
||||
import UserProfile from '@/layouts/components/UserProfile.vue'
|
||||
import OrganisationSwitcher from '@/components/layout/OrganisationSwitcher.vue'
|
||||
import NavBarI18n from '@core/components/I18n.vue'
|
||||
|
||||
// @layouts plugin
|
||||
import { VerticalNavLayout } from '@layouts'
|
||||
@@ -21,12 +22,15 @@ import { VerticalNavLayout } from '@layouts'
|
||||
<div class="vertical-nav-items-shadow" />
|
||||
</template>
|
||||
|
||||
<!-- 👉 navbar -->
|
||||
<!-- 👉 navbar (match Vuexy full-version: search + actions; search flex-grows) -->
|
||||
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
||||
<div class="d-flex h-100 align-center">
|
||||
<div
|
||||
class="d-flex h-100 align-center w-100"
|
||||
style="min-inline-size: 0;"
|
||||
>
|
||||
<IconBtn
|
||||
id="vertical-nav-toggle-btn"
|
||||
class="ms-n3 d-lg-none"
|
||||
class="ms-n3 d-lg-none flex-shrink-0"
|
||||
@click="toggleVerticalOverlayNavActive(true)"
|
||||
>
|
||||
<VIcon
|
||||
@@ -35,15 +39,12 @@ import { VerticalNavLayout } from '@layouts'
|
||||
/>
|
||||
</IconBtn>
|
||||
|
||||
<NavbarThemeSwitcher />
|
||||
<NavSearchBar class="flex-grow-1 ms-lg-n3 min-w-0" />
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<NavBarI18n
|
||||
v-if="themeConfig.app.i18n.enable && themeConfig.app.i18n.langConfig?.length"
|
||||
:languages="themeConfig.app.i18n.langConfig"
|
||||
/>
|
||||
<UserProfile />
|
||||
<NavbarThemeSwitcher class="flex-shrink-0 me-2" />
|
||||
<NavbarShortcuts class="flex-shrink-0" />
|
||||
<NavBarNotifications class="flex-shrink-0 me-1" />
|
||||
<UserProfile class="flex-shrink-0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import { computed } from 'vue'
|
||||
import { useLogout } from '@/composables/api/useAuth'
|
||||
import { useAuthStore } from '@/stores/useAuthStore'
|
||||
|
||||
@@ -7,6 +7,28 @@ const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const { mutate: logout, isPending: isLoggingOut } = useLogout()
|
||||
|
||||
const user = computed(() => authStore.user)
|
||||
|
||||
const initials = computed(() => {
|
||||
const name = user.value?.name?.trim() ?? ''
|
||||
if (!name)
|
||||
return '?'
|
||||
const parts = name.split(/\s+/).filter(Boolean)
|
||||
if (parts.length >= 2)
|
||||
return (parts[0]![0]! + parts[parts.length - 1]![0]!).toUpperCase()
|
||||
return name.slice(0, 2).toUpperCase()
|
||||
})
|
||||
|
||||
const avatarSrc = computed((): string | null => {
|
||||
const raw = user.value?.avatar
|
||||
if (!raw)
|
||||
return null
|
||||
if (raw.startsWith('http://') || raw.startsWith('https://'))
|
||||
return raw
|
||||
const base = (import.meta.env.VITE_API_URL as string | undefined)?.replace(/\/api\/v1\/?$/, '') ?? ''
|
||||
return raw.startsWith('/') ? `${base}${raw}` : `${base}/${raw}`
|
||||
})
|
||||
|
||||
function handleLogout() {
|
||||
logout(undefined, {
|
||||
onSettled: () => {
|
||||
@@ -17,105 +39,57 @@ function handleLogout() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VBadge
|
||||
dot
|
||||
location="bottom right"
|
||||
offset-x="3"
|
||||
offset-y="3"
|
||||
bordered
|
||||
color="success"
|
||||
<VAvatar
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
size="38"
|
||||
>
|
||||
<VAvatar
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
<VImg
|
||||
v-if="avatarSrc"
|
||||
:src="avatarSrc"
|
||||
:alt="user?.name ?? ''"
|
||||
cover
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="text-caption font-weight-bold"
|
||||
>
|
||||
<VImg :src="avatar1" />
|
||||
{{ initials }}
|
||||
</span>
|
||||
|
||||
<!-- SECTION Menu -->
|
||||
<VMenu
|
||||
activator="parent"
|
||||
width="230"
|
||||
location="bottom end"
|
||||
offset="14px"
|
||||
>
|
||||
<VList>
|
||||
<!-- 👉 User Avatar & Name -->
|
||||
<VListItem>
|
||||
<template #prepend>
|
||||
<VListItemAction start>
|
||||
<VBadge
|
||||
dot
|
||||
location="bottom right"
|
||||
offset-x="3"
|
||||
offset-y="3"
|
||||
color="success"
|
||||
>
|
||||
<VAvatar
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
>
|
||||
<VImg :src="avatar1" />
|
||||
</VAvatar>
|
||||
</VBadge>
|
||||
</VListItemAction>
|
||||
</template>
|
||||
<VMenu
|
||||
activator="parent"
|
||||
width="260"
|
||||
location="bottom end"
|
||||
offset="14px"
|
||||
>
|
||||
<VList>
|
||||
<VListItem class="text-high-emphasis">
|
||||
<VListItemTitle class="font-weight-semibold">
|
||||
{{ user?.name ?? '—' }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-wrap">
|
||||
{{ user?.email ?? '' }}
|
||||
</VListItemSubtitle>
|
||||
</VListItem>
|
||||
|
||||
<VListItemTitle class="font-weight-semibold">
|
||||
{{ authStore.user?.name ?? 'User' }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle>{{ authStore.currentOrganisation?.role ?? '' }}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VDivider class="my-2" />
|
||||
|
||||
<VDivider class="my-2" />
|
||||
|
||||
<!-- 👉 Profile -->
|
||||
<VListItem link>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
icon="tabler-user"
|
||||
size="22"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<VListItemTitle>Profile</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- 👉 Settings -->
|
||||
<VListItem link>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
icon="tabler-settings"
|
||||
size="22"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<VListItemTitle>Settings</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- Divider -->
|
||||
<VDivider class="my-2" />
|
||||
|
||||
<!-- 👉 Logout -->
|
||||
<VListItem
|
||||
:disabled="isLoggingOut"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
icon="tabler-logout"
|
||||
size="22"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<VListItemTitle>Logout</VListItemTitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
<!-- !SECTION -->
|
||||
</VAvatar>
|
||||
</VBadge>
|
||||
<VListItem
|
||||
:disabled="isLoggingOut"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<template #prepend>
|
||||
<VIcon
|
||||
class="me-2"
|
||||
icon="tabler-logout"
|
||||
size="22"
|
||||
/>
|
||||
</template>
|
||||
<VListItemTitle>Uitloggen</VListItemTitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VMenu>
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user