feat(frontend): search tracks live as you type on explore page
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Search from '@lucide/svelte/icons/search';
|
import Search from '@lucide/svelte/icons/search';
|
||||||
import Music from '@lucide/svelte/icons/music';
|
import Music from '@lucide/svelte/icons/music';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
import { player } from '$lib/player/player.svelte';
|
import { player } from '$lib/player/player.svelte';
|
||||||
import Cover from '$lib/components/ui/Cover.svelte';
|
import Cover from '$lib/components/ui/Cover.svelte';
|
||||||
import { HUES } from '$lib/theme/color';
|
import { HUES } from '$lib/theme/color';
|
||||||
@@ -13,6 +14,19 @@
|
|||||||
|
|
||||||
const dateFormatter = new Intl.DateTimeFormat('es', { dateStyle: 'medium' });
|
const dateFormatter = new Intl.DateTimeFormat('es', { dateStyle: 'medium' });
|
||||||
|
|
||||||
|
let searchTimeout: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
|
function onSearchInput(event: Event) {
|
||||||
|
const value = (event.currentTarget as HTMLInputElement).value;
|
||||||
|
clearTimeout(searchTimeout);
|
||||||
|
searchTimeout = setTimeout(() => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (value.trim()) params.set('q', value.trim());
|
||||||
|
const qs = params.toString();
|
||||||
|
goto(qs ? `/explore?${qs}` : '/explore', { keepFocus: true, replaceState: true, noScroll: true });
|
||||||
|
}, 350);
|
||||||
|
}
|
||||||
|
|
||||||
function hueFor(id: string) {
|
function hueFor(id: string) {
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
||||||
@@ -43,29 +57,19 @@
|
|||||||
<h1 class="font-display text-3xl font-bold tracking-tight sm:text-4xl">Explorar</h1>
|
<h1 class="font-display text-3xl font-bold tracking-tight sm:text-4xl">Explorar</h1>
|
||||||
<p class="mt-2 text-neutral-400">Descubre canciones o busca por nombre.</p>
|
<p class="mt-2 text-neutral-400">Descubre canciones o busca por nombre.</p>
|
||||||
|
|
||||||
<form method="GET" class="mt-8 flex gap-3">
|
<div class="relative mt-8 max-w-xl">
|
||||||
<div class="relative flex-1">
|
<span class="pointer-events-none absolute inset-y-0 left-4 grid place-items-center text-neutral-500">
|
||||||
<span
|
|
||||||
class="pointer-events-none absolute inset-y-0 left-4 grid place-items-center text-neutral-500"
|
|
||||||
>
|
|
||||||
<Search class="h-4 w-4" />
|
<Search class="h-4 w-4" />
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
name="q"
|
|
||||||
value={data.query}
|
value={data.query}
|
||||||
|
oninput={onSearchInput}
|
||||||
placeholder="Buscar por nombre…"
|
placeholder="Buscar por nombre…"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="w-full rounded-lg border border-white/15 bg-neutral-950 py-3 pl-11 pr-4 text-sm text-neutral-100 placeholder:text-neutral-500 focus:border-emerald-500/60 focus:outline-none"
|
class="w-full rounded-lg border border-white/15 bg-neutral-950 py-3 pl-11 pr-4 text-sm text-neutral-100 placeholder:text-neutral-500 focus:border-emerald-500/60 focus:outline-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="rounded-lg bg-[var(--mf-accent)] px-6 py-3 text-sm font-semibold text-neutral-950 backdrop-blur-md transition hover:brightness-110 hover:shadow-[0_8px_24px_-8px] active:scale-[0.97]"
|
|
||||||
>
|
|
||||||
Buscar
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p class="mt-6 text-sm text-neutral-500">
|
<p class="mt-6 text-sm text-neutral-500">
|
||||||
{#if data.query}
|
{#if data.query}
|
||||||
|
|||||||
Reference in New Issue
Block a user