Add various new components
This commit is contained in:
parent
e162c674bf
commit
ff396e8ca2
6 changed files with 185 additions and 0 deletions
84
src/lib/components/custom/Views/AlbumView.svelte
Normal file
84
src/lib/components/custom/Views/AlbumView.svelte
Normal 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>
|
24
src/lib/components/custom/Views/PlaylistView.svelte
Normal file
24
src/lib/components/custom/Views/PlaylistView.svelte
Normal 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>
|
42
src/lib/components/custom/Views/ViewCard.svelte
Normal file
42
src/lib/components/custom/Views/ViewCard.svelte
Normal 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>
|
17
src/lib/components/custom/Views/views.svelte.ts
Normal file
17
src/lib/components/custom/Views/views.svelte.ts
Normal 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"
|
||||
}
|
7
src/lib/components/ui/skeleton/index.ts
Normal file
7
src/lib/components/ui/skeleton/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Root from "./skeleton.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Skeleton,
|
||||
};
|
11
src/lib/components/ui/skeleton/skeleton.svelte
Normal file
11
src/lib/components/ui/skeleton/skeleton.svelte
Normal 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>
|
Loading…
Reference in a new issue