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.
This commit is contained in:
2026-05-09 17:30:38 -04:00
parent 3caf207129
commit 7dfefac569
2 changed files with 112 additions and 29 deletions
+84 -24
View File
@@ -2,8 +2,9 @@ use ely_browser_core::BrowserSnapshot;
use ely_design_system::{colors, spacing}; use ely_design_system::{colors, spacing};
use ely_domain::{ArchivedTab, BrowserTab, Profile, Space}; use ely_domain::{ArchivedTab, BrowserTab, Profile, Space};
use gpui::{ use gpui::{
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, Render, SharedString, AnyElement, BoxShadow, Context, InteractiveElement, IntoElement, ParentElement, Render,
StatefulInteractiveElement, Styled, Window, div, px, rgb, rgba, SharedString, StatefulInteractiveElement, Styled, Window, div, hsla, linear_gradient, point,
linear_color_stop, prelude::FluentBuilder, px, rgb, rgba,
}; };
use gpui_component::{ use gpui_component::{
IconName, Selectable, Sizable, StyledExt, IconName, Selectable, Sizable, StyledExt,
@@ -65,13 +66,26 @@ impl ElyShell {
.on_action(cx.listener(Self::on_toggle_sidebar)) .on_action(cx.listener(Self::on_toggle_sidebar))
.on_action(cx.listener(Self::on_zoom_in)) .on_action(cx.listener(Self::on_zoom_in))
.on_action(cx.listener(Self::on_zoom_out)) .on_action(cx.listener(Self::on_zoom_out))
.bg(rgb(colors::CANVAS)) .bg(linear_gradient(
135.0,
linear_color_stop(hsla(20.0 / 360.0, 0.35, 0.92, 1.0), 0.0),
linear_color_stop(hsla(220.0 / 360.0, 0.25, 0.88, 1.0), 1.0),
))
.text_color(rgb(colors::INK)) .text_color(rgb(colors::INK))
.child(
div()
.absolute()
.inset_0()
.p(px(spacing::SHELL_INSET)) .p(px(spacing::SHELL_INSET))
.gap(px(spacing::SIDEBAR_MAIN_GAP)) .gap(px(spacing::SIDEBAR_MAIN_GAP))
.flex() .flex()
.child(self.render_sidebar(&snapshot, sidebar_width, sidebar_collapsed, cx)) .child(
.child(self.render_main_pane(&snapshot, &active_tab, sidebar_collapsed, cx)) self.render_sidebar(&snapshot, sidebar_width, sidebar_collapsed, cx),
)
.child(
self.render_main_pane(&snapshot, &active_tab, sidebar_collapsed, cx),
),
)
.into_any_element() .into_any_element()
} }
@@ -89,7 +103,8 @@ impl ElyShell {
.flex() .flex()
.flex_col() .flex_col()
.rounded(px(spacing::RADIUS_CARD)) .rounded(px(spacing::RADIUS_CARD))
.bg(rgba(colors::GLASS)) .bg(rgba(PANEL_BG))
.shadow(panel_shadow())
.overflow_hidden() .overflow_hidden()
.child(self.render_topbar(snapshot, active_tab, sidebar_collapsed, cx)) .child(self.render_topbar(snapshot, active_tab, sidebar_collapsed, cx))
.child( .child(
@@ -128,23 +143,20 @@ impl ElyShell {
} else { } else {
None None
}) })
.child(render_icon_button("nav-back", IconName::ChevronLeft, false)) .child(render_icon_button("nav-back", IconName::ChevronLeft))
.child(render_icon_button("nav-forward", IconName::ChevronRight, false)) .child(render_icon_button("nav-forward", IconName::ChevronRight))
.child( .child(
div() div()
.flex_1() .flex_1()
.h(px(spacing::OMNIBAR_HEIGHT)) .h(px(spacing::OMNIBAR_HEIGHT))
.rounded(px(spacing::RADIUS_PILL)) .rounded(px(spacing::RADIUS_PILL))
.bg(rgba(OMNIBAR_BG)) .bg(rgba(OMNIBAR_BG))
.shadow(soft_shadow())
.px(px(14.0)) .px(px(14.0))
.flex() .flex()
.items_center() .items_center()
.gap(px(10.0)) .gap(px(10.0))
.child( .child(div().text_color(rgb(colors::INK_3)).child(IconName::Search))
div()
.text_color(rgb(colors::INK_3))
.child(IconName::Search),
)
.child( .child(
div() div()
.flex_1() .flex_1()
@@ -201,7 +213,8 @@ impl ElyShell {
.flex() .flex()
.flex_col() .flex_col()
.rounded(px(spacing::RADIUS_CARD)) .rounded(px(spacing::RADIUS_CARD))
.bg(rgba(colors::GLASS)) .bg(rgba(PANEL_BG))
.shadow(panel_shadow())
.overflow_hidden() .overflow_hidden()
.child(self.render_sidebar_header(snapshot)) .child(self.render_sidebar_header(snapshot))
.child( .child(
@@ -301,7 +314,11 @@ impl ElyShell {
div() div()
.size(px(26.0)) .size(px(26.0))
.rounded_full() .rounded_full()
.bg(rgb(colors::ACCENT)) .bg(linear_gradient(
135.0,
linear_color_stop(hsla(20.0 / 360.0, 0.6, 0.84, 1.0), 0.0),
linear_color_stop(hsla(15.0 / 360.0, 0.55, 0.53, 1.0), 1.0),
))
.flex() .flex()
.items_center() .items_center()
.justify_center() .justify_center()
@@ -309,7 +326,7 @@ impl ElyShell {
div() div()
.text_size(px(10.0)) .text_size(px(10.0))
.font_semibold() .font_semibold()
.text_color(rgb(colors::SURFACE_CARD)) .text_color(rgb(0xffffff))
.child( .child(
snapshot snapshot
.active_profile_name .active_profile_name
@@ -324,6 +341,7 @@ impl ElyShell {
.child( .child(
div() div()
.text_size(px(13.0)) .text_size(px(13.0))
.font_weight(gpui::FontWeight(500.0))
.text_color(rgb(colors::INK_2)) .text_color(rgb(colors::INK_2))
.child(snapshot.active_profile_name.clone()), .child(snapshot.active_profile_name.clone()),
) )
@@ -352,6 +370,7 @@ impl ElyShell {
.hover(|style| style.bg(rgba(ACTIVE_NAV_BG))) .hover(|style| style.bg(rgba(ACTIVE_NAV_BG)))
.active(|style| style.opacity(0.82)) .active(|style| style.opacity(0.82))
.bg(rgba(bg_color)) .bg(rgba(bg_color))
.when(active, |el| el.shadow(soft_shadow()))
.on_click(cx.listener(move |shell, _, window, cx| { .on_click(cx.listener(move |shell, _, window, cx| {
shell.select_space(&space_id, window, cx); shell.select_space(&space_id, window, cx);
})) }))
@@ -411,6 +430,7 @@ impl ElyShell {
.hover(|style| style.bg(rgba(ACTIVE_NAV_BG))) .hover(|style| style.bg(rgba(ACTIVE_NAV_BG)))
.active(|style| style.opacity(0.82)) .active(|style| style.opacity(0.82))
.bg(rgba(bg_color)) .bg(rgba(bg_color))
.when(active, |el| el.shadow(soft_shadow()))
.on_click(cx.listener(move |shell, _, window, cx| { .on_click(cx.listener(move |shell, _, window, cx| {
shell.select_tab(&tab_id, window, cx); shell.select_tab(&tab_id, window, cx);
})) }))
@@ -449,6 +469,7 @@ impl ElyShell {
.hover(|style| style.bg(rgba(ACTIVE_NAV_BG))) .hover(|style| style.bg(rgba(ACTIVE_NAV_BG)))
.active(|style| style.opacity(0.82)) .active(|style| style.opacity(0.82))
.bg(rgba(bg_color)) .bg(rgba(bg_color))
.when(active, |el| el.shadow(soft_shadow()))
.on_click(cx.listener(move |shell, _, window, cx| { .on_click(cx.listener(move |shell, _, window, cx| {
shell.select_tab(&tab_id, window, cx); shell.select_tab(&tab_id, window, cx);
})) }))
@@ -521,14 +542,48 @@ impl ElyShell {
} }
} }
const OMNIBAR_BG: u32 = 0xffffff8c; // rgba(255,255,255,0.55) // rgba(255,255,255,0.55) — omnibar background
const ACTIVE_NAV_BG: u32 = 0xffffffd9; // rgba(255,255,255,0.85) const OMNIBAR_BG: u32 = 0xffffff8c;
// rgba(255,255,255,0.85) — active nav item background
const ACTIVE_NAV_BG: u32 = 0xffffffd9;
// rgba(255,255,255,0.88) — glass panel background
const PANEL_BG: u32 = 0xffffffe0;
fn render_icon_button( fn panel_shadow() -> Vec<BoxShadow> {
id: &'static str, vec![
icon: IconName, BoxShadow {
_active: bool, color: hsla(25.0 / 360.0, 0.33, 0.12, 0.30),
) -> impl IntoElement { 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.),
},
]
}
fn soft_shadow() -> Vec<BoxShadow> {
vec![
BoxShadow {
color: hsla(0., 0., 1., 0.7),
offset: point(px(0.), px(1.)),
blur_radius: px(0.),
spread_radius: px(0.),
},
BoxShadow {
color: hsla(25.0 / 360.0, 0.33, 0.12, 0.08),
offset: point(px(0.), px(0.)),
blur_radius: px(0.),
spread_radius: px(1.),
},
]
}
fn render_icon_button(id: &'static str, icon: IconName) -> impl IntoElement {
div() div()
.id(id) .id(id)
.size(px(30.0)) .size(px(30.0))
@@ -570,7 +625,12 @@ fn render_workspace_tile(space: &Space) -> impl IntoElement {
div() div()
.size(px(32.0)) .size(px(32.0))
.rounded(px(9.0)) .rounded(px(9.0))
.bg(rgba(colors::GLASS_3)) .bg(linear_gradient(
135.0,
linear_color_stop(hsla(0., 0., 1., 1.0), 0.0),
linear_color_stop(hsla(20.0 / 360.0, 0.6, 0.94, 1.0), 1.0),
))
.shadow(soft_shadow())
.flex() .flex()
.items_center() .items_center()
.justify_center() .justify_center()
+25 -2
View File
@@ -3,7 +3,10 @@ use ely_design_system::{colors, spacing};
use ely_domain::{ use ely_domain::{
ArchivedTab, BrowserTab, COLLAPSED_SIDEBAR_WIDTH_PX, DEFAULT_SIDEBAR_WIDTH_PX, Space, ArchivedTab, BrowserTab, COLLAPSED_SIDEBAR_WIDTH_PX, DEFAULT_SIDEBAR_WIDTH_PX, Space,
}; };
use gpui::{AnyElement, Context, IntoElement, ParentElement, Styled, Window, div, px, rgb, rgba}; use gpui::{
AnyElement, BoxShadow, Context, IntoElement, ParentElement, Styled, Window, div, hsla, point,
px, rgb, rgba,
};
use gpui_component::{ use gpui_component::{
IconName, Selectable, Sizable, StyledExt, IconName, Selectable, Sizable, StyledExt,
button::{Button, ButtonVariants}, button::{Button, ButtonVariants},
@@ -37,7 +40,8 @@ impl ElyShell {
.gap_2() .gap_2()
.p_2() .p_2()
.rounded(px(spacing::RADIUS_CARD)) .rounded(px(spacing::RADIUS_CARD))
.bg(rgba(colors::GLASS)) .bg(rgba(PANEL_BG))
.shadow(panel_shadow())
.children(snapshot.favorites.iter().enumerate().map(|(index, tab)| { .children(snapshot.favorites.iter().enumerate().map(|(index, tab)| {
self.render_compact_tab_button( self.render_compact_tab_button(
("compact-favorite", index), ("compact-favorite", index),
@@ -219,3 +223,22 @@ pub(super) fn render_command_bar_identity(
pub(super) fn collapsed_sidebar_active(sidebar_width: f32) -> bool { pub(super) fn collapsed_sidebar_active(sidebar_width: f32) -> bool {
sidebar_width <= f32::from(COLLAPSED_SIDEBAR_WIDTH_PX) sidebar_width <= f32::from(COLLAPSED_SIDEBAR_WIDTH_PX)
} }
const PANEL_BG: u32 = 0xffffffe0;
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.),
},
]
}