Tags are now automatically extracted from #hashtags in content text. Removed TagInput from entry editing, keeping it only in FilterBar. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
80 lines
2.5 KiB
Svelte
80 lines
2.5 KiB
Svelte
<script lang="ts">
|
|
import { goto } from '$app/navigation';
|
|
import { page } from '$app/state';
|
|
import { get } from 'svelte/store';
|
|
import EntryList from '$lib/components/EntryList.svelte';
|
|
import QuickCapture from '$lib/components/QuickCapture.svelte';
|
|
import CompletedToggle from '$lib/components/CompletedToggle.svelte';
|
|
import SearchBar from '$lib/components/SearchBar.svelte';
|
|
import FilterBar from '$lib/components/FilterBar.svelte';
|
|
import { preferences } from '$lib/stores/preferences.svelte';
|
|
import { recentSearches, addRecentSearch } from '$lib/stores/recentSearches';
|
|
import { type SearchFilters, defaultFilters } from '$lib/types/search';
|
|
|
|
let { data } = $props();
|
|
|
|
// Search and filter state
|
|
let searchQuery = $state('');
|
|
let filters = $state<SearchFilters>({ ...defaultFilters });
|
|
|
|
// Sync filters.query with searchQuery
|
|
$effect(() => {
|
|
if (filters.query !== searchQuery) {
|
|
filters = { ...filters, query: searchQuery };
|
|
}
|
|
});
|
|
|
|
// Sync URL with preference on mount (client-side only)
|
|
$effect(() => {
|
|
if (typeof window !== 'undefined') {
|
|
const urlShowCompleted = page.url.searchParams.get('showCompleted') === 'true';
|
|
const prefShowCompleted = get(preferences).showCompleted;
|
|
|
|
// Only sync if different and not already matching
|
|
if (urlShowCompleted !== prefShowCompleted) {
|
|
const url = new URL(page.url);
|
|
if (prefShowCompleted) {
|
|
url.searchParams.set('showCompleted', 'true');
|
|
} else {
|
|
url.searchParams.delete('showCompleted');
|
|
}
|
|
goto(url.toString(), { replaceState: true, invalidateAll: true });
|
|
}
|
|
}
|
|
});
|
|
|
|
function handleFilterChange(newFilters: SearchFilters) {
|
|
filters = newFilters;
|
|
// Sync query back to searchQuery
|
|
if (newFilters.query !== searchQuery) {
|
|
searchQuery = newFilters.query;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>TaskPlaner</title>
|
|
</svelte:head>
|
|
|
|
<main class="min-h-screen bg-gray-50 pb-40">
|
|
<header class="bg-white border-b border-gray-200 sticky top-0 z-10">
|
|
<div class="max-w-2xl mx-auto px-4 py-4">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<h1 class="text-xl font-bold text-gray-900">TaskPlaner</h1>
|
|
<CompletedToggle />
|
|
</div>
|
|
<SearchBar bind:value={searchQuery} recentSearches={$recentSearches} />
|
|
</div>
|
|
</header>
|
|
|
|
<div class="max-w-2xl mx-auto px-4 py-3">
|
|
<FilterBar {filters} availableTags={data.allTags} onchange={handleFilterChange} />
|
|
</div>
|
|
|
|
<div class="max-w-2xl mx-auto px-4 py-4">
|
|
<EntryList entries={data.entries} {filters} {searchQuery} />
|
|
</div>
|
|
|
|
<QuickCapture />
|
|
</main>
|