mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-25 18:25:35 +02:00
feat: add loading bar component and integrate it into TV shows and recommendations loading states and cache metadataprovider responsens in backend
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import {goto} from '$app/navigation';
|
||||
import {base} from '$app/paths';
|
||||
import type {MetaDataProviderShowSearchResult} from '$lib/types.js';
|
||||
import {toOptimizedURL} from "sveltekit-image-optimize/components";
|
||||
|
||||
let loading = $state(false);
|
||||
let errorMessage = $state(null);
|
||||
@@ -47,7 +48,7 @@
|
||||
{#if result.poster_path != null}
|
||||
<img
|
||||
class="max-h-full max-w-full object-contain rounded-lg"
|
||||
src={result.poster_path}
|
||||
src={toOptimizedURL(result.poster_path)}
|
||||
alt="{result.name}'s Poster Image"
|
||||
/>
|
||||
{:else}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<script lang="ts" module>
|
||||
import {Settings, LifeBuoy, Send, LayoutPanelLeft, TvIcon} from "lucide-svelte";
|
||||
import {Settings, LifeBuoy, Send, LayoutPanelLeft, TvIcon, Home} from "lucide-svelte";
|
||||
import {PUBLIC_VERSION} from '$env/static/public';
|
||||
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
url: '/dashboard',
|
||||
icon: Home,
|
||||
isActive: true
|
||||
},
|
||||
{
|
||||
title: 'TV',
|
||||
url: '/dashboard/tv',
|
||||
@@ -23,6 +29,18 @@
|
||||
url: '/dashboard/tv/requests'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
url: '/dashboard/settings',
|
||||
icon: Settings,
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: 'Users',
|
||||
url: '/dashboard/settings#users'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
navSecondary: [
|
||||
@@ -36,18 +54,6 @@
|
||||
url: '#',
|
||||
icon: Send
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
url: '/dashboard',
|
||||
icon: LayoutPanelLeft
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
url: '/dashboard/settings',
|
||||
icon: Settings
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
@@ -85,7 +91,7 @@
|
||||
</Sidebar.Header>
|
||||
<Sidebar.Content>
|
||||
<NavMain items={data.navMain}/>
|
||||
<NavProjects projects={data.projects}/>
|
||||
<!-- <NavProjects projects={data.projects}/> -->
|
||||
<NavSecondary class="mt-auto" items={data.navSecondary}/>
|
||||
</Sidebar.Content>
|
||||
<Sidebar.Footer>
|
||||
|
||||
21
web/src/lib/components/loading-bar.svelte
Normal file
21
web/src/lib/components/loading-bar.svelte
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts">
|
||||
import {Progress} from "$lib/components/ui/progress/index.js";
|
||||
import {onMount} from "svelte";
|
||||
|
||||
let value = $state(0);
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
value += 1;
|
||||
if (value >= 100) {
|
||||
value = 0
|
||||
clearInterval(interval);
|
||||
|
||||
}
|
||||
}, 1);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
</script>
|
||||
|
||||
<Progress value={value}/>
|
||||
@@ -22,7 +22,7 @@
|
||||
</script>
|
||||
|
||||
<Sidebar.Group>
|
||||
<Sidebar.GroupLabel>Platform</Sidebar.GroupLabel>
|
||||
<Sidebar.GroupLabel></Sidebar.GroupLabel>
|
||||
<Sidebar.Menu>
|
||||
{#each items as mainItem (mainItem.title)}
|
||||
<Collapsible.Root open={mainItem.isActive}>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</script>
|
||||
|
||||
<Sidebar.Group class="group-data-[collapsible=icon]:hidden">
|
||||
<Sidebar.GroupLabel>Projects</Sidebar.GroupLabel>
|
||||
<Sidebar.GroupLabel><!-- TODO: what to set this label to?? --> </Sidebar.GroupLabel>
|
||||
<Sidebar.Menu>
|
||||
{#each projects as item (item.name)}
|
||||
<Sidebar.MenuItem>
|
||||
|
||||
7
web/src/lib/components/ui/progress/index.ts
Normal file
7
web/src/lib/components/ui/progress/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import Root from "./progress.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Progress,
|
||||
};
|
||||
24
web/src/lib/components/ui/progress/progress.svelte
Normal file
24
web/src/lib/components/ui/progress/progress.svelte
Normal file
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import {Progress as ProgressPrimitive, type WithoutChildrenOrChild} from "bits-ui";
|
||||
import {cn} from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
max = 100,
|
||||
value,
|
||||
...restProps
|
||||
}: WithoutChildrenOrChild<ProgressPrimitive.RootProps> = $props();
|
||||
</script>
|
||||
|
||||
<ProgressPrimitive.Root
|
||||
{...restProps}
|
||||
bind:ref
|
||||
class={cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className)}
|
||||
{value}
|
||||
>
|
||||
<div
|
||||
class="bg-primary h-full w-full flex-1 transition-all"
|
||||
style={`transform: translateX(-${100 - (100 * (value ?? 0)) / (max ?? 1)}%)`}
|
||||
></div>
|
||||
</ProgressPrimitive.Root>
|
||||
@@ -3,10 +3,13 @@
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js';
|
||||
import RecommendedShowsCarousel from '$lib/components/recommended-shows-carousel.svelte';
|
||||
import LoadingBar from '$lib/components/loading-bar.svelte';
|
||||
import {base} from '$app/paths';
|
||||
import {page} from '$app/state';
|
||||
import type {MetaDataProviderShowSearchResult} from "$lib/types";
|
||||
|
||||
let recommendedShows: Promise<MetaDataProviderShowSearchResult[]> = page.data.tvRecommendations;
|
||||
|
||||
let recommendedShows = page.data.tvRecommendations;
|
||||
</script>
|
||||
|
||||
<header class="flex h-16 shrink-0 items-center gap-2">
|
||||
@@ -30,7 +33,12 @@
|
||||
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min items-center justify-center p-4">
|
||||
<div class="xl:max-w-[1200px] lg:max-w-[750px] md:max-w-[500px] sm:max-w-[200px] mx-auto">
|
||||
<h3 class="scroll-m-20 text-2xl font-semibold tracking-tight text-center my-4">Trending Shows</h3>
|
||||
<RecommendedShowsCarousel shows={recommendedShows}/>
|
||||
{#await recommendedShows}
|
||||
<LoadingBar/>
|
||||
{:then recommendations}
|
||||
<RecommendedShowsCarousel shows={recommendations}/>
|
||||
|
||||
{/await}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,16 +14,5 @@ export const load: PageLoad = async ({fetch}) => {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Failed to fetch TV recommendations: ${response.statusText}`);
|
||||
toast.error(`Failed to fetch TV recommendations: ${response.statusText}`);
|
||||
return {tvRecommendations: []};
|
||||
} else {
|
||||
console.log('Fetched TV recommendations successfully');
|
||||
toast.success('Fetched TV recommendations successfully');
|
||||
}
|
||||
|
||||
const recommendations = await response.json();
|
||||
console.log('Tv Recommendations:', recommendations);
|
||||
return {tvRecommendations: recommendations};
|
||||
return {tvRecommendations: await response.json()};
|
||||
};
|
||||
@@ -10,7 +10,7 @@
|
||||
<h1 class="scroll-m-20 my-6 text-center text-4xl font-extrabold tracking-tight lg:text-5xl">
|
||||
Settings
|
||||
</h1>
|
||||
<Card.Root>
|
||||
<Card.Root id="users">
|
||||
<Card.Header>
|
||||
<Card.Title>Users</Card.Title>
|
||||
<Card.Description>Edit or delete users</Card.Description>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import {toOptimizedURL} from 'sveltekit-image-optimize/components';
|
||||
import {getFullyQualifiedShowName} from '$lib/utils';
|
||||
import logo from '$lib/images/svelte-logo.svg';
|
||||
import LoadingBar from '$lib/components/loading-bar.svelte';
|
||||
|
||||
let tvShowsPromise = page.data.tvShows;
|
||||
</script>
|
||||
@@ -33,19 +34,24 @@
|
||||
</Breadcrumb.Root>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{#snippet loadingbar()}
|
||||
<div class="flex flex-col items-center justify-center w-full col-span-full py-16 animate-fade-in">
|
||||
<div class="w-1/2 max-w-xs">
|
||||
<LoadingBar/>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
<div class="flex w-full flex-1 flex-col gap-4 p-4 pt-0">
|
||||
<h1 class="scroll-m-20 text-center text-4xl font-extrabold tracking-tight lg:text-5xl">
|
||||
TV Shows
|
||||
</h1>
|
||||
<div
|
||||
class="grid w-full auto-rows-min gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5"
|
||||
>
|
||||
<div class="grid w-full auto-rows-min gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
|
||||
{#await tvShowsPromise}
|
||||
Loading...
|
||||
{@render loadingbar()}
|
||||
{:then tvShowsJson}
|
||||
{#await tvShowsJson.json()}
|
||||
Loading...
|
||||
{@render loadingbar()}
|
||||
|
||||
{:then tvShows}
|
||||
{#each tvShows as show}
|
||||
<a href={'/dashboard/tv/' + show.id}>
|
||||
|
||||
Reference in New Issue
Block a user