list page pt. 10 song entry component
This commit is contained in:
87
src/lib/components/SongEntry.svelte
Normal file
87
src/lib/components/SongEntry.svelte
Normal file
@@ -0,0 +1,87 @@
|
||||
<script lang="ts">
|
||||
type SongType = 1 | 2 | 3 | number;
|
||||
|
||||
type SongEntryProps = {
|
||||
animeName: string;
|
||||
type: SongType;
|
||||
number: number;
|
||||
songName: string;
|
||||
artistName: string | null;
|
||||
fileName?: string | null;
|
||||
showPlayer?: boolean;
|
||||
};
|
||||
|
||||
let {
|
||||
animeName,
|
||||
type,
|
||||
number,
|
||||
songName,
|
||||
artistName,
|
||||
fileName = null,
|
||||
showPlayer = false,
|
||||
}: SongEntryProps = $props();
|
||||
|
||||
const typeLabelMap: Record<number, string> = {
|
||||
1: "OP",
|
||||
2: "ED",
|
||||
3: "INS",
|
||||
};
|
||||
|
||||
const typeLabel = $derived(typeLabelMap[type] ?? `T${type}`);
|
||||
|
||||
const displayTypeNumber = $derived.by(() => {
|
||||
const num = Number(number);
|
||||
if (!Number.isFinite(num) || num === 0) return typeLabel;
|
||||
return `${typeLabel}${num}`;
|
||||
});
|
||||
|
||||
const artistDisplay = $derived.by(
|
||||
() => artistName?.trim() || "Unknown Artist",
|
||||
);
|
||||
|
||||
const mediaTitle = $derived.by(() => `${animeName} — ${displayTypeNumber}`);
|
||||
|
||||
const mediaArtist = $derived.by(() => artistDisplay);
|
||||
|
||||
const mediaAlbum = $derived.by(() => `${animeName} (${displayTypeNumber})`);
|
||||
|
||||
$effect(() => {
|
||||
if (!showPlayer || !fileName) return;
|
||||
if (typeof navigator === "undefined") return;
|
||||
const mediaSession = navigator.mediaSession;
|
||||
if (!mediaSession || typeof MediaMetadata === "undefined") return;
|
||||
|
||||
mediaSession.metadata = new MediaMetadata({
|
||||
title: songName,
|
||||
artist: mediaArtist,
|
||||
album: mediaAlbum,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="rounded border px-3 py-2">
|
||||
<div class="flex flex-wrap items-baseline gap-x-2 gap-y-1">
|
||||
<span class="text-sm text-muted-foreground">{animeName}</span>
|
||||
<span class="text-sm text-muted-foreground">•</span>
|
||||
<span class="text-sm text-muted-foreground">{displayTypeNumber}</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-1 font-medium">
|
||||
{songName}
|
||||
<span class="text-sm text-muted-foreground">— {artistDisplay}</span>
|
||||
</div>
|
||||
|
||||
{#if showPlayer && fileName}
|
||||
<div class="mt-2">
|
||||
<audio
|
||||
class="w-full"
|
||||
controls
|
||||
preload="metadata"
|
||||
title={`${mediaTitle} — ${songName} — ${mediaArtist}`}
|
||||
>
|
||||
<source src={`/cdn/${fileName}`} type="audio/mpeg" />
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -3,6 +3,7 @@
|
||||
import { onMount } from "svelte";
|
||||
import { z } from "zod";
|
||||
import { invalidate } from "$app/navigation";
|
||||
import SongEntry from "$lib/components/SongEntry.svelte";
|
||||
import { db as clientDb } from "$lib/db/client-db";
|
||||
import {
|
||||
MalAnimeListQuerySchema,
|
||||
@@ -146,32 +147,16 @@
|
||||
|
||||
<ul class="mt-3 space-y-2">
|
||||
{#each data.songRows as r (String(r.annId) + ":" + String(r.annSongId))}
|
||||
<li class="rounded border px-3 py-2">
|
||||
<div class="font-medium">
|
||||
{r.songName}
|
||||
{#if songArtistLabel(r)}
|
||||
<span class="text-sm text-muted-foreground">
|
||||
— {songArtistLabel(r)}</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-muted-foreground">
|
||||
{r.animeName} • ANN {r.annId} • MAL {r.malId} • link type {r.type} #{r.number}
|
||||
</div>
|
||||
|
||||
{#if r.fileName}
|
||||
<div class="mt-2 text-sm">
|
||||
<a
|
||||
class="hover:underline"
|
||||
href={"https://nawdist.animemusicquiz.com/" + r.fileName}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Audio file
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
<li>
|
||||
<SongEntry
|
||||
animeName={r.animeName}
|
||||
type={r.type}
|
||||
number={r.number}
|
||||
songName={r.songName}
|
||||
artistName={songArtistLabel(r)}
|
||||
fileName={r.fileName}
|
||||
showPlayer={true}
|
||||
/>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user