This commit is contained in:
padreug 2025-02-11 00:25:47 +01:00
parent 9cde9b5cf7
commit f3927b97a4
21 changed files with 8672 additions and 202 deletions

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { Search } from 'lucide-vue-next'
import { Input } from '@/components/ui/input'
@ -16,7 +16,7 @@ import {
const { t } = useI18n()
defineProps<{
const props = defineProps<{
category: string
search: string
town: string
@ -28,6 +28,18 @@ const emit = defineEmits<{
'update:town': [value: string]
}>()
const searchValue = ref('')
// Watch for changes in the search value
watch(searchValue, (newValue) => {
emit('update:search', newValue)
})
// Watch for prop changes to update local value
watch(() => props.search, (newValue) => {
searchValue.value = newValue
}, { immediate: true })
const categoryIcons = {
restaurant: UtensilsCrossed,
lodging: Bed,
@ -77,27 +89,33 @@ const towns = computed(() => [
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Search class="h-5 w-5 text-muted-foreground" />
</div>
<Input type="text" :value="search" @input="emit('update:search', ($event.target as HTMLInputElement).value)"
class="pl-10" :placeholder="t('directory.search')" />
<Input
v-model="searchValue"
type="text"
class="pl-10 w-full"
:placeholder="t('directory.search')"
inputmode="text"
enterkeyhint="search"
/>
</div>
<div class="flex flex-col md:flex-row gap-1 sm:gap-2">
<!-- Category Filter -->
<div class="flex gap-1 sm:gap-2 overflow-x-auto pb-1 sm:pb-2 md:pb-0">
<Button v-for="cat in categories" :key="cat.id" @click="emit('update:category', cat.id)"
:variant="category === cat.id ? 'default' : 'secondary'" size="sm" class="rounded-full whitespace-nowrap">
:variant="props.category === cat.id ? 'default' : 'secondary'" size="sm" class="rounded-full whitespace-nowrap">
<!-- Show only icon on mobile for non-'all' categories -->
<template v-if="cat.id !== 'all'">
<component :is="cat.icon"
class="h-4 w-4 md:mr-2"
:class="[
category === cat.id ? '' : categoryColors[cat.id as keyof typeof categoryColors],
props.category === cat.id ? '' : categoryColors[cat.id as keyof typeof categoryColors],
'md:hidden'
]"
/>
<component :is="cat.icon"
class="h-4 w-4 mr-2 hidden md:inline-block"
:class="category === cat.id ? '' : categoryColors[cat.id as keyof typeof categoryColors]"
:class="props.category === cat.id ? '' : categoryColors[cat.id as keyof typeof categoryColors]"
/>
<span class="hidden md:inline">{{ cat.label }}</span>
</template>
@ -111,7 +129,7 @@ const towns = computed(() => [
<!-- Town Filter -->
<div class="flex gap-1 sm:gap-2 overflow-x-auto pb-1 sm:pb-2 md:pb-0">
<Button v-for="to in towns" :key="to.id" @click="emit('update:town', to.id)"
:variant="town === to.id ? 'default' : 'secondary'" size="sm" class="rounded-full whitespace-nowrap">
:variant="props.town === to.id ? 'default' : 'secondary'" size="sm" class="rounded-full whitespace-nowrap">
{{ to.label }}
</Button>
</div>

View file

@ -53,14 +53,14 @@ const filteredItems = computed(() => {
</script>
<template>
<div class="container mx-auto px-4 py-2 sm:py-8">
<div>
<!-- Filters -->
<div class="mb-4 sm:mb-8 space-y-4 md:space-y-0 md:flex md:items-center md:justify-between">
<div class="space-y-2 md:space-y-0 md:flex md:items-center md:justify-between">
<DirectoryFilter v-model:category="selectedCategory" v-model:search="searchQuery" v-model:town="selectedTown" />
</div>
<!-- Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-4">
<DirectoryCard v-for="item in filteredItems" :key="item.id" :item="item" />
</div>