Changes
This commit is contained in:
Vendored
+1
-1
@@ -591,7 +591,7 @@ export interface components {
|
||||
};
|
||||
CreatePlayListRequest: {
|
||||
name: string;
|
||||
description: string;
|
||||
description: null | string;
|
||||
/** Format: uuid */
|
||||
pictureIntentId: null | string;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<div class="flex flex-col items-center gap-2.5 text-center" style="width:{size}px">
|
||||
<div
|
||||
class="relative grid shrink-0 place-items-center overflow-hidden rounded-full shadow-art ring-1 ring-line transition duration-300 ease-out ring-inset group-hover/artist:-translate-y-1 group-hover/artist:shadow-art-lg"
|
||||
class="relative grid shrink-0 place-items-center overflow-hidden rounded-full shadow-art ring-1 ring-line transition duration-300 ease-out ring-inset group-hover/artist:shadow-art-lg"
|
||||
style="width:{size}px;height:{size}px;background:{gradientForHue(hueFor(id))}"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" module>
|
||||
export const mediaCardArt =
|
||||
'aspect-square w-full rounded-art shadow-art transition duration-300 ease-out group-hover:-translate-y-1 group-hover:shadow-art-lg';
|
||||
'aspect-square w-full rounded-art shadow-art transition duration-300 ease-out group-hover:shadow-art-lg';
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import MixArt from './MixArt.svelte';
|
||||
import { hueFor } from '$lib/theme/color';
|
||||
import type { Mix } from '$lib/mixes';
|
||||
import Cover from './Cover.svelte';
|
||||
import { gradientForHue, hueFor } from '$lib/theme/color';
|
||||
import { mixItemKey, type Mix } from '$lib/mixes';
|
||||
|
||||
interface Props {
|
||||
mix: Mix;
|
||||
@@ -12,35 +12,53 @@
|
||||
}
|
||||
|
||||
let { mix, featured = false, banner = false, class: klass = '', index = 0 }: Props = $props();
|
||||
|
||||
const fillCount = $derived(banner ? 40 : 12);
|
||||
|
||||
const tiles = $derived.by(() => {
|
||||
if (mix.items.length === 0) return [];
|
||||
const out: Mix['items'] = [];
|
||||
while (out.length < fillCount) out.push(...mix.items);
|
||||
return out.slice(0, fillCount);
|
||||
});
|
||||
</script>
|
||||
|
||||
<a
|
||||
href="/mixes/{mix.id}"
|
||||
class="group/tile animate-enter relative block overflow-hidden rounded-art shadow-art ring-1 ring-line transition duration-300 ease-out ring-inset hover:shadow-art-lg focus-visible:ring-2 focus-visible:ring-accent focus-visible:outline-none {klass}"
|
||||
style="animation-delay:{Math.min(index, 10) * 45}ms"
|
||||
style="animation-delay:{Math.min(index, 10) * 45}ms;background:{gradientForHue(hueFor(mix.id))}"
|
||||
>
|
||||
<MixArt
|
||||
items={mix.items}
|
||||
hue={hueFor(mix.id)}
|
||||
class="absolute inset-0 h-full w-full transition duration-500 ease-out group-hover/tile:scale-[1.04]"
|
||||
/>
|
||||
{#if tiles.length > 0}
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0"
|
||||
style="background:linear-gradient(to top, rgba(0,0,0,0.78) 0%, rgba(0,0,0,0.32) 42%, rgba(0,0,0,0.05) 100%)"
|
||||
></div>
|
||||
class="absolute inset-0 flex transition duration-300 ease-out group-hover/tile:scale-[1.01]"
|
||||
>
|
||||
{#each tiles as item, i (i)}
|
||||
<Cover
|
||||
trackId={item.trackId ?? item.videoId ?? ''}
|
||||
src={item.thumbnailUrl}
|
||||
hue={hueFor(mixItemKey(item))}
|
||||
size="medium"
|
||||
class="aspect-square h-full shrink-0"
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0 bg-black/10 transition-colors duration-300 group-hover/tile:bg-black/20"
|
||||
></div>
|
||||
<div
|
||||
class="relative flex h-full flex-col justify-end p-3 sm:p-4 {banner
|
||||
class="group relative flex h-full flex-col justify-end p-3 sm:p-4 {banner
|
||||
? 'sm:flex-row sm:items-center sm:justify-between sm:gap-4'
|
||||
: ''}"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<div
|
||||
class="truncate font-semibold text-white {featured ? 'text-xl sm:text-2xl' : 'text-base'}"
|
||||
class="truncate text-white {featured ? 'text-xl sm:text-2xl' : 'text-base'} group-hover:text-accent-soft transition-colors"
|
||||
>
|
||||
{mix.title}
|
||||
</div>
|
||||
{#if mix.subtitle}
|
||||
<div class="mt-0.5 truncate text-xs text-white/70 sm:text-sm">{mix.subtitle}</div>
|
||||
<div class="mt-0.5 truncate text-xs text-muted sm:text-sm">{mix.subtitle}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
</script>
|
||||
|
||||
<span
|
||||
class="absolute right-2.5 bottom-2.5 grid h-11 w-11 translate-y-2 place-items-center rounded-full bg-accent-soft text-on-accent opacity-0 shadow-lg transition-all group-hover:translate-y-0 group-hover:opacity-100"
|
||||
class="absolute right-2.5 bottom-2.5 grid h-11 w-11 place-items-center rounded-full bg-accent-soft text-on-accent opacity-0 shadow-lg transition-opacity group-hover:opacity-100"
|
||||
class:!opacity-100={active}
|
||||
class:!translate-y-0={active}
|
||||
>
|
||||
{#if active && playing}
|
||||
<Pause class="h-5 w-5" fill="currentColor" />
|
||||
|
||||
@@ -11,12 +11,16 @@
|
||||
</script>
|
||||
|
||||
{#if actions}
|
||||
<div class="mb-3 flex items-baseline justify-between gap-4 sm:mb-4 {klass}">
|
||||
<h2 class="text-lg tracking-tight text-fg sm:text-[28px]">{title}</h2>
|
||||
<div class="mb-3 flex items-baseline justify-between gap-4 sm:mb-4 {klass} tracking-widest">
|
||||
<h2 class="font-display font-medium text-fg sm:text-xl">
|
||||
{title}
|
||||
</h2>
|
||||
{@render actions()}
|
||||
</div>
|
||||
{:else}
|
||||
<h2 class="mb-3 text-lg tracking-tight text-fg sm:mb-4 sm:text-[28px] {klass}">
|
||||
<h2
|
||||
class="mb-3 font-display font-medium text-fg sm:mb-4 sm:text-xl {klass}"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
{/if}
|
||||
|
||||
@@ -10,7 +10,6 @@ export const EXPLORE_ALBUMS_PAGE_SIZE = 10;
|
||||
export const HOME_LATEST_PAGE_SIZE = 10;
|
||||
export const HOME_ALBUMS_LIMIT = 12;
|
||||
export const HOME_MIXES_BENTO = 5;
|
||||
export const HOME_ARTISTS_LIMIT = 10;
|
||||
export const HOME_SHELF_LIMIT = 6;
|
||||
export const YOUTUBE_FILLER_LIMIT = 27;
|
||||
export const PLAYLIST_PICKER_PAGE_SIZE = 50;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
export interface HomeArtist {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const FILLER_ARTISTS = [
|
||||
'Nova Reyes',
|
||||
'The Paper Lanterns',
|
||||
'Kairo',
|
||||
'Lucía Marés',
|
||||
'Midnight Transit',
|
||||
'Sundown Kids',
|
||||
'Aria Volkov',
|
||||
'El Bosque Rojo',
|
||||
'Halcyon',
|
||||
'Marea Baja'
|
||||
];
|
||||
|
||||
export function pickTopArtists(tracks: { artist?: string | null }[], limit: number): HomeArtist[] {
|
||||
const seen = new Set<string>();
|
||||
const artists: HomeArtist[] = [];
|
||||
|
||||
for (const track of tracks) {
|
||||
for (const name of (track.artist ?? '').split(',').map((part) => part.trim())) {
|
||||
const key = name.toLowerCase();
|
||||
if (!name || seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
artists.push({ id: name, name });
|
||||
if (artists.length >= limit) return artists;
|
||||
}
|
||||
}
|
||||
|
||||
for (const name of FILLER_ARTISTS) {
|
||||
const key = name.toLowerCase();
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
artists.push({ id: name, name });
|
||||
if (artists.length >= limit) break;
|
||||
}
|
||||
|
||||
return artists;
|
||||
}
|
||||
@@ -5,9 +5,9 @@
|
||||
--mf-text: #c7c6c5;
|
||||
--mf-text-2: #a5a4a3;
|
||||
--mf-text-3: #8c8b8a;
|
||||
--mf-text-4: #7f7e7d;
|
||||
--mf-text-4: rgb(120, 120, 120);
|
||||
|
||||
--mf-surface: rgb(18, 18, 18);
|
||||
--mf-surface: rgb(15, 15, 15);
|
||||
--mf-surface-2: rgba(255, 255, 255, 0.06);
|
||||
--mf-surface-hover: rgba(255, 255, 255, 0.09);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user