Add various new components

This commit is contained in:
Neshura 2024-04-29 07:15:09 +02:00
parent e162c674bf
commit ff396e8ca2
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
6 changed files with 185 additions and 0 deletions

View file

@ -0,0 +1,84 @@
<svelte:options runes={true} />
<script lang="ts">
import {AlbumViews} from "$lib/components/custom/Views/views.svelte";
import {onMount} from "svelte";
import LoadingSpinner from "$lib/components/custom/LoadingSpinner.svelte";
import ViewCard from "$lib/components/custom/Views/ViewCard.svelte";
import {type AlbumID3, type GetAlbumList2Response, OpenSubsonic, type Parameter} from "$lib/opensubsonic";
import {Skeleton} from "$lib/components/ui/skeleton";
import {goto} from "$app/navigation";
let { viewMode = $bindable() }: { viewMode: AlbumViews } = $props();
let previousView = $state(viewMode);
let albums: Array<AlbumID3> = $state([]);
let loading = $state(true);
let paginating = $state(false);
const paginationIncrement = 100; // TODO: make configurable?
let pagination = $state(0);
let self = $state();
let scrollY = $state(0);
let scrollYMax = $state(1);
async function fetchAlbums() {
let parameters: Array<Parameter> = [
{key: "type", value: viewMode},
{key: "size", value: paginationIncrement},
{key: "offset", value: pagination},
];
const data: GetAlbumList2Response = await OpenSubsonic.get("getAlbumList2", parameters);
if (data && data.albumList2.album) {
albums = albums.concat(data.albumList2.album);
pagination += paginationIncrement;
paginating = false;
loading = false;
}
}
function updateScroll(self) {
scrollY = self.scrollTop;
scrollYMax = self.scrollTopMax;
}
$effect(() => {
if(scrollY/scrollYMax && albums.length === 100 && !paginating) {
console.log("triggered")
paginating = true;
fetchAlbums();
}
})
$effect(() => {
console.log(viewMode);
if (viewMode !== previousView) {
loading = true;
albums = [];
pagination = 0;
fetchAlbums();
previousView = viewMode
}
})
function selectAlbum(albumId) {
goto(`/album/${albumId}`);
console.log(albumId);
}
onMount(() => {
fetchAlbums();
previousView = viewMode;
})
</script>
<div class="border border-2 flex flex-row flex-wrap gap-2 p-2 h-1 min-h-full items-center justify-center overflow-y-auto" bind:this={self} onscroll={() => updateScroll(self)}>
{#if loading}
{#each [...Array(20).keys()] as i}
<Skeleton id={"album-skeleton-" + i} class="rounded-md w-56 h-72 border border-2 bg-background" />
{/each}
{:else}
{#each albums as album}
<ViewCard data={album} onselectalbum={selectAlbum}/>
{/each}
{/if}
</div>

View file

@ -0,0 +1,24 @@
<svelte:options runes={true} />
<script lang="ts">
import {Separator} from "$lib/components/ui/separator";
import {Button} from "$lib/components/ui/button";
import {AlbumViews} from "$lib/components/custom/Views/views.svelte";
let { viewMode = $bindable() }: { viewMode: AlbumViews } = $props();
let range = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,]
</script>
<div class="border border-2 flex flex-col gap-1 p-2 h-1 min-h-full">
<h1>{viewMode}</h1>
<h1>View Actions go here</h1>
<div class="overflow-y-auto">
<p>everything above this should be sticky</p>
<h1>and this lists the songs</h1>
{#each range as ignore}
<p>A</p>
{/each}
<p>And this should be after infiny loading</p>
</div>
</div>

View file

@ -0,0 +1,42 @@
<svelte:options runes={true} />
<script lang="ts">
import {Button} from "$lib/components/ui/button";
import {onMount} from "svelte";
import {type AlbumID3, type GetAlbumList2Response, OpenSubsonic, type Parameter} from "$lib/opensubsonic";
import {Skeleton} from "$lib/components/ui/skeleton";
let { data = $bindable(), onselectalbum }: { data: AlbumID3 } = $props();
let coverImage = $state(new Image());
let loading = $state(true);
async function getCoverImage() {
let parameters: Array<Parameter> = [
{key: "id", value: data.coverArt},
//{key: "size", value: paginationIncrement},
];
const imgData = await OpenSubsonic.get("getCoverArt", parameters);
if (data) {
coverImage.src = imgData.url;
coverImage.onload = () => {
loading = false;
}
}
}
onMount(() => {
getCoverImage();
})
</script>
<div class="border border-2 flex flex-col gap-1 p-2 h-72 w-56 rounded-md" onclick={() => onselectalbum(data.id)}>
{#if loading}
<Skeleton class="min-h-[192px] w-[192px]" />
{:else}
<img alt={data.name + " Cover Art"} src={coverImage.src} height="192px" width="192px" class="rounded-md"/>
{/if}
<h1>{data.name}</h1>
<h2>{data.artist}</h2>
</div>

View file

@ -0,0 +1,17 @@
export enum AlbumViews {
All = "alphabeticalByName",
Random = "random",
Favourites = "starred",
TopRated = "highest",
RecentlyAdded = "newest",
RecentlyPlayed = "recent",
MostPlayed = "frequent"
}
export enum Views {
Albums = "Albums",
Artists = "Artists",
Songs = "Songs",
Radios = "Radios",
Shares = "Shares"
}

View file

@ -0,0 +1,7 @@
import Root from "./skeleton.svelte";
export {
Root,
//
Root as Skeleton,
};

View file

@ -0,0 +1,11 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div class={cn("animate-pulse rounded-md bg-primary/10", className)} {...$$restProps}></div>