Commit Graph
50 Commits
Author SHA1 Message Date
ZacharyZhang-NY d076dad356 Fix shell regressions and reset Servo embedding direction 2026-05-16 11:23:41 -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 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 6b2578c3a8 Make every shell color token theme-aware
Dark mode was persistent in `AppearanceSettings` but never reached any
paint code: every call site in the shell read `colors::INK` etc. as a
`pub const u32`, so toggling `ThemeMode::Dark` mutated state nothing
sampled. Root-cause fix is to invert the contract — the design-system
exports functions that resolve through a thread-local `Mode`, and the
GPUI render impl sets that mode each frame.

What lands:
- `ely_design_system::colors::Mode` + thread-local + `set_mode` /
  `mode` accessors. Every ink shade, glass surface, stroke, divider,
  hairline, canvas, success / error chip now picks the warm-dark
  counterpart when the active mode is `Mode::Dark`.
- `ElyShell::render` resolves `ThemeMode::System` against
  `Window::appearance()` and pushes the mode before traversing the
  tree, so widgets lower down read the right shade without owning a
  `Mode` parameter.
- `render_wallpaper` + `panel_bg` now branch on `colors::mode()` so
  the gradient base, panel tint, and overlay highlights flip to
  warm-graphite when dark mode is active.
- Mechanical conversion across 687 call sites in 55 files from
  `colors::FOO` constants to `colors::foo()` accessors. The
  `Theme` / `ELY_THEME` const surface (unused outside the design
  system) is removed; the function surface is the new contract.
2026-05-15 19:50:38 -04:00
ZacharyZhang-NY 00a8ff1fef Apply cargo fmt across chrome and internal pages 2026-05-15 16:42:00 -04:00
ZacharyZhang-NY 1325f043b4 Commit Servo loaded URLs to tabs 2026-05-13 01:09:39 -04:00
ZacharyZhang-NY 1e85dad291 Solve workspace popover anchor from runtime sidebar width
DISCLOSURE_TOP_PX, DISCLOSURE_LEFT_PX, and DISCLOSURE_WIDTH_PX
were three hardcoded numbers that drifted the moment anyone touched
the sidebar header layout: SHELL_INSET, header padding, picker row
geometry, or the workspace tile size. Replace them with
WorkspaceDisclosureAnchor::solve(sidebar_width) — a pure function
whose algebra is the geometric inverse of render_sidebar_header,
expressed over named layout constants (HEADER_PT, PICKER_BUTTON_SIZE,
etc.) the renderer already applies.

Picker resize now flows: snapshot → sidebar_width → solve → anchor →
render_workspace_disclosure. Three regression tests lock the default
(66, 98, 180), invariance of left/top under resize, and zero-width
clamp. cargo test ely_app --bin ely_app: 101 passed.
2026-05-10 01:12:45 -04:00
ZacharyZhang-NY 69aee5bc68 Resolve clippy warnings in this round's changes
Three nits clippy flagged on the round 13 + 14 commits. Fix each:
* `RangeInclusive::contains` for the sidebar reveal-threshold guard.
* Reword the popover-anchor doc-comments so the `+ tile` lines don't
  get parsed as Markdown list items.
* Collapse the `if let Some(text)` + nested `if` in the external web
  keyboard handler into a single `let-and-and` chain.

No behavior change. cargo clippy -p ely_app: clean.
cargo test --workspace: 440 passed, 0 failed.
2026-05-09 22:22:36 -04:00
ZacharyZhang-NY 4a29e2d23c Suppress workspace popover when sidebar isn't expanded
The disclosure anchors to fixed window coords sized for the picker pill
in the expanded sidebar. If the sidebar is collapsed or hidden when
`workspace_picker_open` is true, the popover would float disconnected
from any visible trigger. Gate the render on
`!sidebar_collapsed && !sidebar_hidden` so the popover only shows when
the pill is actually painted.
2026-05-09 21:53:46 -04:00
ZacharyZhang-NY 41b5208006 Move workspace popover to window root + dismiss on outside click
Previously the disclosure was an absolute child of the picker row,
clipped by the sidebar's overflow_hidden, with no way for an outside
click to close it. Real popovers (Arc, Linear, Raycast) close the
moment you click anywhere else, and they spill past their host
container so a long workspace list isn't cut at the sidebar edge.

Lift the disclosure to the render_browser tree:

* `render_workspace_disclosure_backdrop` paints a fullscreen
  transparent layer that closes the picker on mouse-down — no
  on_click so the close fires immediately, before any synthetic click.
* `render_workspace_disclosure` paints next, pinned to fixed
  window-relative anchor coords (top 98, left 66, width 180) that
  match the picker pill's row in the default sidebar layout.

The picker row inside the sidebar header drops the inline disclosure
child entirely.

cargo test --workspace: 440 passed, 0 failed.
2026-05-09 21:42:37 -04:00
ZacharyZhang-NY 85d1e09916 Add a draggable sidebar resize handle
User reports the sidebar can't be resized. Until now sidebar width
was only mutable through the COLLAPSED/DEFAULT toggle and through
typed settings. Real browsers (Arc, Dia, Zen) all let you drag the
right edge of the sidebar to size it live.

Wire it through the existing space.sidebar_width_px:

* `ElyShell.sidebar_resize_origin: Option<(f32, u16)>` records the
  cursor-x and width-px at the moment the handle is grabbed.
* `begin_sidebar_resize` / `end_sidebar_resize` set and clear it.
* Window-level `on_mouse_move` consults the origin first; while held,
  it forwards the delta to `set_active_sidebar_width` clamped to
  220–480 px so you can't accidentally annihilate either pane.
* Window-level `on_mouse_up` releases the drag.
* The handle itself is a 6 px transparent strip pinned to the right
  edge of the expanded sidebar, `cursor_col_resize`, with a soft white
  hover. mouse-down captures the origin; the rest is window events.

cargo test --workspace: 440 passed, 0 failed.
2026-05-09 21:16:23 -04:00
ZacharyZhang-NY 573eaae4a8 Bundle Geist as the body sans
The design's `--ely-font-sans` is Geist; we were registering only
Newsreader. Body text everywhere fell through to GPUI's
`.SystemUIFont` (SF Pro on macOS) — too humanist for the geometric,
calm tech aesthetic the design wants.

Bundle Geist-Regular (SIL OFL 1.1, 126 KB), register it alongside
Newsreader, and set the root window's `.font_family(SANS_FAMILY)`.
SERIF_FAMILY callsites continue to override per element so headlines
keep using Newsreader.

Only Regular is bundled — GPUI synthesizes weights from the metrics,
so 500/600 still read correctly. Bold/italic file additions are a
later polish.
2026-05-09 21:12:56 -04:00
ZacharyZhang-NY 2d484a7c50 Fix dead-pane regression: drop the absolute highlight overlay
Round 12 painted the inner highlight ring through an absolutely
positioned overlay that covered every glass panel. User reports the
right pane was unclickable, the search bar wouldn't take input, and
sidebar tab close buttons never appeared on hover. Even though the
overlay div had no listeners, in this layout it was racing the
parent's hit-test for the same pixels — the close glyph in
`render_launcher_row` is `opacity(0)` until `group_hover` fires, and
the overlay was preventing that hover from registering.

Move the highlight onto each panel's own `.border_1()` so the ring is
part of the panel paint, not a separate overlay. Painted, never
hit-tested. The four wired callers (expanded sidebar, compact
sidebar, main pane, command overlay panel) now each carry their
inner border directly. `chrome::glass` deletes; nothing else used it.

The 1 px brighter top-edge specular sliver from the design is gone —
GPUI 0.2.2 has no asymmetric border colors and live clicks beat that
single-pixel polish.

cargo test --workspace: 440 passed, 0 failed.
2026-05-09 21:02:48 -04:00
ZacharyZhang-NY a92f478e21 Composite glass: inset highlights, blink, fade, panel tint
Closes the three "platform-impossible" gaps from the design audit
without resorting to hacks or shaders.

* chrome::glass — `render_inner_highlight(radius)` paints the design's
  `box-shadow: inset 0 0 0 1px` ring as an absolute overlay div with a
  1 px top-edge highlight sliver. GPUI 0.2.2's BoxShadow has no inset
  flag, so the composite is the only way to keep the panel content
  unclipped while the ring rides on top.
* chrome::animations — `blink` and `fade_in` wrap GPUI's first-class
  `with_animation` driver. Square-wave caret in the command header,
  180 ms opacity ramp on the command backdrop and workspace
  disclosure list.
* chrome::sidebar — panel_bg now tints toward the active wallpaper
  theme so the wallpaper bleeds through every glass surface, the
  closest honest substitute for backdrop-filter without a shader pass.
* command_overlay split: row helpers move to chrome::command_rows so
  command_overlay drops from 504 → 232 lines, well under the 500-line
  ceiling. No behavior change.

cargo test --workspace: 440 passed, 0 failed.
2026-05-09 20:29:08 -04:00
ZacharyZhang-NY 49e4816bce Wire ↑↓↵ keyboard navigation in the command overlay
The footer chips already advertised ↑↓ to navigate and ↵ to open;
they now match reality.

- chrome::command_match exposes COMMAND_ACTIONS / matching_actions
  alongside the tab/history/bookmark match helpers and a
  CommandSelection enum + visible_command_rows that returns the flat
  ordered list of activatable rows. command_overlay drops its private
  copies of the action const and matcher and consumes them from the
  shared module so render and key handling share one source of truth.

- ElyShell tracks command_selected_index with command_select_next /
  command_select_prev (cyclic, no notify when index doesn't change)
  and activate_selected_command which dispatches the right shell call
  for the currently selected CommandSelection variant and dismisses
  the overlay. Dismissing command mode resets the index to 0.

- The shell root captures key_down via on_command_overlay_key_down.
  When the live snapshot's command_query starts with '>', up / down
  / enter run the matching helper and the event stops propagating so
  the omnibar input doesn't move its caret.

- Each rendered row receives a `selected` flag. The selected row gets
  the design's tinted bg + accent-bar on the left edge so the active
  result is unambiguous at any keyboard step.
2026-05-09 20:12:31 -04:00
ZacharyZhang-NY 4403eacf15 Auto-reveal hidden sidebar on cursor reach
Cursor-reach reveal now fulfils the "Slide in on cursor reach"
description on the design's Hidden-on-hover layout card.

- BrowserCore::active_space_sidebar_width() returns the current
  sidebar tier without cloning a full BrowserSnapshot, so the
  mouse_move hot path stays cheap.
- on_window_mouse_move on the shell root hits-tests the cursor x
  against REVEAL_THRESHOLD_PX (24 px from the left edge). Outside
  the reveal/collapse zones it returns immediately, so 99 % of
  mouse moves never even read the snapshot.
- When in HIDDEN mode and the cursor crosses the reveal threshold,
  expand_hidden_sidebar fires (its early-return on already-expanded
  state prevents notify spam). When the cursor passes
  COLLAPSE_THRESHOLD_PX (shell inset + default sidebar width + 24 px
  buffer), collapse_hidden_sidebar fires.
- Click-to-expand on the rail and click-on-backdrop-to-collapse
  remain as predictable fallbacks.
2026-05-09 20:06:11 -04:00
ZacharyZhang-NY 9a2f9f2d74 Add hidden-on-hover sidebar mode
Domain ships HIDDEN_SIDEBAR_WIDTH_PX = 8 alongside the existing
collapsed/default tiers. ElyShell tracks sidebar_hover_expanded with
expand_hidden_sidebar / collapse_hidden_sidebar helpers; switching
back to a non-hidden width via the layout cards or core API resets
the flag automatically so the sidebar can never be both hidden and
expanded after a mode change.

Renderer:
- render_sidebar takes a sidebar_hidden flag and routes to a thin
  8 px clickable rail (hover bg + click expands) when the active
  space's width is at HIDDEN.
- While the rail is expanded, render_browser overlays a transparent
  backdrop + the full default-width sidebar absolutely positioned in
  the shell inset, so the main pane content never reflows.
- collapsed_sidebar_active still drives the COLLAPSED-tier compact
  sidebar; the hidden tier is opted out of that path.

Appearance form:
- Layout cards section gains the design's third "Hidden on hover"
  card with a 6 px sliver preview that mutates the active space to
  HIDDEN_SIDEBAR_WIDTH_PX. LayoutMode now derives id/width/preview
  from a small enum so adding a fourth mode would be one match arm.

The hover-expanded state never persists into the domain; once the
user switches modes or clicks the backdrop, it collapses cleanly.
2026-05-09 20:01:31 -04:00
ZacharyZhang-NY 3108f3265b Add translucency setting + apply to runtime panel alpha
Domain:
- AppearanceSettings gains translucency_pct (u8, 0..=100, default 40)
  with a clamping setter and serde round-trip coverage.
- DEFAULT_TRANSLUCENCY_PCT and MAX_TRANSLUCENCY_PCT exported for the
  shell.

Core:
- BrowserCore::set_translucency_pct delegates to the appearance struct;
  the existing reset_appearance covers the reset path.
- Integration test covers persistence into snapshot.appearance.

Render:
- chrome::sidebar::panel_bg(snapshot) replaces the static PANEL_BG
  constant, mapping the user's translucency_pct linearly into the alpha
  byte 0xff..0xb3. Sidebar (expanded + compact) and main pane consume
  the helper so changing the setting at runtime updates every glass
  surface in lock-step.

Form:
- Translucency row in chrome::appearance_form mirrors the design's
  static track + thumb visual driven by the persisted percentage, plus
  three preset chips (Solid 0 / Default 40 / Glassy 75) that mutate the
  setting through shell.set_translucency_pct.

Strict UX rule preserved: alpha never drops below 0xb3 so panels stay
readable without backdrop blur (which GPUI 0.2.2 doesn't expose).
2026-05-09 19:39:11 -04:00
ZacharyZhang-NY 9780fdbc8c Route domain WallpaperTheme through render_wallpaper
The shell now reads snapshot.appearance.wallpaper and feeds the domain
WallpaperTheme directly into render_wallpaper. The chrome enum is
deleted; the four design themes (Dawn / Violet / Mint / Slate) all map
to base + upper-blob + lower-blob HSLA palettes that approximate the
design's radial gradients with GPUI's 2-stop linear gradient pair.

Switching themes via core.set_wallpaper_theme now propagates through
snapshots into the next render.
2026-05-09 18:48:54 -04:00
ZacharyZhang-NY 7f1870295d Add command-mode floating switcher overlay
Whenever the command query starts with the existing '>' prefix the shell
now overlays a 640-wide floating panel — backdrop dim, glass card, three
ranked sections (Open tabs from snapshot.tabs, History from
snapshot.history_entries, and a fixed action set for workspace + key
internal routes), and a footer with the design's keyboard hints. Each
result is a real navigation hop; selecting a row dispatches the
appropriate shell action and clears the command query so the overlay
dismisses without leaving stale chrome state.

The overlay reads from the live BrowserSnapshot rather than fabricating
results, and matches case-insensitively against title and URL. Empty
queries surface the most recent items so the panel stays useful even
before the user types.
2026-05-09 18:12:49 -04:00
ZacharyZhang-NY f136ac55c1 Move expanded sidebar list out of render.rs
render.rs was 525 lines because it carried both the shell orchestrator
and every sidebar row helper. The expanded sidebar (favorites, pinned,
spaces, tabs, archive sections plus the profile footer and the row
helpers) now lives in chrome::sidebar, where panel/soft shadow tokens
also moved. render.rs is back to a 150-line orchestrator that only
composes wallpaper, sidebar, topbar, and content area.

Behaviour preserved: render_tab_row stays available for tab_groups via
pub(crate) on impl ElyShell, and all existing on_action listeners and
keyboard captures remain wired in render_browser.
2026-05-09 18:08:42 -04:00
ZacharyZhang-NY 599ed51ce7 Restructure topbar to match design's omnibar + right action cluster
Move topbar rendering into chrome::topbar so it does not bloat render.rs.
The omnibar now ends in two glass chips (filters + favorite star) inline
with the address input, matching the design's pill layout. The toolbar
right cluster is rebuilt as copy-url, downloads, theme, and menu icons:

- Copy chip writes the active tab's URL to the system clipboard.
- Downloads opens ely://downloads (existing internal route).
- Theme chip routes to ely://settings/appearance for now (a Light/Dark
  toggle still has to live in appearance settings before it can be a
  one-shot).
- Menu opens ely://settings.

The pin/new-tab buttons are removed; they were not part of the design's
topbar. Pinning still works through the favorite chip + sidebar
selection state, and Cmd+T continues to create tabs.
2026-05-09 17:59:45 -04:00
ZacharyZhang-NY 7508767014 Replace sidebar header with workspace picker row
The design's sidebar opens with an ELY title row plus a three-part
workspace picker: a layout-grid tile (opens spaces settings), a glass
pill showing the active space's emoji + name (cycles to next space on
click), and a plus button (opens spaces settings). The previous header
was a static title + space-name label that did not match the design.

Cycle behaviour reuses the existing select_next_space core API to avoid
introducing a new state flow; the existing SelectNextSpace shortcut
delegates through the same helper.
2026-05-09 17:55:35 -04:00
ZacharyZhang-NY dcd4bb4c48 Add layered dawn wallpaper to shell background
Designs call for a radial-gradient dawn (cream base + pink upper-right
glow + blue lower-left glow). GPUI 0.2.2 only supports linear gradients,
so the wallpaper is composed of a cream base layer with two diagonal
linear gradients that fade to transparent at ~60% — the perceived effect
matches the design's softness without needing radial-gradient support.

Wallpaper is isolated to chrome::wallpaper so future appearance themes
(violet, mint, slate) extend the enum without touching the shell.
2026-05-09 17:52:56 -04:00
ZacharyZhang-NY 7dfefac569 Add gradient wallpaper and panel shadows for glass depth
The flat white background is the root visual difference from the
design reference. Replace it with a warm-to-cool diagonal linear
gradient (pink-beige to lavender-blue). Add BoxShadow to both
sidebar and main pane panels for floating depth. Use warmer panel
background (88% white) instead of 62% transparent. Add soft shadows
to active nav items and workspace tiles. Avatar uses gradient
matching the design reference.
2026-05-09 17:30:38 -04:00
ZacharyZhang-NY 107619a3fe Refine topbar and nav styling to match design reference
Add back/forward navigation icon buttons, topbar bottom border
(divider), correct omnibar background (55% white), and proper
active nav item styling (85% white).
2026-05-09 16:23:54 -04:00
ZacharyZhang-NY 483bda5567 Redesign shell with glass morphism and warm clay palette
Update design system: warm clay accent (#c96442), ink scale for text
hierarchy, glass surface tokens with alpha, redesigned spacing/radius
tokens. Restructure shell layout: sidebar and main pane as rounded
glass panels, pill-shaped omnibar inside main pane, workspace tiles,
section labels, profile avatar in sidebar footer.
2026-05-09 15:42:10 -04:00
ZacharyZhang-NY 189b9b8b89 Add current page download pipeline 2026-05-09 12:54:24 -04:00
ZacharyZhang-NY 1faa7423c1 Add Servo page zoom support 2026-05-09 12:32:44 -04:00
ZacharyZhang-NY 21a72e157a Bridge web surface keyboard input 2026-05-08 14:49:57 -04:00
ZacharyZhang-NY 8e12d6690b Render PRD sites in real viewport 2026-05-08 13:20:43 -04:00
ZacharyZhang-NY f23e5d4105 Show archive context in shell 2026-05-08 10:01:26 -04:00
ZacharyZhang-NY 448a95db42 Show profile context in sidebar tabs 2026-05-08 09:45:28 -04:00
ZacharyZhang-NY cdb82bcace Add space switching shortcuts 2026-05-08 08:57:18 -04:00
ZacharyZhang-NY 43ab4be548 Add sidebar collapse shortcut 2026-05-08 08:36:58 -04:00
ZacharyZhang-NY 820054ff23 Track space sidebar width 2026-05-08 05:35:32 -04:00
ZacharyZhang-NY 0da8a3531b Add saved split view rows 2026-05-08 01:52:39 -04:00
ZacharyZhang-NY 23b108c8dd Add split view panes 2026-05-08 01:47:19 -04:00
ZacharyZhang-NY a6077fa00a Add task manager internal page 2026-05-08 01:03:59 -04:00
ZacharyZhang-NY dc421b5e78 Render history internal page 2026-05-07 21:15:17 -04:00
ZacharyZhang-NY 3fe737adad Open history and settings pages 2026-05-07 21:00:51 -04:00
ZacharyZhang-NY 4d50946072 Focus command mode from shortcut 2026-05-07 20:57:53 -04:00
ZacharyZhang-NY 9c5f93bcb8 Open downloads from command bar 2026-05-07 20:54:57 -04:00
ZacharyZhang-NY 19d928859c Add basic space switching 2026-05-07 20:19:55 -04:00
ZacharyZhang-NY 8fff64606d Restore archived tabs from sidebar 2026-05-07 20:06:18 -04:00
ZacharyZhang-NY e0eb5b51b2 Archive closed browser tabs 2026-05-07 19:53:32 -04:00
ZacharyZhang-NY 82df2b4502 Add pinned tab controls 2026-05-07 19:47:27 -04:00
ZacharyZhang-NY ba312e5b85 Add favorite tab controls 2026-05-07 19:33:50 -04:00
ZacharyZhang-NY 62951fe3b0 Split browser shell rendering 2026-05-07 19:26:02 -04:00