feat: implement endless scrolling
This commit is contained in:
@@ -3,7 +3,10 @@ import { aktis, ratings } from '$lib/server/db/schema';
|
||||
import { avg, eq } from 'drizzle-orm';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ url }) => {
|
||||
const offset = Number(url.searchParams.get('offset')) || 0;
|
||||
const limit = 20;
|
||||
|
||||
const a = await db
|
||||
.select({
|
||||
id: aktis.id,
|
||||
@@ -14,7 +17,8 @@ export const load: PageServerLoad = async () => {
|
||||
.from(aktis)
|
||||
.leftJoin(ratings, eq(aktis.id, ratings.aktiId))
|
||||
.groupBy(aktis.id, aktis.title, aktis.summary)
|
||||
.limit(50);
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
|
||||
return {
|
||||
aktis: a.map((a) => ({ ...a, rating: a.rating ? parseFloat(a.rating) : undefined }))
|
||||
|
||||
+44
-1
@@ -1,12 +1,55 @@
|
||||
<script lang="ts">
|
||||
import AktiCard from '$lib/components/akti/AktiCard.svelte';
|
||||
import type { PageProps } from './$types';
|
||||
import { Spinner } from 'flowbite-svelte';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
let aktis = $state(data.aktis);
|
||||
let offset = $state(data.aktis.length);
|
||||
let loading = $state(false);
|
||||
let hasMore = $state(data.aktis.length >= 20);
|
||||
|
||||
async function loadMore() {
|
||||
if (loading || !hasMore) return;
|
||||
loading = true;
|
||||
const res = await fetch(`/api/aktis?offset=${offset}`);
|
||||
const newAktis = await res.json();
|
||||
|
||||
if (newAktis.length < 20) {
|
||||
hasMore = false;
|
||||
}
|
||||
|
||||
aktis = [...aktis, ...newAktis];
|
||||
offset += newAktis.length;
|
||||
loading = false;
|
||||
}
|
||||
|
||||
function infiniteScroll(node: HTMLElement) {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
loadMore();
|
||||
}
|
||||
});
|
||||
observer.observe(node);
|
||||
return {
|
||||
destroy() {
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid gap-5 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 3xl:grid-cols-5">
|
||||
{#each data.aktis as akti (akti.id)}
|
||||
{#each aktis as akti (akti.id)}
|
||||
<AktiCard {akti}></AktiCard>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex justify-center h-20">
|
||||
{#if loading}
|
||||
<Spinner />
|
||||
{:else if hasMore}
|
||||
<div use:infiniteScroll></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { db } from '$lib/server/db';
|
||||
import { aktis, ratings } from '$lib/server/db/schema';
|
||||
import { avg, eq } from 'drizzle-orm';
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const GET: RequestHandler = async ({ url }) => {
|
||||
const offset = Number(url.searchParams.get('offset')) || 0;
|
||||
const limit = 20;
|
||||
|
||||
const a = await db
|
||||
.select({
|
||||
id: aktis.id,
|
||||
title: aktis.title,
|
||||
summary: aktis.summary,
|
||||
rating: avg(ratings.rating)
|
||||
})
|
||||
.from(aktis)
|
||||
.leftJoin(ratings, eq(aktis.id, ratings.aktiId))
|
||||
.groupBy(aktis.id, aktis.title, aktis.summary)
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
|
||||
return json(a.map((a) => ({ ...a, rating: a.rating ? parseFloat(a.rating) : undefined })));
|
||||
};
|
||||
Reference in New Issue
Block a user