Drops the separate dashboard tile and the top-level "+" button so the
sidebar's first row holds a single workspace identity. "+ New
workspace" lives inside the disclosure popover next to the existing
spaces list, matching that row's geometry instead of inventing a new
square tile.
The previous 76 px traffic-light reserve only cleared the buttons
when the row also carried the tile and "+" — with the pill alone
plus its drop-shadow, it slid back behind the green button on the
default sidebar width. Widen `TRAFFIC_LIGHT_RESERVE` to 100 px and
document the derivation: pill outer left = `29 + RESERVE`, traffic-
light group right edge ≈ 112 px, so 100 leaves 17 px of breathing
room. Anchor solver and tests track the new geometry.
Pointing the renderer at the site's own `/favicon.ico` was producing
GPUI image-cache errors on every other tab — notion.com redirected
across origins, sites shipped multi-image `image/x-icon` blobs the
PNG/WebP decoder couldn't read, hosts 404'd. Each one logged a noisy
`ERROR gpui::asset_cache: Failed to load asset` line.
Switch `UrlText::favicon_url` to
`https://www.google.com/s2/favicons?domain=<host>&sz=64`. Google's
endpoint normalises every response to PNG, follows redirects on its
side, and serves a `_/` globe glyph for sites without a favicon at
all — same URL shape every browser dev-tools panel already shows
for "favicon" so the fetch is uniformly succeeding.
Replace the "drop a session token in a file" workflow with a real
Chrome-style email login. The Cloudflare worker already had Better
Auth's `email-otp` plugin wired into `SEND_EMAIL`; this commit
builds the renderer-side counterpart.
Worker side:
- Move the OTP sender from `auth@elydora.com` to `browser@elydora.com`
(wrangler.toml `allowed_sender_addresses` + better_auth.ts
`EMAIL_OTP_FROM_ADDRESS`). Worker must be redeployed to pick this up.
Client side (`ely_sync_client::email_otp`):
- `send_email_otp(config, email)` POSTs `/api/auth/email-otp/send-verification-otp`
with `{ email, type: "sign-in" }`.
- `verify_email_otp(config, email, otp)` POSTs `/api/auth/sign-in/email-otp`,
reads the Better Auth session token from the JSON body's `token` field
with the `Set-Cookie: better-auth.session_token=…` header as the
documented fallback channel, and returns it as a `BearerToken`.
Shell side (`shell/auth.rs` + `shell/internal_pages/sync.rs`):
- New `AuthFlowPhase` (Idle / SendingCode / AwaitingOtp / Verifying /
Error) tracks the in-flight form. Two off-thread workers run the
HTTP exchanges so the GPUI render loop never blocks.
- Successful verify saves the bearer via `SyncEngine::install_bearer`
and triggers an immediate snapshot upload, so the user is signed in
+ initial-synced in one click.
- Sync settings page replaces the bare "Sync now" button row with an
account card: when SignedOut → email field + Send code → OTP field
+ Verify / Resend; when signed in → an account chip + Sign out.
- `trigger_cloud_sync_upload` no longer takes a `Context` param so
the post-auth path can fire it from the inbox-drain pass without
needing a window context.
Two paths in `WebSurfaceStore::tick` were downgrading a perfectly good
Ready frame back to Failed / Loading on every transient hiccup:
- `WebSurfaceRuntimeFrame::Failed` overwrote the surface state
unconditionally. Combined with the 125 Hz tick (which submits a Poll
for every visible tab and any transient ensure / poll error becomes
a Failed response), even one parse glitch wiped the rendered page.
- The `initial_display_gate_message` and `should_hold_initial_frame`
checks for incoming Ready frames hardcoded `has_previous_frame =
false`, so a stray empty paint pass after the page had already
rendered would knock the surface back to Loading or Failed.
Detect whether the surface already has a `Ready(_)` state and:
- ignore Failed responses (logging through `tracing` for diagnostics)
while a real frame is on screen;
- pass that "had ready" signal into the gate / hold checks so they only
apply to the very first paint, not later refreshes.
The page now stays put even when Servo emits a momentary error; only
the first-paint failure path can mark the surface Failed.