86 lines
2.9 KiB
Vue
86 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import { useI18n } from 'vue-i18n'
|
|
import DirectoryGrid from '@/components/directory/DirectoryGrid.vue'
|
|
import DirectoryFilter from '@/components/directory/DirectoryFilter.vue'
|
|
import { mockDirectoryItems } from '@/data/directory'
|
|
import { ref, computed, watch } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { useTheme } from '@/components/theme-provider'
|
|
|
|
const { t } = useI18n()
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const { currentTown } = useTheme()
|
|
|
|
// Use the imported mock data
|
|
const items = mockDirectoryItems
|
|
|
|
const category = ref('all')
|
|
const search = ref('')
|
|
const town = ref(currentTown.value)
|
|
|
|
// Watch for route changes to update filters
|
|
watch(() => route.query, (newQuery) => {
|
|
category.value = newQuery.category?.toString() || 'all'
|
|
search.value = newQuery.search?.toString() || ''
|
|
town.value = newQuery.town === undefined ? currentTown.value : (newQuery.town?.toString() || 'all')
|
|
}, { immediate: true })
|
|
|
|
// Watch for filter changes and update URL
|
|
watch([category, search, town], ([newCategory, newSearch, newTown]) => {
|
|
// Don't update URL if it matches current query params
|
|
if (
|
|
newCategory === route.query.category &&
|
|
newSearch === route.query.search &&
|
|
newTown === route.query.town
|
|
) {
|
|
return
|
|
}
|
|
|
|
const query = {
|
|
...(newCategory !== 'all' && { category: newCategory }),
|
|
...(newSearch && { search: newSearch }),
|
|
...(newTown !== currentTown.value && { town: newTown })
|
|
}
|
|
router.replace({ query })
|
|
})
|
|
|
|
// Filter items based on category, search, and town
|
|
const filteredItems = computed(() => {
|
|
return items.filter(item => {
|
|
const matchesCategory = category.value === 'all' || item.category === category.value
|
|
const matchesSearch = !search.value ||
|
|
item.name.toLowerCase().includes(search.value.toLowerCase()) ||
|
|
item.description?.toLowerCase().includes(search.value.toLowerCase())
|
|
const matchesTown = town.value === 'all' || item.town === town.value
|
|
return matchesCategory && matchesSearch && matchesTown
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="container mx-auto px-4 py-2 md:py-8">
|
|
<div class="space-y-4">
|
|
<!-- Directory Header -->
|
|
<div class="hidden md:block text-center space-y-2 mb-6">
|
|
<h1 class="text-2xl font-bold tracking-tight sm:text-3xl">
|
|
{{ t('directory.title') }}
|
|
</h1>
|
|
<p class="text-sm sm:text-base text-muted-foreground">
|
|
{{ t('directory.subtitle') }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Sticky Container for Filter -->
|
|
<div class="sticky top-14 z-40 -mx-4 bg-background/95 backdrop-blur-sm border-b w-screen left-0">
|
|
<div class="container mx-auto px-4">
|
|
<DirectoryFilter v-model:category="category" v-model:search="search" v-model:town="town" class="py-4" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Directory Grid -->
|
|
<DirectoryGrid :items="filteredItems" class="pt-4" />
|
|
</div>
|
|
</div>
|
|
</template>
|