TirayaFrontend/src/lib/components/list/TrackListItem.svelte
2024-05-23 16:50:36 +02:00

206 lines
5.6 KiB
Svelte

<script lang="ts">
import { locale } from "$i18n/i18n-svelte";
import { mdiPlay, mdiDotsVertical } from "@mdi/js";
import { createContextMenu, createDropdownMenu, melt } from "@melt-ui/svelte";
import {
albumLink,
formatDateStr,
formatDate,
userLink,
formatDuration,
} from "$lib/util/functions";
import { mainPhone } from "$lib/stores/layout";
import { CTXMENU_CFG, DROPDOWN_CFG } from "$lib/util/constants";
import { ListView, type FilteredItem, type Track, Direction } from "$lib/util/types";
import Icon from "$lib/components/ui/Icon.svelte";
import AvatarBadge from "$lib/components/ui/AvatarBadge.svelte";
import IconPlaying from "$lib/components/ui/IconPlaying.svelte";
import LinkText from "$lib/components/ui/LinkText.svelte";
import TrackTitle from "./TrackTitle.svelte";
import TrackMenu from "$lib/components/contextmenu/TrackMenu.svelte";
export let track: FilteredItem<Track>;
export let view: ListView;
export let showAuthors: boolean;
export let trackIndex: number;
export let selected: boolean;
export let selectedAbv: boolean;
export let selectedBel: boolean;
export let showIcon: boolean;
export let selectedTracks: Track[];
export let rowid: string;
export let moveIndicator: Direction | null;
let rowElm: HTMLElement;
$: ctxTracks = selected ? selectedTracks : [track.item];
function playLabel(track: Track): string {
return track.artists[0]
? `Play ${track.name} by ${track.artists[0].name}`
: `Play ${track.name}`;
}
function playTrack(event: Event) {
alert("playing " + track.item.name);
event.stopPropagation();
}
// Temporary variables
let playingId = "yt:abc";
// Context menu
/*const onOpenChange: ChangeFn<boolean> = ({ next }) => {
if (next) {
if ($screenPhone) {
alert("TODO: bottom sheet");
return false;
}
}
return next;
};*/
const {
elements: { trigger: ctxTrigger, menu: ctxMenu, item: ctxItem },
builders: { createSubmenu: createCtxSubmenu },
states: { open: ctxOpen },
} = createContextMenu(CTXMENU_CFG);
const {
elements: { trigger: ddnTrigger, menu: ddnMenu, item: ddnItem },
builders: { createSubmenu: createDdnSubmenu },
states: { open: ddnOpen },
} = createDropdownMenu(DROPDOWN_CFG);
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
use:melt={$ctxTrigger}
class="row"
role="row"
aria-rowindex={trackIndex + 2}
class:selected
class:selected-abv={selectedAbv}
class:selected-bel={selectedBel}
class:show-icon={showIcon}
class:move-bef={moveIndicator === Direction.Backward}
class:move-aft={moveIndicator === Direction.Forward}
aria-selected={selected}
tabindex="-1"
draggable="true"
id={rowid}
bind:this={rowElm}
on:click
on:dragstart
on:dragover
on:dragleave
on:drop
>
<!-- Index column -->
<div class="col index" role="gridcell" aria-colindex={1}>
<button
class="index-btn"
aria-label={playLabel(track.item)}
tabindex="-1"
on:click={playTrack}
>
<Icon cls="play-icon" path={mdiPlay} size={1.4} />
<span class="index-nr">
{#if playingId === track.item.id}
<IconPlaying />
{:else}
{track.n}
{/if}
</span>
</button>
</div>
<!-- Cover/Title/Artist column -->
<div class="col first" role="gridcell" aria-colindex={2}>
<TrackTitle
track={track.item}
withCover={view !== ListView.Album}
markings={track.markings}
/>
</div>
<!-- Album column -->
{#if view > ListView.Album}
<div class="col var1" role="gridcell" aria-colindex={3}>
<LinkText
item={albumLink(track.item.album)}
marked={track.markings?.album}
tabindex={-1}
ol
/>
</div>
{/if}
<!-- Release date column -->
{#if view > ListView.Album}
<div class="col var2" role="gridcell" aria-colindex={4}>
{#if track.item.album.releaseDate}
<span class="ellipsis-ol">
{formatDateStr(track.item.album.releaseDate, $locale)}
</span>
{/if}
</div>
{/if}
<!-- Added date column -->
{#if view === ListView.Playlist}
<div class="col var3" role="gridcell" aria-colindex={5}>
{#if track.item.addedDate}
<span class="ellipsis-ol">
{formatDate(track.item.addedDate, $locale)}
</span>
{/if}
</div>
{/if}
<!-- Added by column -->
{#if showAuthors}
<div class="col var4" role="gridcell" aria-colindex={6}>
{#if track.item.addedBy}
<AvatarBadge
link={userLink(track.item.addedBy, true)}
imageUrl="https://secure.gravatar.com/avatar/7535c97c4fc2b39c8fcc3717efb96973?d=identicon&s=64"
tabindex={-1}
/>
{/if}
</div>
{/if}
<!-- Duration / context menu column -->
<div class="col last" role="gridcell" aria-colindex={7}>
<span class="ellipsis-ol text-sm text-base-content text-opacity-60">
{formatDuration(track.item.duration, $mainPhone)}
</span>
<span class="ddn-button">
<button
use:melt={$ddnTrigger}
class="btn btn-sm btn-ghost btn-circle"
aria-label="Track options"
tabindex="-1"
on:m-click={(e) => {
e.detail.originalEvent.stopPropagation();
}}
>
<Icon path={mdiDotsVertical} />
</button>
</span>
</div>
</div>
<TrackMenu
menu={$ctxMenu}
item={$ctxItem}
open={$ctxOpen}
createSubmenu={createCtxSubmenu}
tracks={ctxTracks}
playlistIndex={trackIndex}
on:moveTracks
/>
<TrackMenu
menu={$ddnMenu}
item={$ddnItem}
open={$ddnOpen}
createSubmenu={createDdnSubmenu}
tracks={ctxTracks}
playlistIndex={trackIndex}
on:moveTracks
/>