From 715b648b95c0f07d14d4f498077751f1bcc83daf Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 21 Oct 2026 20:17:13 -0400 Subject: [PATCH] Web client comments describe the code to a stranger (#6222) Milestone 546 "Bring the repo to the comment standard (rule 32) and compose defaults (rule 198)", step #6222 "Comment standard sweep: web client (frontend/)". Comments, docstrings and template notes across frontend/ now say what the code does and the non-obvious why as present-tense facts. Issue, task, note, milestone and family-idea references are gone, along with narration of what used to happen: the titles index's wiki-link origin and its once-per-session load (#5165), the card-controls overlap a phone showed (task 2697), the M7 and M10.9 labels, and the card unification behind the reminders lens (task 1913). Hazards stay as facts, among them LEAVE_MS matching the editor's leave duration, the Android client twin that must not be widened, and keeping leavers in flow in the multi-column masonry. 62 files, comments only: a comment-stripping diff of every changed file against HEAD is identical. Co-Authored-By: Claude Opus 5.5 --- frontend/index.html | 9 +- frontend/public/sw.js | 13 +- frontend/src/adapters/local.ts | 15 +- frontend/src/adapters/repo.ts | 18 +-- frontend/src/adapters/rest.ts | 12 +- frontend/src/components/AccountList.vue | 6 +- frontend/src/components/ActivityList.vue | 2 +- frontend/src/components/AppShell.vue | 125 +++++---------- frontend/src/components/AsyncState.vue | 2 +- frontend/src/components/BackupPanel.vue | 2 +- frontend/src/components/BaseButton.vue | 7 +- frontend/src/components/BaseModal.vue | 25 ++- frontend/src/components/ClientDownloads.vue | 48 ++---- frontend/src/components/DesktopMenuEntry.vue | 5 +- frontend/src/components/GroupList.vue | 2 +- frontend/src/components/Icon.vue | 2 +- frontend/src/components/InviteList.vue | 4 +- frontend/src/components/MarkdownInline.vue | 11 +- frontend/src/components/MarkdownText.vue | 6 +- frontend/src/components/NoteActions.vue | 2 +- frontend/src/components/NoteCard.vue | 159 ++++++------------- frontend/src/components/NoteEditor.vue | 104 +++++------- frontend/src/components/NoteGrid.vue | 19 +-- frontend/src/components/OneTimeSecret.vue | 2 +- frontend/src/components/ScrollSentinel.vue | 2 +- frontend/src/components/ShareDialog.vue | 4 +- frontend/src/composables/useCardDrag.ts | 19 +-- frontend/src/composables/useEditorMorph.ts | 22 +-- frontend/src/composables/useLensName.ts | 9 +- frontend/src/composables/useNoteEditor.ts | 9 +- frontend/src/composables/useNoteList.ts | 6 +- frontend/src/composables/usePageTitle.ts | 7 +- frontend/src/composables/useReducedMotion.ts | 12 +- frontend/src/desktop/bridge.ts | 27 ++-- frontend/src/notes/attachments.ts | 4 +- frontend/src/notes/blocks.ts | 39 ++--- frontend/src/notes/colors.ts | 92 ++++------- frontend/src/notes/datetime.ts | 9 +- frontend/src/notes/facets.test.ts | 4 +- frontend/src/notes/grammar.test.ts | 4 +- frontend/src/notes/links.ts | 2 +- frontend/src/notes/markdown.ts | 31 ++-- frontend/src/notes/recentTags.ts | 2 +- frontend/src/notes/sharing.ts | 2 +- frontend/src/notes/tags.ts | 2 +- frontend/src/router/index.ts | 30 ++-- frontend/src/stores/config.ts | 27 ++-- frontend/src/stores/labels.ts | 10 +- frontend/src/stores/notes.ts | 6 +- frontend/src/stores/reminders.ts | 14 +- frontend/src/stores/titles.test.ts | 2 - frontend/src/stores/titles.ts | 14 +- frontend/src/stores/ui.ts | 2 +- frontend/src/style.css | 124 ++++++--------- frontend/src/views/AccountView.vue | 4 +- frontend/src/views/BoardView.vue | 8 +- frontend/src/views/ForgotPasswordView.vue | 2 +- frontend/src/views/LoginView.vue | 2 +- frontend/src/views/RemindersView.vue | 16 +- frontend/src/views/ResetPasswordView.vue | 4 +- frontend/src/views/SyncView.vue | 6 +- frontend/src/views/TimelineView.vue | 5 +- 62 files changed, 411 insertions(+), 773 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 3ab5f16..5dd3c48 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,12 +2,9 @@ - + label_ids). A few operations have no offline meaning -// yet (account auth, device linking) — those reject with a clear message -// rather than silently failing; the board, editor, attachments, capture, filters, -// labels, checklists, reminders, import and export all work fully offline. +// parameters (labelIds -> label_ids). Operations with no offline meaning (account +// auth, device linking) reject with a clear message. import { invoke } from "../desktop/bridge"; import type { Note, NoteRevision } from "../stores/notes"; @@ -58,7 +55,7 @@ export const local: Repo = { snoozeReminder: (id, minutes) => invoke("notes_snooze_reminder", { id, minutes }), setLabels: (id, labelIds) => invoke("notes_set_labels", { id, labelIds }), updateItem: (id, itemId, changes) => invoke("notes_update_item", { id, itemId, changes }), - // Kept on this device and uploaded by the next sync once linked (#5168). The bytes + // Kept on this device and uploaded by the next sync once linked. The bytes // go as the raw IPC body; the name is percent-encoded because a header carries // only ASCII. uploadAttachment: async (id, file) => @@ -91,7 +88,7 @@ export const local: Repo = { sendTestEmail: () => Promise.reject<{ to: string }>(new Error(NEEDS_SERVER)), }, - // Sharing is between accounts on a server, so these go to the linked one (#5175). + // Sharing is between accounts on a server, so these go to the linked one. // Unlinked, each rejects with the core's explanation, which the dialog shows. shares: { directory: () => invoke("shares_directory"), diff --git a/frontend/src/adapters/repo.ts b/frontend/src/adapters/repo.ts index f402716..bc10616 100644 --- a/frontend/src/adapters/repo.ts +++ b/frontend/src/adapters/repo.ts @@ -1,13 +1,9 @@ -// The data-source seam. Stores/views talk to this typed repository interface -// instead of reaching for the HTTP client directly, so the SAME UI can run -// against the REST backend (web + a server-connected desktop) or a fully-local -// on-device source (offline desktop). `rest.ts` implements it over `api/client`; -// `local.ts` (M10.5) implements it over Tauri `invoke`; `index.ts` picks one. +// The data-source seam. Stores and views talk to this interface, so the same UI runs +// against the REST backend (`rest.ts`) or the desktop's on-device store (`local.ts`, +// over Tauri `invoke`); `index.ts` picks one. // -// Keep this interface a thin, semantic mirror of the current calls: every method -// maps 1:1 to a backend operation and returns the same shape the stores already -// consume. Client-side logic (list reconciliation, optimistic updates, toasts) -// stays in the stores — the repo is data access only. +// Each method maps 1:1 to a backend operation. Client-side logic (reconciliation, +// optimistic updates, toasts) stays in the stores; the repo is data access only. import type { Note, NoteFacets, NoteView, NoteRevision } from "../stores/notes"; import type { Label } from "../stores/labels"; @@ -45,7 +41,7 @@ export interface ChecklistItemChanges { } -// ---- sharing (#5174) --------------------------------------------------------- +// ---- sharing ----------------------------------------------------------------- /** A person on this instance, as the member directory shows them. */ export interface Member { @@ -54,7 +50,7 @@ export interface Member { email: string; } -/** A group the admin made, as the directory shows it (#5177). */ +/** A group the admin made, as the directory shows it. */ export interface ShareGroup { id: string; name: string; diff --git a/frontend/src/adapters/rest.ts b/frontend/src/adapters/rest.ts index 62853dd..6474ccd 100644 --- a/frontend/src/adapters/rest.ts +++ b/frontend/src/adapters/rest.ts @@ -1,8 +1,6 @@ -// REST implementation of the repository seam: maps each semantic operation to the -// existing HTTP endpoint via `api/client`. This is the ONLY place that knows about -// URL paths, query strings, and multipart bodies. Behaviour here must stay a -// verbatim mirror of the calls the stores/views made before the seam existed — the -// web app is unchanged; the offline `local.ts` source (M10.5) is the alternative. +// The REST implementation of the repository seam: each operation is an HTTP endpoint +// via `api/client`. The only place that knows URL paths, query strings and multipart +// bodies. import { api } from "../api/client"; import type { Note, NoteRevision } from "../stores/notes"; @@ -26,9 +24,7 @@ import type { StorageUse, } from "./repo"; -// Render a board query to the GET /api/notes query string. Mirrors the param -// building that used to live in notes.store.load()/TimelineView (order-preserving; -// query-param order is irrelevant to the server, but kept close for review). +// Render a board query to the GET /api/notes query string. function notesQuery(q: NoteListQuery): string { const params = new URLSearchParams(); params.set("filter", q.view); diff --git a/frontend/src/components/AccountList.vue b/frontend/src/components/AccountList.vue index 3c29324..309e2dd 100644 --- a/frontend/src/components/AccountList.vue +++ b/frontend/src/components/AccountList.vue @@ -6,9 +6,9 @@ import { appLink } from "../router/links"; import OneTimeSecret from "./OneTimeSecret.vue"; import { useRowAction, useLoad } from "../composables/useAction"; -// Admin: the accounts on this instance, and a password reset link for any of them -// (#5173). The admin hands the link over; a person can also mail one to themselves -// when the server can send email (#5266). +// Admin: the accounts on this instance, and a password reset link for any of them. +// The admin hands the link over; a person can also mail one to themselves when the +// server can send email. const session = useSessionStore(); diff --git a/frontend/src/components/ActivityList.vue b/frontend/src/components/ActivityList.vue index d9b505e..7e6d036 100644 --- a/frontend/src/components/ActivityList.vue +++ b/frontend/src/components/ActivityList.vue @@ -6,7 +6,7 @@ import { formatShortDateTime } from "../notes/datetime"; import { useLoad } from "../composables/useAction"; import ScrollSentinel from "./ScrollSentinel.vue"; -// Admin: what has happened to accounts on this instance, newest first (#2939 §5). +// Admin: what has happened to accounts on this instance, newest first. // Kept for `audit_retention_days` (Settings → Security). interface AuditEvent { diff --git a/frontend/src/components/AppShell.vue b/frontend/src/components/AppShell.vue index 7b10058..b4bbf8e 100644 --- a/frontend/src/components/AppShell.vue +++ b/frontend/src/components/AppShell.vue @@ -36,18 +36,11 @@ const ui = useUiStore(); // Sync is a desktop-app concern: the web build already IS the server's UI. const desktopApp = isDesktop(); -// The build, for the dim line at the foot of the rail (#3181). +// The build, for the dim line at the foot of the rail. Never blank: "unknown" when +// missing, since this is the only answer to "which build is this?". // -// NEVER BLANK. "unknown" is the honest answer when the value is missing, and an -// empty space is a bug that reads as a design choice. Note 3127 §5: with version -// tags gone this is the only answer to "which build is this?", so it has to be -// either right or visibly absent. -// -// One slot, two artifacts, and that is deliberate rather than sloppy. In the -// browser `repo` is `rest`, so this is the SERVER's version; in the desktop shell -// `repo` is `local` and `config_get` returns the desktop build's own. Each surface -// names the thing the person is actually looking at. A linked server's version is -// a different question and Sync answers it separately. +// In the browser it is the server's version; in the desktop shell `config_get` +// returns the desktop build's own. A linked server's version is shown on Sync. const buildVersion = computed(() => config.version || "unknown"); const buildLabel = computed( () => `Inkwell ${desktopApp ? "desktop" : "server"} build ${buildVersion.value}`, @@ -55,7 +48,7 @@ const buildLabel = computed( const managing = ref(false); -// The rail lists the few tags in use, not all of them (#5931); "All tags" opens the +// The rail lists the few tags in use, not all of them; "All tags" opens the // rest in place, below everything else, so nothing is pushed out of view. const viewer = computed(() => session.user?.id ?? "local"); const tagViews = ref({}); @@ -209,16 +202,8 @@ onBeforeUnmount(() => { const BOARD_ROUTES = new Set(["board", "archive", "trash", "label"]); /** - * Search is a FACET, not a destination. - * - * It used to navigate to a `/search` view backed by a different endpoint with no - * facets at all — so the one screen you landed on when you searched was the one - * screen where you could not also narrow by tag, which is precisely what tags are - * for (note 2930). Now it writes `?q=` into the board's URL, beside any labels - * already there, and the same AND-ed query serves both. - * - * Existing facets are preserved, so "filter by #grocery, then search" and the reverse - * both work. + * Search is a facet, not a destination: it writes `?q=` into the board's URL beside + * any tags already there, so search and tag filters combine in either order. */ function onSearch(value: string) { searchText.value = value; @@ -233,9 +218,8 @@ function onSearch(value: string) { }, 250); } -// The URL is the filter state (see notes/facets.ts), so the box READS from it rather -// than holding its own copy — which is also what keeps it in step with the Filters -// panel's Clear button. +// The URL is the filter state (notes/facets.ts), so the box reads from it rather than +// holding a copy, and the Filters panel's Clear button clears it too. watch( () => route.query.q, (q) => { @@ -260,26 +244,21 @@ async function signOut() {