Fix messy Stash header/toolbar layout on mobile

- Let the title badges (Encrypted · Syncs everywhere · sats) wrap
  gracefully instead of colliding with the toolbar controls
- Hide the list/grid view toggle on the empty state (nothing to toggle)
  so it no longer clutters the space next to the Add button
- Give the title row room to grow on mobile (min-h-14 + padding)
  instead of forcing everything into a fixed 56px row
- Make the search input flex-fill and shrink the category select on
  small screens so the filter bar no longer overflows
- Add aria-labels to the view-toggle buttons

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-09-02 19:17:40 +07:00
parent 955d5902d5
commit 9086123240

View file

@ -705,8 +705,8 @@ export default function StashPage() {
<div className="sticky top-0 z-30 bg-black/96 backdrop-blur-md border-b border-white/8">
<div className="container px-4 max-w-7xl">
{/* Title row */}
<div className="flex items-center justify-between h-14 gap-3">
<div className="flex items-center gap-3 min-w-0">
<div className="flex items-center justify-between min-h-14 py-2 gap-3">
<div className="flex items-center gap-3 min-w-0 flex-1">
<div className="relative flex-shrink-0">
<div className="w-9 h-9 rounded-xl bg-gradient-to-br from-[#ff6600] to-[#ff0040] flex items-center justify-center shadow-[0_0_16px_rgba(255,102,0,0.35)]">
<Backpack className="h-4 w-4 text-white" />
@ -717,26 +717,29 @@ export default function StashPage() {
</div>
)}
</div>
<div>
<div className="min-w-0">
<h1 className="text-lg font-black uppercase text-white leading-none tracking-tight">My Stash</h1>
<div className="flex items-center gap-2 mt-0.5">
<span className="flex items-center gap-1 text-[10px] text-green-400/80"><Shield className="h-2.5 w-2.5" />Encrypted</span>
<div className="flex items-center flex-wrap gap-x-2 gap-y-1 mt-1">
<span className="flex items-center gap-1 text-[10px] text-green-400/80 whitespace-nowrap"><Shield className="h-2.5 w-2.5 flex-shrink-0" />Encrypted</span>
<span className="text-white/15 text-[10px]">·</span>
<span className="text-[10px] text-[#ccff00]/70">Syncs everywhere</span>
<span className="text-[10px] text-[#ccff00]/70 whitespace-nowrap">Syncs everywhere</span>
{stats.totalValue > 0 && (
<><span className="text-white/15 text-[10px]">·</span>
<span className="flex items-center gap-0.5 text-[10px] text-amber-400/80"><Zap className="h-2.5 w-2.5" />{stats.totalValue > 999 ? Math.floor(stats.totalValue / 1000) + 'k' : stats.totalValue} sats</span></>
<span className="flex items-center gap-0.5 text-[10px] text-amber-400/80 whitespace-nowrap"><Zap className="h-2.5 w-2.5 flex-shrink-0" />{stats.totalValue > 999 ? Math.floor(stats.totalValue / 1000) + 'k' : stats.totalValue} sats</span></>
)}
</div>
</div>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
<div className="flex items-center rounded-lg border border-white/10 overflow-hidden">
<button onClick={() => setViewMode('list')} className={cn('px-2.5 py-1.5 transition-colors', viewMode === 'list' ? 'bg-white/12 text-white' : 'text-gray-600 hover:text-gray-300')}><List className="h-3.5 w-3.5" /></button>
<button onClick={() => setViewMode('grid')} className={cn('px-2.5 py-1.5 transition-colors', viewMode === 'grid' ? 'bg-white/12 text-white' : 'text-gray-600 hover:text-gray-300')}><LayoutGrid className="h-3.5 w-3.5" /></button>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
{/* View toggle — only useful when there are items to view */}
{stats.total > 0 && (
<div className="flex items-center rounded-lg border border-white/10 overflow-hidden">
<button aria-label="List view" onClick={() => setViewMode('list')} className={cn('px-2.5 py-1.5 transition-colors', viewMode === 'list' ? 'bg-white/12 text-white' : 'text-gray-600 hover:text-gray-300')}><List className="h-3.5 w-3.5" /></button>
<button aria-label="Grid view" onClick={() => setViewMode('grid')} className={cn('px-2.5 py-1.5 transition-colors', viewMode === 'grid' ? 'bg-white/12 text-white' : 'text-gray-600 hover:text-gray-300')}><LayoutGrid className="h-3.5 w-3.5" /></button>
</div>
)}
{/* Mobile-only quick add — desktop has sidebar buttons */}
<div className="flex sm:hidden gap-1.5">
<div className="flex sm:hidden">
<AddItemDialog onAdd={(item) => addItem.mutate(item)} mode="stash" />
</div>
</div>
@ -763,12 +766,12 @@ export default function StashPage() {
{/* ── Filter bar ── */}
<div className="border-b border-white/6 bg-black/40">
<div className="container px-4 max-w-7xl py-2 flex items-center gap-2 flex-wrap">
<div className="relative w-44 flex-shrink-0">
<div className="relative flex-1 min-w-[140px] sm:flex-none sm:w-44">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-gray-600 pointer-events-none" />
<Input placeholder="Search..." value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} className="pl-8 h-8 bg-white/4 border-white/8 text-sm placeholder:text-gray-600 focus:border-[#ff6600]/50" />
</div>
<Select value={filterCategory} onValueChange={setFilterCategory}>
<SelectTrigger className="w-[140px] h-8 bg-white/4 border-white/8 text-sm flex-shrink-0"><SelectValue placeholder="All categories" /></SelectTrigger>
<SelectTrigger className="w-[130px] sm:w-[140px] h-8 bg-white/4 border-white/8 text-sm flex-shrink-0"><SelectValue placeholder="All categories" /></SelectTrigger>
<SelectContent>
<SelectItem value="all">All categories</SelectItem>
{Object.entries(STASH_CATEGORIES).map(([key, cat]) => <SelectItem key={key} value={key}>{cat.emoji} {cat.label}</SelectItem>)}