mirror of
https://github.com/markuryy/shark.git
synced 2025-12-12 11:41:02 +00:00
feat(ui): add page decoration component for collection views
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||||
import { playback } from '$lib/stores/playback';
|
import { playback } from '$lib/stores/playback';
|
||||||
import ContextMenu, { type MenuItem } from '$lib/components/ContextMenu.svelte';
|
import ContextMenu, { type MenuItem } from '$lib/components/ContextMenu.svelte';
|
||||||
|
import PageDecoration from '$lib/components/PageDecoration.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
onTrackClick?: (index: number) => void;
|
onTrackClick?: (index: number) => void;
|
||||||
showAlbumColumn?: boolean;
|
showAlbumColumn?: boolean;
|
||||||
useSequentialNumbers?: boolean;
|
useSequentialNumbers?: boolean;
|
||||||
|
decorationLabel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -25,7 +27,8 @@
|
|||||||
selectedTrackIndex = null,
|
selectedTrackIndex = null,
|
||||||
onTrackClick,
|
onTrackClick,
|
||||||
showAlbumColumn = false,
|
showAlbumColumn = false,
|
||||||
useSequentialNumbers = false
|
useSequentialNumbers = false,
|
||||||
|
decorationLabel = 'LOCAL PLAYLIST'
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
let contextMenu = $state<{ x: number; y: number; trackIndex: number } | null>(null);
|
let contextMenu = $state<{ x: number; y: number; trackIndex: number } | null>(null);
|
||||||
@@ -75,6 +78,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<PageDecoration label={decorationLabel} />
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="collection-header">
|
<div class="collection-header">
|
||||||
{#if coverArtPath}
|
{#if coverArtPath}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Track } from '$lib/types/track';
|
import type { Track } from '$lib/types/track';
|
||||||
|
import PageDecoration from '$lib/components/PageDecoration.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -64,6 +65,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<PageDecoration label="DEEZER PLAYLIST" />
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="collection-header">
|
<div class="collection-header">
|
||||||
{#if coverImageUrl}
|
{#if coverImageUrl}
|
||||||
|
|||||||
61
src/lib/components/PageDecoration.svelte
Normal file
61
src/lib/components/PageDecoration.svelte
Normal 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>
|
||||||
@@ -79,6 +79,7 @@
|
|||||||
{selectedTrackIndex}
|
{selectedTrackIndex}
|
||||||
onTrackClick={handleTrackClick}
|
onTrackClick={handleTrackClick}
|
||||||
showAlbumColumn={false}
|
showAlbumColumn={false}
|
||||||
|
decorationLabel="ALBUM OVERVIEW"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
11
static/vectors/title-decoration.svg
Normal file
11
static/vectors/title-decoration.svg
Normal 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 |
Reference in New Issue
Block a user