Feed: add custom date range (From/To) inputs alongside search bar
This commit is contained in:
@@ -42,6 +42,8 @@
|
||||
let datePre = 'all';
|
||||
let dateFrom = '';
|
||||
let dateTo = '';
|
||||
let customFrom = '';
|
||||
let customTo = '';
|
||||
let query = '';
|
||||
let shown = PAGE_SIZE;
|
||||
let loading = true;
|
||||
@@ -83,7 +85,8 @@
|
||||
return true;
|
||||
});
|
||||
$: allYears = [...new Set(all.map(a => a.started_at?.slice(0, 4)).filter(Boolean) as string[])].sort().reverse();
|
||||
$: ({ dateFrom, dateTo } = computeDateRange(datePre));
|
||||
$: dateFrom = (customFrom || customTo) ? customFrom : computeDateRange(datePre).dateFrom;
|
||||
$: dateTo = (customFrom || customTo) ? (customTo ? customTo + '' : '') : computeDateRange(datePre).dateTo;
|
||||
$: withDate = !dateFrom && !dateTo ? withPrivacy : withPrivacy.filter(a =>
|
||||
(!dateFrom || a.started_at >= dateFrom) && (!dateTo || a.started_at < dateTo)
|
||||
);
|
||||
@@ -126,7 +129,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: if (sport || datePre || query) shown = PAGE_SIZE; // reset pagination on filter change
|
||||
$: if (sport || datePre || query || customFrom || customTo) shown = PAGE_SIZE; // reset pagination on filter change
|
||||
|
||||
// When a search query is active, eagerly load all remaining shards so the
|
||||
// full history is searched (not just the initially-loaded recent year).
|
||||
@@ -153,18 +156,22 @@
|
||||
$: if (mounted) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (sport === 'all') params.delete('sport'); else params.set('sport', sport);
|
||||
if (datePre === 'all') params.delete('date'); else params.set('date', datePre);
|
||||
if (datePre === 'all' || customFrom || customTo) params.delete('date'); else params.set('date', datePre);
|
||||
if (!query.trim()) params.delete('q'); else params.set('q', query.trim());
|
||||
if (!customFrom) params.delete('from'); else params.set('from', customFrom);
|
||||
if (!customTo) params.delete('to'); else params.set('to', customTo);
|
||||
const qs = params.toString();
|
||||
history.replaceState(null, '', qs ? `?${qs}` : window.location.pathname);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
sport = (params.get('sport') as Sport | 'all') ?? 'all';
|
||||
datePre = params.get('date') ?? 'all';
|
||||
query = params.get('q') ?? '';
|
||||
mounted = true;
|
||||
sport = (params.get('sport') as Sport | 'all') ?? 'all';
|
||||
datePre = params.get('date') ?? 'all';
|
||||
query = params.get('q') ?? '';
|
||||
customFrom = params.get('from') ?? '';
|
||||
customTo = params.get('to') ?? '';
|
||||
mounted = true;
|
||||
|
||||
// Resolve the logged-in handle so we can show the owner their private activities.
|
||||
if ((window as any).__bincioMe !== undefined) {
|
||||
@@ -215,14 +222,34 @@
|
||||
];
|
||||
</script>
|
||||
|
||||
<!-- Search -->
|
||||
<div class="relative mb-4">
|
||||
<!-- Search + date range -->
|
||||
<div class="flex flex-col md:flex-row gap-2 mb-4">
|
||||
<input
|
||||
type="search"
|
||||
placeholder="Search activities…"
|
||||
bind:value={query}
|
||||
class="w-full px-4 py-2 rounded-lg bg-zinc-900 border border-zinc-700 text-white placeholder-zinc-500 text-sm focus:outline-none focus:border-zinc-500 transition-colors"
|
||||
class="flex-1 px-4 py-2 rounded-lg bg-zinc-900 border border-zinc-700 text-white placeholder-zinc-500 text-sm focus:outline-none focus:border-zinc-500 transition-colors"
|
||||
/>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex items-center gap-1.5 px-3 py-2 rounded-lg bg-zinc-900 border border-zinc-700 focus-within:border-zinc-500 transition-colors">
|
||||
<span class="text-xs text-zinc-500 whitespace-nowrap select-none">From</span>
|
||||
<input
|
||||
type="date"
|
||||
bind:value={customFrom}
|
||||
on:change={() => { datePre = 'all'; }}
|
||||
class="bg-transparent text-white text-sm focus:outline-none [color-scheme:dark]"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 px-3 py-2 rounded-lg bg-zinc-900 border border-zinc-700 focus-within:border-zinc-500 transition-colors">
|
||||
<span class="text-xs text-zinc-500 whitespace-nowrap select-none">To</span>
|
||||
<input
|
||||
type="date"
|
||||
bind:value={customTo}
|
||||
on:change={() => { datePre = 'all'; }}
|
||||
class="bg-transparent text-white text-sm focus:outline-none [color-scheme:dark]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sport filter bar -->
|
||||
@@ -254,14 +281,15 @@
|
||||
<!-- Date filter bar -->
|
||||
<div class="flex gap-2 mb-6 flex-wrap">
|
||||
{#each [{ value: 'all', label: 'All time' }, { value: '7d', label: '7 days' }, { value: '30d', label: '30 days' }, { value: '6mo', label: '6 months' }, ...allYears.map(y => ({ value: y, label: y }))] as d}
|
||||
{@const isActive = datePre === d.value && !customFrom && !customTo}
|
||||
<button
|
||||
class="px-3 py-1 rounded-full text-sm font-medium border transition-colors"
|
||||
class:border-zinc-700={datePre !== d.value}
|
||||
class:text-zinc-400={datePre !== d.value}
|
||||
class:border-[--accent]={datePre === d.value}
|
||||
class:text-white={datePre === d.value}
|
||||
style={datePre === d.value ? 'background:var(--accent-dim)' : ''}
|
||||
on:click={() => datePre = d.value}
|
||||
class:border-zinc-700={!isActive}
|
||||
class:text-zinc-400={!isActive}
|
||||
class:border-[--accent]={isActive}
|
||||
class:text-white={isActive}
|
||||
style={isActive ? 'background:var(--accent-dim)' : ''}
|
||||
on:click={() => { datePre = d.value; customFrom = ''; customTo = ''; }}
|
||||
>
|
||||
{d.label}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user