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.
286 lines
8.8 KiB
Rust
286 lines
8.8 KiB
Rust
use ely_browser_core::BrowserSnapshot;
|
|
use ely_design_system::{colors, spacing};
|
|
use ely_domain::{
|
|
ArchivedTab, BrowserTab, COLLAPSED_SIDEBAR_WIDTH_PX, DEFAULT_SIDEBAR_WIDTH_PX,
|
|
HIDDEN_SIDEBAR_WIDTH_PX, Space,
|
|
};
|
|
use gpui::{
|
|
AnyElement, BoxShadow, Context, IntoElement, ParentElement, Styled, Window, div, hsla, point,
|
|
px, rgb, rgba,
|
|
};
|
|
use gpui_component::{
|
|
IconName, Selectable, Sizable, StyledExt,
|
|
button::{Button, ButtonVariants},
|
|
};
|
|
|
|
use super::chrome::panel_bg;
|
|
use super::{ElyShell, ShellState, render::tab_profile_label};
|
|
use crate::ToggleSidebar;
|
|
|
|
impl ElyShell {
|
|
pub(super) fn on_toggle_sidebar(
|
|
&mut self,
|
|
_: &ToggleSidebar,
|
|
_: &mut Window,
|
|
cx: &mut Context<Self>,
|
|
) {
|
|
self.toggle_sidebar_width(cx);
|
|
}
|
|
|
|
pub(super) fn render_compact_sidebar(
|
|
&mut self,
|
|
snapshot: &BrowserSnapshot,
|
|
sidebar_width: f32,
|
|
cx: &mut Context<Self>,
|
|
) -> AnyElement {
|
|
let panel_color = panel_bg(snapshot);
|
|
div()
|
|
.w(px(sidebar_width))
|
|
.h_full()
|
|
.flex()
|
|
.flex_col()
|
|
.items_center()
|
|
.gap_2()
|
|
.p_2()
|
|
.rounded(px(spacing::RADIUS_CARD))
|
|
.bg(rgba(panel_color))
|
|
.border_1()
|
|
.border_color(rgba(HIGHLIGHT_BORDER))
|
|
.shadow(panel_shadow())
|
|
.children(snapshot.favorites.iter().enumerate().map(|(index, tab)| {
|
|
self.render_compact_tab_button(
|
|
("compact-favorite", index),
|
|
tab,
|
|
snapshot,
|
|
tab.id() == &snapshot.active_tab_id,
|
|
IconName::Star,
|
|
cx,
|
|
)
|
|
}))
|
|
.children(snapshot.pinned_tabs.iter().enumerate().map(|(index, tab)| {
|
|
self.render_compact_tab_button(
|
|
("compact-pinned", index),
|
|
tab,
|
|
snapshot,
|
|
tab.id() == &snapshot.active_tab_id,
|
|
IconName::Asterisk,
|
|
cx,
|
|
)
|
|
}))
|
|
.children(snapshot.spaces.iter().enumerate().map(|(index, space)| {
|
|
self.render_compact_space_button(
|
|
index,
|
|
space,
|
|
space.id() == &snapshot.active_space_id,
|
|
cx,
|
|
)
|
|
}))
|
|
.children(snapshot.tabs.iter().enumerate().map(|(index, tab)| {
|
|
self.render_compact_tab_button(
|
|
("compact-tab", index),
|
|
tab,
|
|
snapshot,
|
|
tab.id() == &snapshot.active_tab_id,
|
|
IconName::Globe,
|
|
cx,
|
|
)
|
|
}))
|
|
.children(snapshot.archived_tabs.iter().rev().enumerate().map(
|
|
|(index, archived_tab)| {
|
|
self.render_compact_archived_button(index, archived_tab, cx)
|
|
},
|
|
))
|
|
.into_any_element()
|
|
}
|
|
|
|
fn toggle_sidebar_width(&mut self, cx: &mut Context<Self>) {
|
|
let ShellState::Ready(core) = &mut self.state else {
|
|
return;
|
|
};
|
|
let Ok(snapshot) = core.snapshot() else {
|
|
return;
|
|
};
|
|
let Some(active_space) =
|
|
snapshot.spaces.iter().find(|space| space.id() == &snapshot.active_space_id)
|
|
else {
|
|
return;
|
|
};
|
|
|
|
let next_width = if active_space.sidebar_width_px() <= COLLAPSED_SIDEBAR_WIDTH_PX {
|
|
DEFAULT_SIDEBAR_WIDTH_PX
|
|
} else {
|
|
COLLAPSED_SIDEBAR_WIDTH_PX
|
|
};
|
|
|
|
if core.set_space_sidebar_width(&snapshot.active_space_id, next_width).is_ok() {
|
|
cx.notify();
|
|
}
|
|
}
|
|
|
|
pub(crate) fn set_active_sidebar_width(&mut self, width_px: u16, cx: &mut Context<Self>) {
|
|
let ShellState::Ready(core) = &mut self.state else {
|
|
return;
|
|
};
|
|
let active_space_id = match core.snapshot() {
|
|
Ok(snapshot) => snapshot.active_space_id,
|
|
Err(_) => return,
|
|
};
|
|
|
|
if core.set_space_sidebar_width(&active_space_id, width_px).is_ok() {
|
|
if width_px > HIDDEN_SIDEBAR_WIDTH_PX {
|
|
self.sidebar_hover_expanded = false;
|
|
}
|
|
cx.notify();
|
|
}
|
|
}
|
|
|
|
pub(crate) fn expand_hidden_sidebar(&mut self, cx: &mut Context<Self>) {
|
|
if !self.sidebar_hover_expanded {
|
|
self.sidebar_hover_expanded = true;
|
|
cx.notify();
|
|
}
|
|
}
|
|
|
|
pub(crate) fn collapse_hidden_sidebar(&mut self, cx: &mut Context<Self>) {
|
|
if self.sidebar_hover_expanded {
|
|
self.sidebar_hover_expanded = false;
|
|
cx.notify();
|
|
}
|
|
}
|
|
|
|
fn render_compact_space_button(
|
|
&mut self,
|
|
index: usize,
|
|
space: &Space,
|
|
active: bool,
|
|
cx: &mut Context<Self>,
|
|
) -> AnyElement {
|
|
let space_id = space.id().clone();
|
|
Button::new(("compact-space", index))
|
|
.ghost()
|
|
.small()
|
|
.selected(active)
|
|
.label(space.icon().to_string())
|
|
.tooltip(space.name().to_string())
|
|
.on_click(cx.listener(move |shell, _, window, cx| {
|
|
shell.select_space(&space_id, window, cx);
|
|
}))
|
|
.into_any_element()
|
|
}
|
|
|
|
fn render_compact_tab_button(
|
|
&mut self,
|
|
id: (&'static str, usize),
|
|
tab: &BrowserTab,
|
|
snapshot: &BrowserSnapshot,
|
|
active: bool,
|
|
icon: IconName,
|
|
cx: &mut Context<Self>,
|
|
) -> AnyElement {
|
|
let tab_id = tab.id().clone();
|
|
let tooltip = format!("{} - {}", tab.title(), tab_profile_label(tab, &snapshot.profiles));
|
|
Button::new(id)
|
|
.ghost()
|
|
.small()
|
|
.selected(active)
|
|
.icon(icon)
|
|
.tooltip(tooltip)
|
|
.on_click(cx.listener(move |shell, _, window, cx| {
|
|
shell.select_tab(&tab_id, window, cx);
|
|
}))
|
|
.into_any_element()
|
|
}
|
|
|
|
fn render_compact_archived_button(
|
|
&mut self,
|
|
index: usize,
|
|
archived_tab: &ArchivedTab,
|
|
cx: &mut Context<Self>,
|
|
) -> AnyElement {
|
|
let tab = archived_tab.tab();
|
|
let tab_id = tab.id().clone();
|
|
Button::new(("compact-archive", index))
|
|
.ghost()
|
|
.small()
|
|
.icon(IconName::Undo2)
|
|
.tooltip(tab.title().to_string())
|
|
.on_click(cx.listener(move |shell, _, window, cx| {
|
|
shell.restore_archived_tab(&tab_id, window, cx);
|
|
}))
|
|
.into_any_element()
|
|
}
|
|
}
|
|
|
|
pub(super) fn render_command_bar_identity(
|
|
snapshot: &BrowserSnapshot,
|
|
_sidebar_width: f32,
|
|
sidebar_collapsed: bool,
|
|
) -> AnyElement {
|
|
if sidebar_collapsed {
|
|
return div()
|
|
.flex()
|
|
.items_center()
|
|
.child(
|
|
div()
|
|
.size(px(28.0))
|
|
.rounded(px(spacing::RADIUS_NAV))
|
|
.bg(rgb(colors::ACCENT))
|
|
.text_color(rgb(colors::SURFACE_CARD))
|
|
.text_size(px(10.0))
|
|
.font_semibold()
|
|
.flex()
|
|
.items_center()
|
|
.justify_center()
|
|
.child("ELY"),
|
|
)
|
|
.into_any_element();
|
|
}
|
|
|
|
div()
|
|
.flex()
|
|
.items_center()
|
|
.gap_2()
|
|
.child(
|
|
div()
|
|
.text_size(px(15.0))
|
|
.font_semibold()
|
|
.text_color(rgb(colors::INK))
|
|
.child("ELY Browser"),
|
|
)
|
|
.child(
|
|
div()
|
|
.text_size(px(11.0))
|
|
.text_color(rgb(colors::INK_3))
|
|
.child(snapshot.active_space_name.clone()),
|
|
)
|
|
.into_any_element()
|
|
}
|
|
|
|
pub(super) fn collapsed_sidebar_active(sidebar_width: f32) -> bool {
|
|
sidebar_width <= f32::from(COLLAPSED_SIDEBAR_WIDTH_PX)
|
|
}
|
|
|
|
/// 50% white inner border that traces every glass panel — the GPUI
|
|
/// substitute for the design's `box-shadow: inset 0 0 0 1px rgba(255,255,255,0.5)`.
|
|
/// Painting it as the panel's own border keeps it part of the frame
|
|
/// (no separate absolute overlay) so it never participates in hit
|
|
/// testing and never blocks clicks on inner content.
|
|
const HIGHLIGHT_BORDER: u32 = 0xffffff80;
|
|
|
|
fn panel_shadow() -> Vec<BoxShadow> {
|
|
vec![
|
|
BoxShadow {
|
|
color: hsla(25.0 / 360.0, 0.33, 0.12, 0.30),
|
|
offset: point(px(0.), px(20.)),
|
|
blur_radius: px(50.),
|
|
spread_radius: px(-15.),
|
|
},
|
|
BoxShadow {
|
|
color: hsla(0., 0., 1., 0.5),
|
|
offset: point(px(0.), px(0.)),
|
|
blur_radius: px(0.),
|
|
spread_radius: px(1.),
|
|
},
|
|
]
|
|
}
|