This commit is contained in:
team3
2026-08-29 11:28:25 +02:00
parent 38d5a8cfae
commit f5aeaadc42
20 changed files with 1934 additions and 184 deletions

View File

@@ -0,0 +1,105 @@
<script setup>
import { ref, watch } from 'vue'
import MovieCard from './MovieCard.vue'
const emit = defineEmits(['open'])
const query = ref('')
const results = ref([])
const loading = ref(false)
const error = ref('')
const searched = ref(false)
let timer = null
let laufende = 0
async function run(term) {
if (term.trim().length < 2) {
results.value = []
searched.value = false
return
}
const meine = ++laufende
loading.value = true
error.value = ''
try {
const resp = await fetch(`/api/search?q=${encodeURIComponent(term.trim())}`)
if (!resp.ok) throw new Error('Suche fehlgeschlagen')
const data = await resp.json()
// Eine ältere Anfrage darf ein neueres Ergebnis nicht überschreiben
if (meine !== laufende) return
results.value = data
searched.value = true
} catch (err) {
if (meine === laufende) error.value = err.message
} finally {
if (meine === laufende) loading.value = false
}
}
watch(query, (term) => {
clearTimeout(timer)
timer = setTimeout(() => run(term), 350)
})
async function open(movie) {
const resp = await fetch(`/api/search/${movie.id}`)
if (resp.ok) emit('open', await resp.json())
}
</script>
<template>
<div class="search-tab">
<input
v-model="query"
type="search"
class="big-search"
placeholder="Film suchen — egal wo er läuft…"
autofocus
/>
<p v-if="loading" class="note">Suche läuft…</p>
<p v-else-if="error" class="note error">{{ error }}</p>
<p v-else-if="searched && !results.length" class="note">
Nichts gefunden für „{{ query }}“.
</p>
<p v-else-if="!searched" class="note">
Tippe einen Titel ein. Gesucht wird der ganze TMDB-Bestand, nicht nur
der Katalog.
</p>
<div class="grid">
<MovieCard
v-for="movie in results"
:key="movie.id"
:movie="movie"
@open="open"
/>
</div>
</div>
</template>
<style scoped>
.big-search {
width: 100%;
margin-bottom: 1.5rem;
padding: 0.9rem 1.1rem;
font-size: 1.05rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
gap: 1.1rem;
}
.note {
padding: 2.5rem 0;
color: var(--muted);
text-align: center;
}
.note.error {
color: var(--accent);
}
</style>