web: UX overhaul — kill entry flicker, silent session restore, hub switcher, memory lifecycle#1
Merged
Merged
Conversation
The /home → /brain → /h/personal/memories redirect chain painted the brain surface (centered bar, conversations panel, Brain rail tab) for ~300-600ms before flicking to memories on every cold entry — the 'bar renders then flicks into memory view' defect. - /home becomes a client-side entry resolver: it decides between /brain (activated) and /h/personal/memories (everyone else) BEFORE any destination chrome paints, using a persisted landing-surface hint for instant single-hop routing on returning entries. - New lib/landing-surface.ts owns the hint; useOnboardingActivation refreshes it whenever the server activation signal resolves; clearSession clears it with the token keys. - route-helpers: /home is no longer a brain-view route — the shell renders neutral chrome (no bar, no active rail tab, no secondary panel) while resolving; getShellTabForPath(/home) → null. - LeftRail renders collapsed on /home so entry doesn't play an expanded→collapsed width shift on arrival. - recent-navigation: /home is no surface — no brain/memory morph into or out of the resolver. Verified with CDP screencasts: cold entry now goes loader → neutral shell → destination in one hop, both hinted and unhinted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
A previously-signed-in user tapping 'Sign in' on the landing page went through a full reload → login loader → brain flash → memories chain. Root cause: the session lives in localStorage, so neither middleware nor server components could see it — every signed-out surface had to render first and correct itself client-side after auth init. - New lib/session-presence.ts: a secretless marker cookie (memax_session_presence=1) planted whenever tokens are stored or a session is verified (login, token refresh, successful /me), cleared with the session. Existing sessions migrate on their first /me. - middleware.ts: /, /login, /register redirect straight to the /home entry resolver when the cookie is present — signed-in users land in the app in one hop with zero credential re-entry and never see the marketing page or login form. Stale cookie degrades to one bounce through /login (auth init clears it; no loop). - Tests: middleware presence fast-path cases + cookie/normalization independence. Verified with Playwright: / with session → memories directly (landing never paints); 'Sign in' tap from a pre-cookie landing → app in ~1.2s, login form never visible. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
Placement (audit C1): the only desktop switcher trigger lived inside the topic panel header on memories routes — brain/agents/inbox/dreams had no hub affordance at all, and mobile had one only on memories. - LeftRail gains a hub anchor (badge + tooltip + popover switcher) under the brand mark, present on every surface — Slack/Linear pattern: workspace identity lives in the nav rail. Reuses HubIdentityChip via a new 'rail' variant so all switch/create logic stays in one component. - MobileTopBar shows a compact hub badge in the trailing corner on non-memories tabs (memories keeps its title-position chip), opening the existing bottom sheet. Behavior (C2): switching held a dimmed 'Switching to…' overlay for a 480ms minimum even when the destination was cache-warm, while a '✓ Switched' toast fired simultaneously — contradictory double feedback with artificial latency. - Overlay hold is skipped when the warm-up settles within 120ms (the 200ms fade is the whole transition); min-hold only applies to real waits. - Removed the immediate success toast from the switch path — the overlay names the hub and the destination header is the confirmation. Consistency (C3/C4): - Switching from a non-hub route pushed '/memories', which middleware rewrote to /h/personal/... and silently reverted team-hub selections to personal. All switch paths (menu + create-hub flows) now navigate to the TARGET hub's v2 slug. - topic detail/memories query keys now carry the hub scope (prefix pattern: writers patch via getQueriesData/invalidateQueries which are prefix-matching), so a cache entry fetched under one hub can never satisfy a read under another. - Switcher menu rows show the memory count for every hub (the old 'Show X's recent' hint line hid it on inactive rows). - Dropped the dead '/home' warm contract (entry resolver renders no hub data). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
…ettings deep link Edit (audit D1): body editing lived only behind the ⋯ menu — content looked inert. The detail body now shows a hover-revealed Edit pencil (always visible on touch), and 'e' enters edit mode (Linear/GitHub convention; guarded against inputs/contenteditable and modifiers). The ⋯ menu path remains. Bar search/ask states (D2/D3): - Ask-failure copy said 'sources below are still available' directly above the 'No memories match' empty state. SynthesisSlot now picks errorNoSources copy when there are zero sources (en + zh keys). - 'Save it above to start remembering.' is onboarding copy — shown even to users with a full corpus whose query missed. The no-results hint now picks by corpus emptiness across accessible hubs (empty → save-first copy; non-empty → 'try different words'). Bar scrim (D4): engaged desktop bar now sits on a dimmed page scrim (Spotlight/Raycast pattern) — no more full-contrast content bleeding through the glass pill; clicks land on the scrim and the existing click-outside handler closes the bar in one step. Settings deep link (D5): /settings opened the dialog on a 100ms timer AFTER router.replace — the redirect unmounted the page and the effect cleanup cleared the timer, so the dialog never appeared. Open first (provider lives above the route tree), then navigate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
- Hub greeting: the server interpolated a hardcoded English "there" into greeting_params.name for accounts without a display name, which leaked English into every non-English locale's greeting templates. The server now sends the name empty and the client substitutes a locale-appropriate fallback (en "there", zh "朋友") via the new hubHeader.greetingNameFallback key. - Inbox page: the card-level "Inbox" SectionHeader now renders only on the popover panel surface. On /inbox the PageHeader (and the mobile top-bar tab title) already carry the title — three stacked "Inbox" labels on mobile (audit E6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
… layers Auth/session (review 0-2): - Refresh-in-flight-at-logout race: both refresh flows (memax-client refreshAccessToken, auth tryRefresh) now drop the late response when the stored refresh token is gone — a torn-down session can no longer be resurrected (which, with the presence-cookie fast path, would have silently re-signed-in a logged-out browser). - Stale presence cookie with no localStorage tokens caused an infinite /login↔/home loader loop; auth init's no-token branch now clears the cookie so the login form is reachable after exactly one bounce. - /register is out of the middleware fast path (invite links carry ?invite=TOKEN that the redirect swallowed) and the fast path skips any request with a query string (/login?returnTo=… flow state). Landing resolution (review 3, 4, 9): - landingPathFor resolves memories against the ACTIVE hub slug — a /home entry no longer silently reverts a team-hub selection. - Activation hook: query error now means UNKNOWN (isUnknown), never 'activated'; neither the hook nor the resolver persists a landing hint on error, so a transient 500 can't misroute future cold entries. - LandingSurfaceSync mounts the activation hook in the authed shell so the hint self-corrects on every surface (was stale-forever for users who activate while on memories). Overlays + misc (review 5-8): - bar-context brain jumps (⌘M, goBack) target /brain directly (morph restored, no resolver hop); dream-toast 'view recent' navigates to the target hub's memories path instead of /home. - Bar scrim drops to z 50 so bar notifications (z 51) stay clickable. - 'e' edit shortcut ignores keys originating inside dialogs/menus/ popovers/listboxes. - Greeting: server keeps sending 'there' for deployed-bundle back-compat; the client treats it (and '') as the no-name sentinel and substitutes the locale fallback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
End-to-end UI/UX overhaul of the web app targeting the three long-standing flow defects plus the memory-lifecycle rough edges, driven by a full screen-by-screen audit (mobile + desktop, light + dark, Playwright/CDP frame captures).
Named defects — fixed at the root
/home → /brain → /h/personal/memorieschain painted brain chrome (centered bar, conversations panel, Brain rail tab) for 300–600ms before yanking to memories./homeis now a neutral entry resolver: no bar, no active tab, no panel while it decides, with a persisted landing-surface hint for single-hop routing on returning entries. Verified frame-by-frame with CDP screencasts.memax_session_presencecookie (set on token store/refresh/verify, cleared with the session) lets middleware route/and/loginstraight into the app. Measured: tap → app ~1.2s, login form never paints.Memory lifecycle
eshortcut on the detail body (⋯ menu path kept)./settingsdeep link actually opens the dialog (open-then-navigate; the old 100ms timer was cancelled by unmount cleanup).Polish
Locale-safe greeting fallback (server "there" no longer leaks into zh), mobile inbox heading dedupe.
Review
High-effort multi-agent review over the branch confirmed 10 findings — including 3 serious session bugs introduced mid-branch (logout race resurrecting sessions, stale-cookie infinite loader loop, invite-token swallowing) — all fixed in the final commit and re-verified.
Test plan
pnpm format && pnpm lintclean (--max-warnings 0)e+ save) → hub anchor on detail → switch (~250ms) → team content consistent🤖 Generated with Claude Code
https://claude.ai/code/session_01DaVzvqvcAJiqtgASHYKZ5s