diff --git a/crates/ely_app/src/shell/chrome/brand_glyph.rs b/crates/ely_app/src/shell/chrome/brand_glyph.rs index 95cea31..8ab4e7a 100644 --- a/crates/ely_app/src/shell/chrome/brand_glyph.rs +++ b/crates/ely_app/src/shell/chrome/brand_glyph.rs @@ -102,6 +102,35 @@ pub(crate) fn render_glyph_for( render_fallback(fallback_initial, size) } +/// Single-color accent for a brand — used by surfaces (split-pane headers, +/// tab indicators) that need a readable dot rather than the full brand mark. +/// Matches the design's `accent` prop on each pane. +pub(crate) fn brand_accent_color(brand: Brand) -> u32 { + match brand { + Brand::Notion => 0x111111, + Brand::YouTube => 0xff3b2d, + Brand::Dribbble => 0xea4c89, + Brand::X => 0x1d1c1a, + Brand::Vercel => 0x1d1c1a, + Brand::Behance => 0x1769ff, + Brand::Figma => 0x7c6cf7, + Brand::Slack => 0xe01e5a, + Brand::GitHub => 0x1d1c1a, + Brand::Linear => 0x5e6ad2, + Brand::Reading => 0xc96442, + Brand::News => 0x3a3733, + } +} + +/// Best-effort accent for any host. Falls back to the warm system accent so +/// unknown sites still render the design's colored dot instead of looking +/// stranded. +pub(crate) fn accent_color_for_host(host: Option<&str>) -> u32 { + host.and_then(Brand::from_host) + .map(brand_accent_color) + .unwrap_or(colors::ACCENT) +} + fn render_notion(size: f32) -> AnyElement { flat_square(size, 0xffffff, fontable(size, 0.65, 700.0, 0x111111, "N")) } diff --git a/crates/ely_app/src/shell/chrome/mod.rs b/crates/ely_app/src/shell/chrome/mod.rs index 3a8015d..c4a9cdc 100644 --- a/crates/ely_app/src/shell/chrome/mod.rs +++ b/crates/ely_app/src/shell/chrome/mod.rs @@ -19,7 +19,7 @@ pub(crate) mod typography; pub(crate) mod wallpaper; pub(crate) use appearance_form::render_appearance_form; -pub(crate) use brand_glyph::render_glyph_for; +pub(crate) use brand_glyph::{accent_color_for_host, render_glyph_for}; pub(crate) use command_overlay::render_command_overlay; pub(crate) use home::render_home_page; pub(crate) use plugin_detail_view::render_plugin_detail_view; @@ -27,7 +27,7 @@ pub(crate) use settings_layout::render_settings_landing; pub(crate) use sidebar::{panel_bg, panel_shadow}; pub(crate) use sidebar_header::render_sidebar_header; pub(crate) use split_pane::{ - pane_host_label, pane_path_label, pane_url_is_secure, render_compact_split_canvas, + pane_host_label, pane_url_is_secure, render_compact_split_canvas, render_split_pane_header, }; pub(crate) use topbar::render_topbar; diff --git a/crates/ely_app/src/shell/chrome/split_pane.rs b/crates/ely_app/src/shell/chrome/split_pane.rs index 03d813a..c9ebfa4 100644 --- a/crates/ely_app/src/shell/chrome/split_pane.rs +++ b/crates/ely_app/src/shell/chrome/split_pane.rs @@ -7,20 +7,25 @@ use gpui::{ use gpui_component::IconName; use crate::shell::ElyShell; -use crate::shell::chrome::render_glyph_for; +use crate::shell::chrome::accent_color_for_host; +/// Pane header chrome for a split tab. +/// +/// Matches the design's split.jsx Pane header: 30 px tall, warm card bg, +/// hairline divider, an 8 px brand-accent dot, the secure indicator, host +/// name in INK, the tab title in INK_4, then reload + close glyphs. pub(crate) fn render_split_pane_header( host: String, - path: String, + title: String, secure: bool, - glyph_initial: String, close_tab_id: TabId, cx: &mut Context, ) -> AnyElement { let lock_or_globe = if secure { IconName::Search } else { IconName::Globe }; + let accent = accent_color_for_host(Some(host.as_str())); div() - .h(px(32.0)) + .h(px(30.0)) .px(px(10.0)) .gap(px(8.0)) .flex() @@ -29,7 +34,12 @@ pub(crate) fn render_split_pane_header( .border_b_1() .border_color(rgb(colors::HAIRLINE)) .bg(rgb(0xf6f4ef)) - .child(render_glyph_for(Some(host.as_str()), &glyph_initial, 16.0)) + .child( + div() + .size(px(8.0)) + .rounded_full() + .bg(rgb(accent)), + ) .child( div() .text_color(rgb(colors::INK_3)) @@ -38,7 +48,7 @@ pub(crate) fn render_split_pane_header( ) .child( div() - .text_size(px(11.5)) + .text_size(px(11.0)) .font_weight(FontWeight(500.0)) .text_color(rgb(colors::INK)) .child(host), @@ -50,7 +60,7 @@ pub(crate) fn render_split_pane_header( .truncate() .text_size(px(11.0)) .text_color(rgb(colors::INK_4)) - .child(path), + .child(title), ) .child(render_reload_glyph(close_tab_id.clone(), cx)) .child(render_close_glyph(close_tab_id, cx)) @@ -95,16 +105,6 @@ pub(crate) fn pane_host_label(tab: &BrowserTab) -> String { .unwrap_or_else(|| tab.title().to_string()) } -pub(crate) fn pane_path_label(tab: &BrowserTab) -> String { - let url = tab.url().as_str(); - let path_start = url.find("://").map(|prefix| prefix + 3).unwrap_or(0); - let from_path = &url[path_start..]; - match from_path.find('/') { - Some(slash) => from_path[slash..].to_string(), - None => String::new(), - } -} - pub(crate) fn pane_url_is_secure(tab: &BrowserTab) -> bool { let url = tab.url().as_str(); url.starts_with("https://") || url.starts_with("ely://") diff --git a/crates/ely_app/src/shell/splits.rs b/crates/ely_app/src/shell/splits.rs index e5e55b2..1aa3b43 100644 --- a/crates/ely_app/src/shell/splits.rs +++ b/crates/ely_app/src/shell/splits.rs @@ -11,7 +11,7 @@ use gpui_component::{ }; use super::chrome::{ - pane_host_label, pane_path_label, pane_url_is_secure, render_compact_split_canvas, + pane_host_label, pane_url_is_secure, render_compact_split_canvas, render_split_pane_header, }; use super::{ElyShell, ShellState}; @@ -190,14 +190,8 @@ impl ElyShell { let close_tab_id = tab.id().clone(); let border = if active { colors::ACCENT } else { colors::HAIRLINE_STRONG }; let host = pane_host_label(tab); - let path = pane_path_label(tab); + let title = tab.title().to_string(); let secure = pane_url_is_secure(tab); - let glyph_initial = tab - .title() - .chars() - .next() - .unwrap_or('?') - .to_string(); div() .id(SharedString::from(format!("split-pane-{}", tab.id().as_str()))) @@ -217,7 +211,7 @@ impl ElyShell { .on_click(cx.listener(move |shell, _, window, cx| { shell.select_tab(&tab_id, window, cx); })) - .child(render_split_pane_header(host, path, secure, glyph_initial, close_tab_id, cx)) + .child(render_split_pane_header(host, title, secure, close_tab_id, cx)) .child(div().flex_1().min_h_0().overflow_hidden().child(if compact_canvas { render_compact_split_canvas(tab) } else {