fix(web): quick-capture docks above bottom nav, mutually exclusive with other sheets (BUG-1765) (#713)

The center + set captureOpen without closing the other nav surfaces and
wasn't a toggle, so tapping + with Search open stacked both sheets.
QuickCaptureSheet now presents as a DockedSheet (anchored above the nav,
like Workspace/You and the search palette) and BottomNav routes all four
surfaces through a shared closeAllSurfaces() so opening any one closes
the rest; a second tap on + collapses it and the slot lights while open.
This commit is contained in:
xarmian
2026-06-07 12:02:30 -04:00
committed by GitHub
parent ba734d55e7
commit 00d4fe066b
2 changed files with 54 additions and 18 deletions
+38 -15
View File
@@ -2,10 +2,11 @@
BottomNav — mobile-only persistent bottom navigation (PLAN-1694).
Five slots: Workspace · Search · Quick-capture (center ) · Activity · You.
"Workspace" and "You" open docked sheets (DockedSheet) that anchor ABOVE
this bar, so the nav stays visible and the active slot stays lit:
"Workspace", "You" and the center open docked sheets (DockedSheet) that
anchor ABOVE this bar, so the nav stays visible and the active slot stays lit:
- WorkspaceSheet — switcher card + Navigate + Collections.
- YouSheet — account (profile, theme, settings, sign out, …).
- QuickCaptureSheet — pick a collection, type a title, create (BUG-1765).
Together with the contextual bar they replace the retired mobile <TopBar />
inside a workspace (PLAN-1694 Phase 2-3, redesigned in TASK-1701).
@@ -38,27 +39,37 @@
let onWorkspaceContent = $derived(!!activeKey && activeKey !== 'activity');
// Tap toggles: a second tap on the active slot closes its surface. Opening
// any of the three surfaces (Workspace / You / Search) closes the others.
function toggleWorkspace() {
// any of the four surfaces (Workspace / You / Search / Quick-capture)
// closes the others (BUG-1765).
function closeAllSurfaces() {
workspaceOpen = false;
youOpen = false;
captureOpen = false;
uiStore.closeSearch();
workspaceOpen = !workspaceOpen;
}
function toggleWorkspace() {
const next = !workspaceOpen;
closeAllSurfaces();
workspaceOpen = next;
}
function toggleYou() {
workspaceOpen = false;
uiStore.closeSearch();
youOpen = !youOpen;
const next = !youOpen;
closeAllSurfaces();
youOpen = next;
}
function toggleSearch() {
if (uiStore.searchOpen) {
uiStore.closeSearch();
} else {
workspaceOpen = false;
youOpen = false;
const next = !uiStore.searchOpen;
closeAllSurfaces();
if (next) {
uiStore.openSearch();
uiStore.onNavigate();
}
}
function toggleCapture() {
const next = !captureOpen;
closeAllSurfaces();
captureOpen = next;
}
// Drive the .main-content reflow only while shown (mobile). app.css owns
// the media-gated padding rule.
@@ -101,9 +112,12 @@
<button
class="bn-item bn-capture"
class:active={captureOpen}
type="button"
onclick={() => (captureOpen = true)}
onclick={toggleCapture}
aria-label="Quick capture"
aria-haspopup="dialog"
aria-expanded={captureOpen}
>
<span class="bn-capture-plus" aria-hidden="true"></span>
</button>
@@ -112,7 +126,10 @@
class="bn-item"
class:active={activeKey === 'activity'}
href={`${wsPrefix}/activity`}
onclick={() => uiStore.onNavigate()}
onclick={() => {
closeAllSurfaces();
uiStore.onNavigate();
}}
>
<span class="bn-icon" aria-hidden="true">📋</span>
<span class="bn-label">Activity</span>
@@ -220,4 +237,10 @@
line-height: 1;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
/* Lit while its sheet is open — same ring the Workspace avatar uses. */
.bn-capture.active .bn-capture-plus {
box-shadow:
0 0 0 2px color-mix(in srgb, var(--accent-blue) 55%, transparent),
0 2px 8px rgba(0, 0, 0, 0.35);
}
</style>
@@ -6,6 +6,12 @@
mounted and renders a desktop-ish overlay (Codex review of PLAN-1694). The
create logic mirrors Sidebar.svelte's submitQuickAdd so behaviour (default
status, content template, navigate to the new item) stays consistent.
Presents as a DockedSheet (anchored above the bottom nav) like the
Workspace/You sheets, so the nav stays visible/tappable, the slot stays
lit, and BottomNav's mutual-exclusion toggles work symmetrically. It was
previously a full-screen common/BottomSheet that covered the nav and
stacked on top of an open Search/Workspace/You surface (BUG-1765).
-->
<script lang="ts">
import { goto } from '$app/navigation';
@@ -14,7 +20,7 @@
import { uiStore } from '$lib/stores/ui.svelte';
import { toastStore } from '$lib/stores/toast.svelte';
import { parseSchema, parseSettings, itemUrlId } from '$lib/types';
import BottomSheet from '$lib/components/common/BottomSheet.svelte';
import DockedSheet from '$lib/components/layout/DockedSheet.svelte';
let {
open,
@@ -107,8 +113,9 @@
}
</script>
<BottomSheet {open} onclose={close} title="Quick capture">
<DockedSheet {open} onclose={close} label="Quick capture">
<div class="capture">
<h2 class="capture-heading">Quick capture</h2>
<select class="capture-collection" bind:value={selectedSlug} aria-label="Collection">
{#each collections as c (c.id)}
<option value={c.slug}>{c.icon} {c.name}</option>
@@ -134,7 +141,7 @@
</button>
</div>
</div>
</BottomSheet>
</DockedSheet>
<style>
.capture {
@@ -143,6 +150,12 @@
gap: var(--space-3);
padding: 0 var(--space-5) var(--space-4);
}
.capture-heading {
margin: 0;
font-size: 1.05em;
font-weight: 600;
color: var(--text-primary);
}
.capture-collection {
appearance: none;
background: var(--bg-primary);