style: collapse search bar into icon on mobile

On mobile, show a search icon that expands into a full-width search bar
with a back arrow to close. Desktop keeps the always-visible search bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Frederic Cabassut
2026-03-06 23:12:36 +01:00
co-authored by Claude Opus 4.6
parent 4b247b2627
commit 0a245672e1
3 changed files with 68 additions and 18 deletions
+35 -16
View File
@@ -2,32 +2,51 @@
import SearchBar from '../SearchBar.svelte';
import SyncIndicator from '../SyncIndicator.svelte';
import Menu from 'lucide-svelte/icons/menu';
import Search from 'lucide-svelte/icons/search';
interface Props {
onMenuToggle: () => void;
}
let { onMenuToggle }: Props = $props();
let mobileSearchOpen = $state(false);
</script>
<header class="sticky top-0 z-30 flex h-16 items-center gap-4 border-b border-[var(--border)] bg-[var(--bg-surface)] px-4">
<button
onclick={onMenuToggle}
class="rounded-sm p-2 hover:bg-[var(--border)]/10"
aria-label="Toggle sidebar"
>
<Menu class="h-6 w-6 text-[var(--text)]" />
</button>
{#if mobileSearchOpen}
<!-- Mobile expanded search -->
<div class="flex flex-1 items-center gap-2 lg:hidden">
<SearchBar onClose={() => (mobileSearchOpen = false)} />
</div>
{:else}
<button
onclick={onMenuToggle}
class="rounded-sm p-2 hover:bg-[var(--border)]/10"
aria-label="Toggle sidebar"
>
<Menu class="h-6 w-6 text-[var(--text)]" />
</button>
<div class="flex items-center gap-2">
<h1 class="font-['Press_Start_2P'] text-lg text-[var(--primary)]">Crumbs</h1>
</div>
<div class="flex items-center gap-2">
<h1 class="font-['Press_Start_2P'] text-lg text-[var(--primary)]">Crumbs</h1>
</div>
<div class="mx-4 flex-1">
<SearchBar />
</div>
<!-- Desktop search bar -->
<div class="mx-4 hidden flex-1 lg:block">
<SearchBar />
</div>
<div class="flex items-center gap-2">
<SyncIndicator />
</div>
<!-- Mobile search icon -->
<button
onclick={() => (mobileSearchOpen = true)}
class="ml-auto rounded-sm p-2 hover:bg-[var(--border)]/10 lg:hidden"
aria-label="Search"
>
<Search class="h-5 w-5 text-[var(--text)]" />
</button>
<div class="flex items-center gap-2">
<SyncIndicator />
</div>
{/if}
</header>
+26 -2
View File
@@ -3,10 +3,22 @@
import type { Note } from '$lib/types/index.js';
import Search from 'lucide-svelte/icons/search';
import X from 'lucide-svelte/icons/x';
import ArrowLeft from 'lucide-svelte/icons/arrow-left';
interface Props {
onClose?: () => void;
}
let { onClose }: Props = $props();
let query = $state('');
let originalNotes: Note[] = [];
let isSearching = $state(false);
let inputEl: HTMLInputElement | undefined = $state();
$effect(() => {
if (onClose) inputEl?.focus();
});
async function handleSearch() {
if (!query.trim()) {
@@ -36,12 +48,24 @@
isSearching = false;
}
}
function close() {
clearSearch();
onClose?.();
}
</script>
<div class="relative max-w-2xl">
<div class="relative flex-1 max-w-2xl">
<div class="flex items-center rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-base)] px-4 py-2 focus-within:border-[var(--primary)]">
<Search class="mr-3 h-5 w-5 text-[var(--text-muted)]" />
{#if onClose}
<button onclick={close} class="mr-2 text-[var(--text-muted)] hover:text-[var(--text)]" aria-label="Back">
<ArrowLeft class="h-5 w-5" />
</button>
{:else}
<Search class="mr-3 h-5 w-5 text-[var(--text-muted)]" />
{/if}
<input
bind:this={inputEl}
type="text"
placeholder="Search crumbs..."
bind:value={query}