update
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { abonnieren } from './live'
|
import { abonnieren } from './live'
|
||||||
import MovieCard from './components/MovieCard.vue'
|
import MovieCard from './components/MovieCard.vue'
|
||||||
import FilterSidebar from './components/FilterSidebar.vue'
|
import FilterSidebar from './components/FilterSidebar.vue'
|
||||||
@@ -512,6 +512,56 @@ const visibleCanon = computed(() =>
|
|||||||
filterGruppen(canonGroups.value, search.value.trim().toLowerCase())
|
filterGruppen(canonGroups.value, search.value.trim().toLowerCase())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Gefiltert wird über den ganzen Katalog, gerendert nur der Anfang davon.
|
||||||
|
// Alle 2554 Karten auf einmal sind in der Detailansicht über zehntausend
|
||||||
|
// Bilder — der Browser meldet dann "Seite reagiert nicht".
|
||||||
|
const STAPEL = 100
|
||||||
|
const gezeigt = ref(STAPEL)
|
||||||
|
|
||||||
|
const aktuelleListe = computed(() =>
|
||||||
|
activeTab.value === 'netflix' ? visible.value : visibleCanon.value
|
||||||
|
)
|
||||||
|
|
||||||
|
const sichtbar = computed(() => aktuelleListe.value.slice(0, gezeigt.value))
|
||||||
|
|
||||||
|
// Jede neue Suche, jeder Filter und jeder Reiterwechsel fängt oben an
|
||||||
|
watch([aktuelleListe, ansicht], () => {
|
||||||
|
gezeigt.value = STAPEL
|
||||||
|
})
|
||||||
|
|
||||||
|
async function mehrLaden() {
|
||||||
|
if (gezeigt.value >= aktuelleListe.value.length) return
|
||||||
|
gezeigt.value += STAPEL
|
||||||
|
// Der Beobachter meldet sich nur beim Wechsel sichtbar/unsichtbar. Bleibt
|
||||||
|
// der Fuß nach dem Nachladen im Blick — großer Bildschirm, kurze Liste —,
|
||||||
|
// käme sonst nie ein zweiter Stapel.
|
||||||
|
await nextTick()
|
||||||
|
const el = nachschub.value
|
||||||
|
if (el && el.getBoundingClientRect().top < window.innerHeight + 600) mehrLaden()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Der Fuß der Liste meldet sich, sobald er in Sichtweite kommt. Ein
|
||||||
|
// Scroll-Handler müsste bei jedem Pixel rechnen, das hier nicht.
|
||||||
|
// Gleich hier angelegt, nicht in onMounted: die Vorlage setzt die Referenz
|
||||||
|
// schon beim ersten Zeichnen, da muss der Beobachter bereits stehen.
|
||||||
|
const nachschub = ref(null)
|
||||||
|
const beobachter = new IntersectionObserver(
|
||||||
|
(eintraege) => {
|
||||||
|
if (eintraege.some((e) => e.isIntersecting)) mehrLaden()
|
||||||
|
},
|
||||||
|
// Vorlauf, damit der Nachschub schon da ist, bevor die Liste endet
|
||||||
|
{ rootMargin: '600px' }
|
||||||
|
)
|
||||||
|
|
||||||
|
onUnmounted(() => beobachter.disconnect())
|
||||||
|
|
||||||
|
// Der Fuß verschwindet und kommt wieder, je nach Filter — also bei jedem
|
||||||
|
// Wechsel neu anmelden
|
||||||
|
watch(nachschub, (el, vorher) => {
|
||||||
|
if (vorher) beobachter.unobserve(vorher)
|
||||||
|
if (el) beobachter.observe(el)
|
||||||
|
})
|
||||||
|
|
||||||
// Die Reihe zum geöffneten Film. Im Kanon ist das die Gruppe der Vorlage,
|
// Die Reihe zum geöffneten Film. Im Kanon ist das die Gruppe der Vorlage,
|
||||||
// sonst TMDBs Collection — dort aber nur, was auch auf Netflix liegt.
|
// sonst TMDBs Collection — dort aber nur, was auch auf Netflix liegt.
|
||||||
const series = computed(() => {
|
const series = computed(() => {
|
||||||
@@ -681,10 +731,7 @@ onUnmounted(() => {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="grid" :class="ansicht">
|
<div class="grid" :class="ansicht">
|
||||||
<template
|
<template v-for="entry in sichtbar" :key="entry.group">
|
||||||
v-for="entry in activeTab === 'netflix' ? visible : visibleCanon"
|
|
||||||
:key="entry.group"
|
|
||||||
>
|
|
||||||
<MovieCard
|
<MovieCard
|
||||||
v-if="entry.parts.length === 1"
|
v-if="entry.parts.length === 1"
|
||||||
:movie="entry.parts[0]"
|
:movie="entry.parts[0]"
|
||||||
@@ -702,6 +749,10 @@ onUnmounted(() => {
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="gezeigt < aktuelleListe.length" ref="nachschub" class="nachschub">
|
||||||
|
Lädt weitere Filme …
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FilterSidebar
|
<FilterSidebar
|
||||||
@@ -870,6 +921,13 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nachschub {
|
||||||
|
padding: 2rem 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
|
||||||
|
|||||||
Reference in New Issue
Block a user