Füge Scrollsteuerung für Mannschaften-Untermenü hinzu und optimiere Importpfade
This commit is contained in:
@@ -193,9 +193,10 @@
|
|||||||
<template v-if="currentSubmenu === 'mannschaften'">
|
<template v-if="currentSubmenu === 'mannschaften'">
|
||||||
<div
|
<div
|
||||||
ref="mannschaftenSubmenuRail"
|
ref="mannschaftenSubmenuRail"
|
||||||
class="flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap scroll-smooth pr-7 [scrollbar-color:theme(colors.primary.700)_transparent] [scrollbar-width:thin]"
|
class="flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap scroll-smooth px-7 [scrollbar-color:theme(colors.primary.700)_transparent] [scrollbar-width:thin]"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
aria-label="Mannschaften-Untermenü – horizontal scrollbar"
|
aria-label="Mannschaften-Untermenü – horizontal scrollbar"
|
||||||
|
@scroll.passive="updateMannschaftenSubmenuControls"
|
||||||
>
|
>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/mannschaften"
|
to="/mannschaften"
|
||||||
@@ -234,6 +235,17 @@
|
|||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
v-if="showMannschaftenSubmenuLeftControl"
|
||||||
|
type="button"
|
||||||
|
class="absolute inset-y-0 left-0 z-10 flex w-9 items-center justify-start bg-gradient-to-r from-primary-900 via-primary-900/90 to-transparent pl-1 text-primary-300 transition-colors hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-300"
|
||||||
|
aria-label="Vorherige Mannschaften anzeigen"
|
||||||
|
@pointerdown.stop
|
||||||
|
@click.stop.prevent="scrollMannschaftenSubmenuLeft"
|
||||||
|
>
|
||||||
|
‹
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="showMannschaftenSubmenuRightControl"
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute inset-y-0 right-0 z-10 flex w-9 items-center justify-end bg-gradient-to-l from-primary-900 via-primary-900/90 to-transparent pr-1 text-primary-300 transition-colors hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-300"
|
class="absolute inset-y-0 right-0 z-10 flex w-9 items-center justify-end bg-gradient-to-l from-primary-900 via-primary-900/90 to-transparent pr-1 text-primary-300 transition-colors hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-300"
|
||||||
aria-label="Weitere Mannschaften anzeigen"
|
aria-label="Weitere Mannschaften anzeigen"
|
||||||
@@ -872,7 +884,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
import { ref, onMounted, onUnmounted, computed, nextTick, watch } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { Menu, X, ChevronDown } from 'lucide-vue-next'
|
import { Menu, X, ChevronDown } from 'lucide-vue-next'
|
||||||
|
|
||||||
@@ -881,6 +893,8 @@ const isMobileMenuOpen = ref(false)
|
|||||||
const mobileSubmenu = ref(null)
|
const mobileSubmenu = ref(null)
|
||||||
const mannschaften = ref([])
|
const mannschaften = ref([])
|
||||||
const mannschaftenSubmenuRail = ref(null)
|
const mannschaftenSubmenuRail = ref(null)
|
||||||
|
const showMannschaftenSubmenuLeftControl = ref(false)
|
||||||
|
const showMannschaftenSubmenuRightControl = ref(false)
|
||||||
const hasGalleryImages = ref(false)
|
const hasGalleryImages = ref(false)
|
||||||
const showCmsDropdown = ref(false)
|
const showCmsDropdown = ref(false)
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
@@ -918,6 +932,28 @@ const toggleMobileSubmenu = (menu) => {
|
|||||||
mobileSubmenu.value = mobileSubmenu.value === menu ? null : menu
|
mobileSubmenu.value = mobileSubmenu.value === menu ? null : menu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateMannschaftenSubmenuControls = () => {
|
||||||
|
const rail = mannschaftenSubmenuRail.value
|
||||||
|
if (!rail) return
|
||||||
|
|
||||||
|
const canScroll = rail.scrollWidth > rail.clientWidth + 1
|
||||||
|
const atStart = rail.scrollLeft <= 1
|
||||||
|
const atEnd = rail.scrollLeft + rail.clientWidth >= rail.scrollWidth - 1
|
||||||
|
|
||||||
|
showMannschaftenSubmenuLeftControl.value = canScroll && !atStart
|
||||||
|
showMannschaftenSubmenuRightControl.value = canScroll && !atEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollMannschaftenSubmenuLeft = () => {
|
||||||
|
const rail = mannschaftenSubmenuRail.value
|
||||||
|
if (!rail) return
|
||||||
|
|
||||||
|
rail.scrollBy({
|
||||||
|
left: -Math.max(rail.clientWidth * 0.8, 160),
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const scrollMannschaftenSubmenuRight = () => {
|
const scrollMannschaftenSubmenuRight = () => {
|
||||||
const rail = mannschaftenSubmenuRail.value
|
const rail = mannschaftenSubmenuRail.value
|
||||||
if (!rail) return
|
if (!rail) return
|
||||||
@@ -1012,16 +1048,23 @@ onMounted(() => {
|
|||||||
// Listen for global updates to mannschaften (e.g., CMS saved)
|
// Listen for global updates to mannschaften (e.g., CMS saved)
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.addEventListener('mannschaften:changed', loadMannschaften)
|
window.addEventListener('mannschaften:changed', loadMannschaften)
|
||||||
|
window.addEventListener('resize', updateMannschaftenSubmenuControls)
|
||||||
}
|
}
|
||||||
|
nextTick(updateMannschaftenSubmenuControls)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener('click', handleDocumentClick)
|
document.removeEventListener('click', handleDocumentClick)
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.removeEventListener('mannschaften:changed', loadMannschaften)
|
window.removeEventListener('mannschaften:changed', loadMannschaften)
|
||||||
|
window.removeEventListener('resize', updateMannschaftenSubmenuControls)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch([currentSubmenu, mannschaften], () => {
|
||||||
|
nextTick(updateMannschaftenSubmenuControls)
|
||||||
|
}, { flush: 'post' })
|
||||||
|
|
||||||
const toggleSubmenu = (menu) => {
|
const toggleSubmenu = (menu) => {
|
||||||
// Wenn wir schon im richtigen Bereich sind, nichts tun (Submenu bleibt offen)
|
// Wenn wir schon im richtigen Bereich sind, nichts tun (Submenu bleibt offen)
|
||||||
// Wenn nicht, zur Hauptseite navigieren
|
// Wenn nicht, zur Hauptseite navigieren
|
||||||
|
|||||||
@@ -362,7 +362,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { rowMatchesTeamFilter } from '../../utils/spielplan-filter.js'
|
import { rowMatchesTeamFilter } from '~/utils/spielplan-filter.js'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
|||||||
@@ -360,7 +360,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { filterSpielplanRows, toApiTeamParam } from '../../utils/spielplan-filter.js'
|
import { filterSpielplanRows, toApiTeamParam } from '~/utils/spielplan-filter.js'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { listSpielplanSeasons, readSpielplanData, validateSeasonSlug } from '../../utils/spielplan-data.js'
|
import { listSpielplanSeasons, readSpielplanData, validateSeasonSlug } from '../../utils/spielplan-data.js'
|
||||||
import { formatTeamDisplayName } from '../../../utils/team-display.js'
|
import { formatTeamDisplayName } from '~/utils/team-display.js'
|
||||||
|
|
||||||
function teamLabel(teamName, teamAgeGroup, competitionAgeGroup) {
|
function teamLabel(teamName, teamAgeGroup, competitionAgeGroup) {
|
||||||
return formatTeamDisplayName(teamName, teamAgeGroup, competitionAgeGroup)
|
return formatTeamDisplayName(teamName, teamAgeGroup, competitionAgeGroup)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import fs from 'fs/promises'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { readSpielplanData, validateSeasonSlug } from '../../utils/spielplan-data.js'
|
import { readSpielplanData, validateSeasonSlug } from '../../utils/spielplan-data.js'
|
||||||
import { info as loggerInfo, error as loggerError } from '../../utils/logger.js'
|
import { info as loggerInfo, error as loggerError } from '../../utils/logger.js'
|
||||||
import { filterSpielplanRows } from '../../../utils/spielplan-filter.js'
|
import { filterSpielplanRows } from '~/utils/spielplan-filter.js'
|
||||||
|
|
||||||
function seasonSlugToLabel(slug) {
|
function seasonSlugToLabel(slug) {
|
||||||
const match = String(slug || '').match(/^(\d{2})--(\d{2})$/)
|
const match = String(slug || '').match(/^(\d{2})--(\d{2})$/)
|
||||||
|
|||||||
Reference in New Issue
Block a user