feat(ui): add page decoration component for collection views

This commit is contained in:
2025-10-04 22:25:07 -04:00
parent 7b84bc32df
commit c30b205d9c
5 changed files with 82 additions and 1 deletions

View File

@@ -3,6 +3,7 @@
import { convertFileSrc } from '@tauri-apps/api/core';
import { playback } from '$lib/stores/playback';
import ContextMenu, { type MenuItem } from '$lib/components/ContextMenu.svelte';
import PageDecoration from '$lib/components/PageDecoration.svelte';
interface Props {
title: string;
@@ -14,6 +15,7 @@
onTrackClick?: (index: number) => void;
showAlbumColumn?: boolean;
useSequentialNumbers?: boolean;
decorationLabel?: string;
}
let {
@@ -25,7 +27,8 @@
selectedTrackIndex = null,
onTrackClick,
showAlbumColumn = false,
useSequentialNumbers = false
useSequentialNumbers = false,
decorationLabel = 'LOCAL PLAYLIST'
}: Props = $props();
let contextMenu = $state<{ x: number; y: number; trackIndex: number } | null>(null);
@@ -75,6 +78,8 @@
}
</script>
<PageDecoration label={decorationLabel} />
<!-- Header -->
<div class="collection-header">
{#if coverArtPath}

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import type { Track } from '$lib/types/track';
import PageDecoration from '$lib/components/PageDecoration.svelte';
interface Props {
title: string;
@@ -64,6 +65,8 @@
}
</script>
<PageDecoration label="DEEZER PLAYLIST" />
<!-- Header -->
<div class="collection-header">
{#if coverImageUrl}

View File

@@ -0,0 +1,61 @@
<script lang="ts">
interface Props {
label: string;
}
let { label }: Props = $props();
// Calculate width based on text length (approximate monospace character width)
let labelWidth = $derived(label.length * 7 + 26); // ~7px per char + padding
</script>
<div class="page-decoration">
<div class="decoration-left" style="width: {labelWidth}px;"></div>
<!-- vector from /static/vectors/title-decoration.svg -->
<svg class="decoration-transition" viewBox="0 0 64 32" preserveAspectRatio="none">
<path d="M64,0H0v32h21.634c3.056-9.369,6.236-15.502,19.82-17.258,2.105-.272,4.23-.37,6.352-.37h16.193V0Z"/>
</svg>
<div class="decoration-right"></div>
<div class="decoration-label">//{label}//</div>
</div>
<style>
.page-decoration {
position: relative;
height: 20px;
display: flex;
align-items: stretch;
margin-bottom: 4px;
flex-shrink: 0;
}
.decoration-left {
flex-shrink: 0;
background: #373737;
}
.decoration-transition {
flex-shrink: 0;
width: 40px;
height: 20px;
fill: #373737;
}
.decoration-right {
flex: 1;
background: linear-gradient(to bottom, #373737 0%, #373737 9.184px, transparent 9.184px);
}
.decoration-label {
position: absolute;
left: 8px;
top: 50%;
transform: translateY(-50%);
color: #ffffff;
font-family: monospace;
font-size: 11px;
font-weight: bold;
letter-spacing: 0.5px;
pointer-events: none;
}
</style>

View File

@@ -79,6 +79,7 @@
{selectedTrackIndex}
onTrackClick={handleTrackClick}
showAlbumColumn={false}
decorationLabel="ALBUM OVERVIEW"
/>
{/if}
</div>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 32">
<defs>
<style>
.cls-1 {
fill: #373737;
}
</style>
</defs>
<path class="cls-1" d="M64,0H0v32h21.634c3.056-9.369,6.236-15.502,19.82-17.258,2.105-.272,4.23-.37,6.352-.37h16.193V0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 353 B