Update split view and web surface to glass morphism styling
Split panes use rounded corners, glass backgrounds, and accent dot indicators matching the design reference. Web surface error page uses centered layout with proper typography. Remove opaque white backgrounds in favor of transparent glass surfaces.
This commit is contained in:
@@ -3,7 +3,7 @@ use ely_design_system::{colors, spacing};
|
||||
use ely_domain::{BrowserTab, SplitAxis, SplitLayout};
|
||||
use gpui::{
|
||||
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, SharedString,
|
||||
StatefulInteractiveElement, Styled, Window, div, px, rgb,
|
||||
StatefulInteractiveElement, Styled, Window, div, px, rgb, rgba,
|
||||
};
|
||||
use gpui_component::{
|
||||
IconName, Selectable, Sizable, StyledExt,
|
||||
@@ -130,12 +130,11 @@ impl ElyShell {
|
||||
.flex_1()
|
||||
.h_full()
|
||||
.min_w_0()
|
||||
.p_3()
|
||||
.gap_3()
|
||||
.p(px(14.0))
|
||||
.gap(px(10.0))
|
||||
.flex()
|
||||
.flex_col()
|
||||
.overflow_hidden()
|
||||
.bg(rgb(colors::CANVAS));
|
||||
.overflow_hidden();
|
||||
let pane_area = div().flex_1().min_h_0().gap_3().overflow_hidden();
|
||||
|
||||
let compact_canvas = layout.axis() == &SplitAxis::Vertical && layout.pane_count() >= 4;
|
||||
@@ -176,7 +175,7 @@ impl ElyShell {
|
||||
|
||||
fn render_split_pane(
|
||||
&mut self,
|
||||
index: usize,
|
||||
_index: usize,
|
||||
tab: &BrowserTab,
|
||||
snapshot: &BrowserSnapshot,
|
||||
compact_canvas: bool,
|
||||
@@ -184,9 +183,8 @@ impl ElyShell {
|
||||
) -> AnyElement {
|
||||
let active = tab.id() == &snapshot.active_tab_id;
|
||||
let tab_id = tab.id().clone();
|
||||
let pane_number = index + 1;
|
||||
let border = if active { colors::PRIMARY } else { colors::HAIRLINE_STRONG };
|
||||
let title_color = if active { colors::INK } else { colors::BODY };
|
||||
let border = if active { colors::ACCENT } else { colors::HAIRLINE_STRONG };
|
||||
let title_color = if active { colors::INK } else { colors::INK_2 };
|
||||
|
||||
div()
|
||||
.id(SharedString::from(format!("split-pane-{}", tab.id().as_str())))
|
||||
@@ -196,41 +194,37 @@ impl ElyShell {
|
||||
.flex()
|
||||
.flex_col()
|
||||
.overflow_hidden()
|
||||
.rounded_md()
|
||||
.rounded(px(10.0))
|
||||
.border_1()
|
||||
.border_color(rgb(border))
|
||||
.bg(rgb(colors::SURFACE_CARD))
|
||||
.bg(rgba(colors::GLASS_2))
|
||||
.cursor_pointer()
|
||||
.hover(|style| style.bg(rgb(colors::CANVAS_SOFT)))
|
||||
.hover(|style| style.bg(rgba(colors::GLASS_3)))
|
||||
.active(|style| style.opacity(0.92))
|
||||
.on_click(cx.listener(move |shell, _, window, cx| {
|
||||
shell.select_tab(&tab_id, window, cx);
|
||||
}))
|
||||
.child(
|
||||
div()
|
||||
.h(px(spacing::COMMAND_BAR_HEIGHT - spacing::MD))
|
||||
.px_3()
|
||||
.gap_2()
|
||||
.h(px(30.0))
|
||||
.px(px(10.0))
|
||||
.gap(px(6.0))
|
||||
.flex()
|
||||
.items_center()
|
||||
.border_b_1()
|
||||
.border_color(rgb(colors::HAIRLINE))
|
||||
.bg(rgb(colors::CANVAS_SOFT))
|
||||
.child(div().text_color(rgb(colors::MUTED)).child(IconName::Frame))
|
||||
.flex_shrink_0()
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.font_semibold()
|
||||
.text_color(rgb(colors::MUTED))
|
||||
.child(format!("Pane {pane_number}")),
|
||||
.size(px(6.0))
|
||||
.rounded_full()
|
||||
.bg(rgb(if active { colors::ACCENT } else { colors::INK_4 })),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.truncate()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.text_size(px(12.0))
|
||||
.font_weight(gpui::FontWeight(500.0))
|
||||
.text_color(rgb(title_color))
|
||||
.child(tab.title().to_string()),
|
||||
),
|
||||
@@ -255,10 +249,8 @@ impl ElyShell {
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.border_1()
|
||||
.border_color(rgb(colors::HAIRLINE))
|
||||
.rounded_md()
|
||||
.bg(rgb(colors::CANVAS_SOFT))
|
||||
.rounded(px(10.0))
|
||||
.bg(rgba(colors::GLASS_2))
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
@@ -391,28 +383,25 @@ impl ElyShell {
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<AnyElement> {
|
||||
let first_tab_id = layout.panes().first()?.tab_id().clone();
|
||||
let background = if active { colors::SURFACE_CARD } else { colors::CANVAS };
|
||||
let border = if active { colors::PRIMARY } else { colors::HAIRLINE };
|
||||
let bg = if active { colors::GLASS_3 } else { 0x00000000 };
|
||||
|
||||
Some(
|
||||
div()
|
||||
.id(SharedString::from(format!("saved-split-{}", layout.id().as_str())))
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(rgb(border))
|
||||
.bg(rgb(background))
|
||||
.px_3()
|
||||
.py_2()
|
||||
.gap_2()
|
||||
.rounded(px(spacing::RADIUS_NAV))
|
||||
.bg(rgba(bg))
|
||||
.px(px(10.0))
|
||||
.py(px(7.0))
|
||||
.gap(px(10.0))
|
||||
.flex()
|
||||
.items_center()
|
||||
.cursor_pointer()
|
||||
.hover(|style| style.bg(rgb(colors::SURFACE_CARD)))
|
||||
.hover(|style| style.bg(rgba(colors::GLASS_3)))
|
||||
.active(|style| style.opacity(0.82))
|
||||
.on_click(cx.listener(move |shell, _, window, cx| {
|
||||
shell.select_tab(&first_tab_id, window, cx);
|
||||
}))
|
||||
.child(div().text_color(rgb(colors::PRIMARY)).child(IconName::Frame))
|
||||
.child(div().text_color(rgb(colors::ACCENT)).child(IconName::Frame))
|
||||
.child(
|
||||
div()
|
||||
.min_w_0()
|
||||
@@ -421,16 +410,16 @@ impl ElyShell {
|
||||
.gap_1()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.text_size(px(13.0))
|
||||
.font_weight(gpui::FontWeight(500.0))
|
||||
.truncate()
|
||||
.text_color(rgb(colors::INK))
|
||||
.child(layout.title().to_string()),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(rgb(colors::MUTED))
|
||||
.text_size(px(11.0))
|
||||
.text_color(rgb(colors::INK_4))
|
||||
.child(format!("{} panes", layout.pane_count())),
|
||||
),
|
||||
)
|
||||
@@ -452,21 +441,18 @@ fn render_compact_split_canvas(tab: &BrowserTab) -> AnyElement {
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.p_2()
|
||||
.bg(rgb(colors::CANVAS_SOFT))
|
||||
.child(
|
||||
div()
|
||||
.size_full()
|
||||
.min_h_0()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(rgb(colors::HAIRLINE))
|
||||
.bg(rgb(colors::SURFACE_CARD))
|
||||
.px_3()
|
||||
.py_2()
|
||||
.gap_2()
|
||||
.rounded(px(10.0))
|
||||
.bg(rgba(colors::GLASS_2))
|
||||
.px(px(10.0))
|
||||
.py(px(8.0))
|
||||
.gap(px(8.0))
|
||||
.flex()
|
||||
.items_center()
|
||||
.child(div().text_color(rgb(colors::MUTED)).child(IconName::Globe))
|
||||
.child(div().text_color(rgb(colors::INK_4)).child(IconName::Globe))
|
||||
.child(
|
||||
div()
|
||||
.min_w_0()
|
||||
@@ -475,15 +461,15 @@ fn render_compact_split_canvas(tab: &BrowserTab) -> AnyElement {
|
||||
.child(
|
||||
div()
|
||||
.truncate()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.text_size(px(13.0))
|
||||
.font_weight(gpui::FontWeight(500.0))
|
||||
.child(tab.title().to_string()),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.truncate()
|
||||
.text_xs()
|
||||
.text_color(rgb(colors::MUTED))
|
||||
.text_size(px(11.0))
|
||||
.text_color(rgb(colors::INK_4))
|
||||
.child(split_canvas_status(tab)),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use ely_domain::{BrowserTab, TabId};
|
||||
use gpui::{
|
||||
AnyElement, App, Entity, ImageSource, InteractiveElement, IntoElement, MouseButton, ObjectFit,
|
||||
ParentElement, Styled, StyledImage, Window, canvas, div, img, prelude::FluentBuilder, px, rgb,
|
||||
ParentElement, Styled, StyledImage, Window, canvas, div, img, px, rgb,
|
||||
};
|
||||
use gpui_component::StyledExt;
|
||||
|
||||
use super::{ElyShell, web_surface_frame::WebSurfaceFrame};
|
||||
use ely_design_system::{colors, spacing};
|
||||
use ely_design_system::colors;
|
||||
|
||||
pub(super) fn render_ready_web_surface(
|
||||
frame: &WebSurfaceFrame,
|
||||
@@ -16,10 +15,7 @@ pub(super) fn render_ready_web_surface(
|
||||
render_web_surface(
|
||||
tab,
|
||||
state_entity,
|
||||
frame.title_label(),
|
||||
frame.url_label().to_string(),
|
||||
Some(frame.detail_label()),
|
||||
img(ImageSource::Render(frame.image.clone())).size_full().object_fit(ObjectFit::Contain),
|
||||
img(ImageSource::Render(frame.image.clone())).size_full().object_fit(ObjectFit::Fill),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,14 +23,7 @@ pub(super) fn render_loading_web_surface(
|
||||
tab: &BrowserTab,
|
||||
state_entity: Entity<ElyShell>,
|
||||
) -> AnyElement {
|
||||
render_web_surface(
|
||||
tab,
|
||||
state_entity,
|
||||
tab.title().to_string(),
|
||||
tab.url().as_str().to_string(),
|
||||
Some("Rendering".to_string()),
|
||||
centered_status(tab.title(), tab.url().as_str(), "Rendering page with Servo", colors::BODY),
|
||||
)
|
||||
render_web_surface(tab, state_entity, div().size_full())
|
||||
}
|
||||
|
||||
pub(super) fn render_failed_web_surface(
|
||||
@@ -42,66 +31,36 @@ pub(super) fn render_failed_web_surface(
|
||||
message: &str,
|
||||
state_entity: Entity<ElyShell>,
|
||||
) -> AnyElement {
|
||||
render_web_surface(
|
||||
tab,
|
||||
state_entity,
|
||||
tab.title().to_string(),
|
||||
tab.url().as_str().to_string(),
|
||||
Some("Render failed".to_string()),
|
||||
centered_status(tab.title(), tab.url().as_str(), message, colors::ERROR),
|
||||
)
|
||||
render_web_surface(tab, state_entity, error_page(message))
|
||||
}
|
||||
|
||||
fn render_web_surface_header(title: String, url: String, detail: Option<String>) -> AnyElement {
|
||||
div()
|
||||
.h(px(34.0))
|
||||
.px_3()
|
||||
.gap_3()
|
||||
.flex()
|
||||
.items_center()
|
||||
.border_b_1()
|
||||
.border_color(rgb(colors::HAIRLINE))
|
||||
.bg(rgb(colors::CANVAS_SOFT))
|
||||
.child(
|
||||
div()
|
||||
.min_w_0()
|
||||
.flex_1()
|
||||
.truncate()
|
||||
.text_sm()
|
||||
.font_semibold()
|
||||
.text_color(rgb(colors::INK))
|
||||
.child(title),
|
||||
)
|
||||
.when_some(detail, |this, detail| {
|
||||
this.child(div().text_xs().text_color(rgb(colors::MUTED)).child(detail))
|
||||
})
|
||||
.child(
|
||||
div().max_w(px(420.0)).truncate().text_xs().text_color(rgb(colors::MUTED)).child(url),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn centered_status(title: &str, url: &str, detail: &str, detail_color: u32) -> impl IntoElement {
|
||||
fn error_page(message: &str) -> impl IntoElement {
|
||||
div()
|
||||
.size_full()
|
||||
.p_8()
|
||||
.p(px(48.0))
|
||||
.flex()
|
||||
.flex_col()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.bg(rgb(colors::SURFACE_CARD))
|
||||
.child(div().text_size(px(26.0)).text_color(rgb(colors::INK)).child(title.to_string()))
|
||||
.child(div().text_sm().text_color(rgb(colors::MUTED)).child(url.to_string()))
|
||||
.child(div().text_sm().text_color(rgb(detail_color)).child(detail.to_string()))
|
||||
.gap(px(12.0))
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(22.0))
|
||||
.font_weight(gpui::FontWeight(400.0))
|
||||
.text_color(rgb(colors::INK))
|
||||
.child("Page unavailable"),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(14.0))
|
||||
.text_color(rgb(colors::INK_3))
|
||||
.child(message.to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_web_surface(
|
||||
tab: &BrowserTab,
|
||||
state_entity: Entity<ElyShell>,
|
||||
title: String,
|
||||
url: String,
|
||||
detail: Option<String>,
|
||||
content: impl IntoElement,
|
||||
) -> AnyElement {
|
||||
let input_tab_id = tab.id().clone();
|
||||
@@ -112,30 +71,16 @@ fn render_web_surface(
|
||||
div()
|
||||
.flex_1()
|
||||
.h_full()
|
||||
.p(px(spacing::SM))
|
||||
.bg(rgb(colors::CANVAS_SOFT))
|
||||
.child(
|
||||
div()
|
||||
.size_full()
|
||||
.min_w_0()
|
||||
.overflow_hidden()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(rgb(colors::HAIRLINE))
|
||||
.bg(rgb(colors::SURFACE_CARD))
|
||||
.flex()
|
||||
.flex_col()
|
||||
.child(render_web_surface_header(title, url, detail))
|
||||
.child(
|
||||
div()
|
||||
.relative()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.bg(rgb(colors::SURFACE_CARD))
|
||||
.child(content)
|
||||
.child(render_viewport_tracker(tab.id().clone(), tracker_entity))
|
||||
.child(render_input_overlay(input_tab_id, input_url, input_entity)),
|
||||
),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user