From c8c8ec4b4ef1707d15453054c809d42adcc85788 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 17 Aug 2026 13:49:27 -0400 Subject: [PATCH] frontend: the shell names the active lens (task 1913) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Which lens you're looking at is a property of the space, not of a page you navigated to — so the name now sits in the bar that never moves, beside the app name, and stays put while everything beneath it re-filters. It replaces three per-view

s that each sat in a different place with slightly different markup (timeline, reminders, graph) and, more to the point, were absent entirely on the board and in search — the two lenses people spend the most time in had no name at all. A label lens is named by the label itself, because "Groceries" is what the user came looking for and "Label" tells them nothing. Shown at every width rather than hidden on small screens, which was my first cut and would have been a regression: deleting the per-view titles while hiding the shell one leaves a phone with no lens name anywhere, and Android is a peer surface now. Below `sm` the app name is already hidden, so the lens name simply takes the space it vacates — you know which app you're in; what you need is which lens. The h1s on Settings, Sync, Account, Login and Register are untouched: those routes render outside the shell entirely, so they have no chrome to be named by. Co-Authored-By: Claude Opus 5 (1M context) --- frontend/src/components/AppShell.vue | 47 ++++++++++++++++++++++++++++ frontend/src/views/GraphView.vue | 4 +-- frontend/src/views/RemindersView.vue | 4 +-- frontend/src/views/TimelineView.vue | 6 ++-- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/AppShell.vue b/frontend/src/components/AppShell.vue index 1b6c184..fb3fd47 100644 --- a/frontend/src/components/AppShell.vue +++ b/frontend/src/components/AppShell.vue @@ -202,6 +202,39 @@ watch( }, ); +/** + * What to call the lens currently in view. + * + * Keyed off the route name rather than each view declaring its own title, so the + * label sits in one place and can't go missing (the board and search never had one) + * or drift in styling (timeline, reminders and graph each had their own h1). + * + * A label lens is named by the label itself — "Groceries" is what the user came + * looking for; "Label" would tell them nothing they didn't already know. + */ +const lensName = computed(() => { + switch (route.name) { + case "archive": + return "Archive"; + case "trash": + return "Trash"; + case "search": + return "Search"; + case "timeline": + return "Timeline"; + case "reminders": + return "Reminders"; + case "graph": + return "Graph"; + case "label": + // The store may not have loaded yet on a deep link; fall back rather than + // flashing an empty slot. + return labels.items.find((l) => l.id === String(route.params.id))?.name ?? "Label"; + default: + return "Notes"; + } +}); + async function signOut() { await session.logout(); await router.replace("/login"); @@ -248,6 +281,20 @@ async function signOut() { + + + + + {{ lensName }} + +
{