M12 — the Android client, end to end #2

Merged
bvandeusen merged 86 commits from dev into main 2026-08-21 08:53:58 -04:00
4 changed files with 55 additions and 6 deletions
Showing only changes of commit c8c8ec4b4e - Show all commits
+47
View File
@@ -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<string>(() => {
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() {
<span class="hidden font-semibold sm:inline">{{ config.siteName }}</span>
</RouterLink>
<!-- The active lens, named in the persistent chrome rather than inside each
view. Which lens you're looking at is a property of the SPACE, not of a
page you navigated to — so it sits in the bar that never moves, beside
the app name, and stays in one place while everything beneath it
re-filters. Replaces the per-view <h1>s, which sat in a different spot
in each view and were absent entirely on the board and in search. -->
<span aria-live="polite" class="flex min-w-0 shrink items-center gap-2 text-sm text-neutral-400">
<!-- The separator only makes sense next to the app name, which is itself
hidden on narrow screens. There, the lens name simply takes the space
the app name vacated — you already know which app you're in. -->
<span aria-hidden="true" class="hidden sm:inline">/</span>
<span class="truncate font-medium text-neutral-600 dark:text-neutral-300">{{ lensName }}</span>
</span>
<div class="flex flex-1 justify-center">
<input
ref="searchInput"
+2 -2
View File
@@ -304,8 +304,8 @@ onBeforeUnmount(() => {
<template>
<div class="flex h-full flex-col p-4">
<div class="mb-3 flex flex-wrap items-center justify-between gap-3">
<h1 class="text-lg font-semibold">Graph</h1>
<!-- Titled by the shell's persistent lens name (task 1913). -->
<div class="mb-3 flex flex-wrap items-center justify-end gap-3">
<div class="flex items-center gap-3 text-sm">
<label class="flex cursor-pointer items-center gap-1.5 text-neutral-600 dark:text-neutral-300">
<input type="checkbox" class="accent-brand" :checked="showLabels" @change="toggleLabels" />
+2 -2
View File
@@ -33,8 +33,8 @@ onMounted(load);
<template>
<div class="mx-auto w-full max-w-2xl px-4 py-6">
<div class="mb-2 flex items-center justify-between gap-3">
<h1 class="text-lg font-semibold">Reminders</h1>
<!-- Titled by the shell's persistent lens name (task 1913). -->
<div class="mb-2 flex items-center justify-end gap-3">
<button
v-if="reminders.osSupported && !reminders.osEnabled"
type="button"
+4 -2
View File
@@ -102,8 +102,10 @@ onMounted(load);
<template>
<div class="mx-auto w-full max-w-6xl px-4 py-6">
<div class="mb-1 flex flex-wrap items-center justify-between gap-3">
<h1 class="text-lg font-semibold">Timeline</h1>
<!-- No <h1> here: the shell's persistent bar names the active lens (task 1913),
so a per-view title would say the same thing twice, in a place that scrolls
away. -->
<div class="mb-1 flex flex-wrap items-center justify-end gap-3">
<div class="flex flex-wrap items-center gap-2 text-sm">
<label class="flex items-center gap-1.5 text-neutral-500 dark:text-neutral-400">
<span>From</span>