adds feed

This commit is contained in:
Christian Beutel
2025-07-11 16:02:18 +02:00
parent 25bf00a38b
commit 237d12bfec
33 changed files with 967 additions and 119 deletions

View File

@@ -1,11 +1,14 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { page } from "$app/state";
import emptyStateTrailDark from "$lib/assets/svgs/empty_states/empty_state_trail_dark.svg";
import emptyStateTrailLight from "$lib/assets/svgs/empty_states/empty_state_trail_light.svg";
import Search, {
type SearchItem,
} from "$lib/components/base/search.svelte";
import CategoryCard from "$lib/components/category_card.svelte";
import EmptyStateFeed from "$lib/components/empty_states/empty_state_feed.svelte";
import FeedCard from "$lib/components/profile/feed_card.svelte";
import Scene from "$lib/components/scene.svelte";
import TrailCard from "$lib/components/trail/trail_card.svelte";
import {
@@ -13,6 +16,7 @@
type TrailSearchResult,
} from "$lib/models/trail.js";
import { categories } from "$lib/stores/category_store";
import { feed_index } from "$lib/stores/feed_store.js";
import {
searchActors,
searchMulti,
@@ -20,7 +24,6 @@
type LocationSearchResult,
} from "$lib/stores/search_store.js";
import { theme } from "$lib/stores/theme_store";
import { currentUser } from "$lib/stores/user_store";
import { getIconForLocation } from "$lib/util/icon_util.js";
import { Canvas } from "@threlte/core";
import { _ } from "svelte-i18n";
@@ -29,6 +32,15 @@
let searchDropdownItems: SearchItem[] = $state([]);
let feed = $state(data.feed);
let pagination = $derived({
page: feed.page,
totalPages: feed.totalItems,
});
let loading: boolean = false;
async function search(q: string) {
if (q.startsWith("@")) {
const actors = await searchActors(q);
@@ -97,18 +109,41 @@
goto(`/map/?lat=${item.value.lat}&lon=${item.value.lon}`);
}
}
async function onScroll(e: Event) {
if (!page.data.user) {
return;
}
if (
window.innerHeight + window.scrollY >=
0.8 * document.body.offsetHeight &&
pagination.page !== pagination.totalPages &&
!loading
) {
loading = true;
await loadNextPage();
loading = false;
}
}
async function loadNextPage() {
pagination.page += 1;
feed = await feed_index(pagination.page);
}
</script>
<svelte:head>
<title>Home | wanderer</title>
</svelte:head>
<svelte:window onscroll={onScroll} />
<section
class="hero grid grid-cols-1 lg:grid-cols-2 md:px-8 md:gap-8"
style="height: calc(100vh - 112px)"
style="min-height: calc(100vh - 112px)"
>
<div
class="flex flex-col justify-center gap-8 max-w-md mx-8 sm:mx-auto mt-0 lg:-mt-24 md:mt-24"
class="flex flex-col justify-center gap-8 max-w-md mx-8 sm:mx-auto mt-0 lg:-mt-24 md:mt-24 max-h-screen md:sticky top-0"
>
<h2 class="text-5xl sm:text-6xl md:text-7xl font-bold">
{$_("welcome_to")} <span class="-tracking-[0.075em]">wanderer</span>
@@ -125,89 +160,111 @@
items={searchDropdownItems}
></Search>
</div>
<div class="hidden md:block">
<Canvas toneMapping={0}>
<Scene></Scene>
</Canvas>
</div>
</section>
<section
class="max-w-7xl mx-auto mt-8 px-8 xl:px-0 grid grid-cols-1 md:grid-cols-2 items-center gap-x-12"
>
<div
id="trails"
class="flex flex-wrap justify-items-center gap-8 py-8 order-1 md:order-none"
>
{#if data.trails.length == 0}
<img
style="width: min(450px, 100%)"
class="rounded-md"
src={$theme === "light"
? emptyStateTrailLight
: emptyStateTrailDark}
alt="Empty state"
/>
{:else}
{#each data.trails as trail}
{#if !page.data.user}
<div class="hidden md:block">
<Canvas toneMapping={0}>
<Scene></Scene>
</Canvas>
</div>
{:else}
<div class="space-y-2">
{#if feed.items.length === 0}
<EmptyStateFeed></EmptyStateFeed>
{/if}
{#each feed.items as f}
<a
class="w-full md:max-w-72"
href="/trail/view/@{trail.author}{trail.domain
? '@' + trail.domain
: ''}/{trail.id}"
>
<TrailCard {trail} fullWidth selected={false} hovered={false}></TrailCard></a
class="block"
href={(f.type === "trail" ? "/trail/view/" : "/lists/") +
`@${f.expand.author?.preferred_username}@${f.expand.author?.domain}/${f.item}`}
>
<FeedCard feedItem={f}></FeedCard>
</a>
{/each}
{/if}
</div>
<div class="max-w-md md:mx-auto space-y-8">
{#if data.trails.length == 0}
<h2 class="text-4xl md:text-5xl font-bold">
{$_("hero_section_1_heading")}
</h2>
<h5>{$_("hero_section_1_text_alternative")}</h5>
<a
class="inline-block btn-primary btn-large"
href="/trail/edit/new"
role="button">{$_("new-trail")}</a
>
{:else}
<h2 class="text-4xl md:text-5xl font-bold">
{$currentUser
? $_("trails-for-you")
: $_("explore-some-trails")}
</h2>
<h5>
{$_("hero_section_1_text")}
</h5>
<a
class="inline-block btn-primary btn-large"
href="/trails"
role="button">{$_("explore")}</a
>
{/if}
</div>
</div>
{/if}
</section>
<section
class="max-w-7xl mx-auto mt-8 px-8 xl:px-0 grid grid-cols-1 md:grid-cols-2 items-center"
>
<div class="max-w-md md:mx-auto space-y-8">
<h2 class="text-4xl md:text-5xl font-bold">{$_("categories")}</h2>
<h5>
{$_("hero_section_2_text")}
</h5>
</div>
<div
id="categories"
class="grid grid-cols-1 lg:grid-cols-2 justify-items-center gap-8 py-8"
{#if !page.data.user}
<section
class="max-w-7xl mx-auto mt-8 px-8 xl:px-0 grid grid-cols-1 md:grid-cols-2 items-center gap-x-12"
>
{#each $categories as category}
<a href="/trails?category={category.name}">
<CategoryCard {category}></CategoryCard>
</a>
{/each}
</div>
</section>
<div
id="trails"
class="flex flex-wrap justify-items-center gap-8 py-8 order-1 md:order-none"
>
{#if data.trails.length == 0}
<img
style="width: min(450px, 100%)"
class="rounded-md"
src={$theme === "light"
? emptyStateTrailLight
: emptyStateTrailDark}
alt="Empty state"
/>
{:else}
{#each data.trails as trail}
<a
class="w-full md:max-w-72"
href="/trail/view/@{trail.author}{trail.domain
? '@' + trail.domain
: ''}/{trail.id}"
>
<TrailCard
{trail}
fullWidth
selected={false}
hovered={false}
></TrailCard></a
>
{/each}
{/if}
</div>
<div class="max-w-md md:mx-auto space-y-8">
{#if data.trails.length == 0}
<h2 class="text-4xl md:text-5xl font-bold">
{$_("hero_section_1_heading")}
</h2>
<h5>{$_("hero_section_1_text_alternative")}</h5>
<a
class="inline-block btn-primary btn-large"
href="/trail/edit/new"
role="button">{$_("new-trail")}</a
>
{:else}
<h2 class="text-4xl md:text-5xl font-bold">
{$_("explore-some-trails")}
</h2>
<h5>
{$_("hero_section_1_text")}
</h5>
<a
class="inline-block btn-primary btn-large"
href="/trails"
role="button">{$_("explore")}</a
>
{/if}
</div>
</section>
<section
class="max-w-7xl mx-auto mt-8 px-8 xl:px-0 grid grid-cols-1 md:grid-cols-2 items-center"
>
<div class="max-w-md md:mx-auto space-y-8">
<h2 class="text-4xl md:text-5xl font-bold">{$_("categories")}</h2>
<h5>
{$_("hero_section_2_text")}
</h5>
</div>
<div
id="categories"
class="grid grid-cols-1 lg:grid-cols-2 justify-items-center gap-8 py-8"
>
{#each $categories as category}
<a href="/trails?category={category.name}">
<CategoryCard {category}></CategoryCard>
</a>
{/each}
</div>
</section>
{/if}
<style>
</style>

View File

@@ -1,5 +1,6 @@
import type { Trail } from "$lib/models/trail";
import { categories_index } from "$lib/stores/category_store";
import { feed_index } from "$lib/stores/feed_store";
import { trails_recommend } from "$lib/stores/trail_store";
import type { ServerLoad } from "@sveltejs/kit";
@@ -7,11 +8,13 @@ export const load: ServerLoad = async ({ params, locals, fetch }) => {
try {
await categories_index(fetch)
const feed = await feed_index(1, 10, fetch);
const trails: Trail[] = await trails_recommend(4, fetch)
return { trails: trails ?? [] }
return { trails: trails ?? [], feed }
} catch (e) {
console.error(e)
}
return { trails: [] }
return { trails: [], feed: {items: [], page: 1, perPage: 1, totalItems: 0, totalPages: 0} }
};

View File

@@ -0,0 +1,13 @@
import type { FeedItem } from "$lib/models/feed";
import { Collection, handleError, list } from "$lib/util/api_util";
import { json, type RequestEvent } from "@sveltejs/kit";
export async function GET(event: RequestEvent) {
try {
const r = await list<FeedItem>(event, Collection.feed);
return json(r)
} catch (e) {
return handleError(e)
}
}

View File

@@ -404,7 +404,6 @@
><i class="fa fa-table mr-3"></i>{$_("all-activities")}</span
>
<div class=" overflow-x-auto">
{data.logs.length}
<SummitLogTable
{summitLogs}
handle={page.params.handle}