Commit Graph
470 Commits
Author SHA1 Message Date
ZacharyZhang-NY b550360a47 refactor(core): split browser settings state 2026-05-16 06:48:45 -04:00
ZacharyZhang-NY 00d48a9286 feat(sync): include site permissions in snapshots 2026-05-16 06:43:04 -04:00
ZacharyZhang-NY d5e25345c5 refactor(sync): split snapshot apply coordinator 2026-05-16 06:35:31 -04:00
ZacharyZhang-NY 5409c02394 feat(sync): include profiles in snapshots 2026-05-16 06:31:52 -04:00
ZacharyZhang-NY 323271fc1f feat(sync): include reading list in snapshots 2026-05-16 06:17:38 -04:00
ZacharyZhang-NY b2b3d5deca feat(sync): include notes in snapshots 2026-05-16 06:07:44 -04:00
ZacharyZhang-NY 7d5e936ca4 refactor(sync): split snapshot records 2026-05-16 05:52:39 -04:00
ZacharyZhang-NY bfdc97d7fd feat(sync): preserve spaces in snapshots 2026-05-16 05:42:17 -04:00
ZacharyZhang-NY 973fd0a582 feat(app): animate sync toggle motion 2026-05-16 05:27:24 -04:00
ZacharyZhang-NY 0c9bfc2673 perf(sync): avoid snapshot clone when scheduling uploads 2026-05-16 05:19:54 -04:00
ZacharyZhang-NY 51f836f34c feat(sync): auto upload changed browser state 2026-05-16 05:13:19 -04:00
ZacharyZhang-NY 0d755af005 perf(app): suppress repeated web metadata updates 2026-05-16 05:03:43 -04:00
ZacharyZhang-NY 76a56decff perf(sidecar): avoid second hardware warmup readback 2026-05-16 04:55:47 -04:00
ZacharyZhang-NY df092f285c perf(app): defer web poll after ensure 2026-05-16 04:40:34 -04:00
ZacharyZhang-NY 654f661237 perf(app): skip unchanged software web frames 2026-05-16 04:36:49 -04:00
ZacharyZhang-NY 91df575cf8 perf(app): batch scroll surface flushes 2026-05-16 04:23:49 -04:00
ZacharyZhang-NY 0c733fa006 perf(app): settle web cadence on visible load frames 2026-05-16 04:16:12 -04:00
ZacharyZhang-NY 168c60bf2a perf(app): settle web poll cadence after load 2026-05-16 04:13:20 -04:00
ZacharyZhang-NY 99d54a7089 perf(app): idle repeated terminal web states 2026-05-16 04:06:41 -04:00
ZacharyZhang-NY 372c29f2c3 perf(app): stop extending loading poll bursts 2026-05-16 04:01:43 -04:00
ZacharyZhang-NY 47eaea28a2 fix(sync): honor paused object policies 2026-05-16 03:53:42 -04:00
ZacharyZhang-NY 8c2dffddc7 fix(sync): run initial upload for signed-in profiles 2026-05-16 03:50:16 -04:00
ZacharyZhang-NY d05d31ed22 feat(sync): include open tabs in snapshots 2026-05-16 03:44:07 -04:00
ZacharyZhang-NY d078ca5247 fix(sidecar): flush metadata changes to live clients 2026-05-16 03:32:29 -04:00
ZacharyZhang-NY 93c2b3636c perf(app): skip iosurface scans on ui thread 2026-05-16 03:25:35 -04:00
ZacharyZhang-NY 54fcce29f3 perf(app): gate payloadless surfaces on app imports 2026-05-16 03:17:45 -04:00
ZacharyZhang-NY dbfcbdb377 perf(sidecar): use payloadless hardware frames after warmup 2026-05-16 02:50:11 -04:00
ZacharyZhang-NY bd59e74ad2 perf(shell): trim render snapshot work 2026-05-16 01:52:19 -04:00
ZacharyZhang-NY cfef7479db perf(shell): render from one browser snapshot 2026-05-16 01:45:38 -04:00
ZacharyZhang-NY e442e6def4 perf(web-surface): avoid snapshot clones on live ticks 2026-05-16 01:41:42 -04:00
ZacharyZhang-NY 42dc9af66c perf(sidecar): skip redundant paint barriers 2026-05-16 01:25:37 -04:00
ZacharyZhang-NY 8ad85ce7f7 perf(sidecar): report exact live frame percentiles 2026-05-16 01:16:22 -04:00
ZacharyZhang-NY c6de666d1c test(sidecar): align live perf bench 2026-05-16 01:12:10 -04:00
ZacharyZhang-NY 5f49786c6e refactor(sidecar): split live session state 2026-05-16 01:07:50 -04:00
ZacharyZhang-NY 234bf4c8a5 fix(web-surface): bound live input paints 2026-05-16 01:02:38 -04:00
ZacharyZhang-NY 8841d74ac5 test(web-surface): lock active cadence to 120hz 2026-05-16 00:22:10 -04:00
ZacharyZhang-NY 319b32b2de feat(sync-ui): animate sync controls 2026-05-16 00:19:59 -04:00
ZacharyZhang-NY 42740842b6 feat(chrome): animate high-frequency actions 2026-05-16 00:15:33 -04:00
ZacharyZhang-NY 40ab6b4874 feat(sync): round trip cloud snapshots 2026-05-16 00:01:28 -04:00
ZacharyZhang-NY 06e947f43e perf(web-surface): adapt shell tick cadence 2026-05-15 23:42:48 -04:00
ZacharyZhang-NY 225a998642 fix(tabs): refresh metadata on navigation 2026-05-15 23:31:12 -04:00
ZacharyZhang-NY ca8f118785 perf(web-surface): throttle idle Servo polling 2026-05-15 23:25:09 -04:00
ZacharyZhang-NY a6620fa265 Fold the workspace picker into one pill and widen the traffic-light reserve
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.
2026-05-15 23:02:53 -04:00
ZacharyZhang-NY 1c72622db8 Resolve favicons through Google's s2 service
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.
2026-05-15 21:59:30 -04:00
ZacharyZhang-NY 74b3de54ed Add email + OTP sign-in flow for cloud sync
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.
2026-05-15 21:32:50 -04:00
ZacharyZhang-NY 80cff6dad3 Stop the web surface from strobing on transient errors
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.
2026-05-15 21:21:14 -04:00
ZacharyZhang-NY 838f80006a Remove broken sidebar Layout cards from appearance settings
The three layout preset cards (Single column / Compact / Hidden on
hover) painted as bright white boxes regardless of theme, never
implemented the layouts they previewed, and duplicated the live
sidebar resize handle which already covers the same intent. Drop
the section, the supporting `appearance_layout_cards` module, and
the chrome `mod` declaration that re-exported it.
2026-05-15 21:18:10 -04:00
ZacharyZhang-NY 81a75f6489 Inline the macOS traffic lights with the workspace picker
The sidebar header stacked a redundant `ELY Browser ⌄` title row above
the workspace picker, pushing the picker down a full 30 px and leaving
the traffic lights stranded over the title text. macOS already advertises
the app name in the menubar, so the in-window title is dead weight.

Drop the title row, reserve `TRAFFIC_LIGHT_RESERVE = 76 px` at the start
of the picker row instead, and recompute the disclosure anchor from the
new geometry. Traffic-light Y from main.rs (`SHELL_INSET + 22`) lines
up with the new picker row's vertical center on the first frame, so the
anchor solver sums one fewer row.
2026-05-15 21:16:10 -04:00
ZacharyZhang-NY 39d10bf3d7 Convert chrome-local color constants to theme-aware accessors
The previous theme refactor only flipped `colors::*` tokens; the
~50 chrome-local `const FOO: u32 = 0xffffff…;` overlays kept their
white-glass values, so dark mode still painted a light omnibar pill,
light search field, light sidebar tab card, light command-overlay
backdrop, light sync page chips, etc.

Promote `colors::pick(light, dark)` to `pub` so component-internal
constants can reach the same thread-local mode the global palette
uses, then convert every white-glass (`0xffffff??`) and warm-dark
wash (`0x281e14??`) constant in:

- chrome/topbar (omnibar pill, hover chip)
- chrome/sidebar_chrome + chrome/sidebar (rail nav row hover/active,
  highlight border, close-button hover, unread badge)
- chrome/sidebar_header (workspace picker, disclosure card)
- chrome/command_overlay + chrome/command_rows + chrome/command_footer
- chrome/settings_layout, chrome/appearance_form,
  chrome/appearance_layout_cards, chrome/plugin_detail_view
- chrome/home/style (search field, arrow chip, pill, card, add-tile)
- internal_pages/sync (status pill, metrics card, button row)
- internal_pages/plugin_catalog
- shell/render (main pane highlight border)

Each constant becomes `fn name() -> u32 { colors::pick(<light>, <dark>) }`
where the dark counterpart preserves the original alpha but swaps the
warm-white prefix `ffffff` for warm-graphite `1f1d1b` (or the inverse:
`281e14` warm-dark wash → `f2efe9` warm-white wash). Brand accents
(`0xc96442??`, `0xffaa7733`) and the global slate backdrop keep their
single value across modes.
2026-05-15 20:22:51 -04:00
ZacharyZhang-NY 467dcb1f87 Reflect real sync state on the Sync settings page
`SyncConnectionState` was a one-variant enum (`SignedOut`), so the
Sync page rendered "Local-only · sign-in coming soon" even after the
bearer token landed on disk and the upload thread completed. The
state machine now mirrors the actual lifecycle.

What lands:
- `SyncConnectionState` gains `SignedIn`, `AwaitingDeviceApproval`,
  `SyncReady { last_synced_at_secs }`, `SyncError { message }`.
  `SyncObjectState::Synced` joins the per-object enum so individual
  rows can advertise "Synced" once a successful upload lands.
- `BrowserCore` stores the current `SyncConnectionState` and exposes
  `set_sync_connection_state`. `sync_status` now propagates the live
  state into the snapshot the UI reads.
- `ElyShell::probe_initial_sync_state` inspects
  `<profile_data>/sync/bearer.token` synchronously at construction
  so the first render of the sync page is honest about whether the
  user is signed in.
- A `std::sync::mpsc` channel ferries upload outcomes from the
  off-thread worker back to the shell; the existing 8 ms tick
  drains it and stamps `core.set_sync_connection_state` with the
  freshest result. The UI now shows "Signed in · awaiting first
  sync", "Synced · last upload Xm ago", "Sync error · …", and the
  worker-special "Signed in · waiting for device approval" when the
  server returns `device_not_approved`.
2026-05-15 19:58:42 -04:00