Match split-pane header to design (accent dot + tab title)
The design's split.jsx Pane header leads with an 8 px brand-accent dot, the lock indicator, host name in INK, then the tab title in INK_4. The previous header rendered a 24 px brand glyph plus the URL path — visually heavier and less informative once both panes share most of their URL prefix. * brand_glyph: `brand_accent_color(brand)` and `accent_color_for_host` collapse each Brand to one design-matching dot color (Figma 7c6cf7, Linear 5e6ad2, etc.). * split_pane: 32 → 30 px header, glyph → 8 px dot, URL path → tab title in INK_4. `pane_path_label` deleted; nothing else used it. cargo test --workspace: 440 passed, 0 failed.
This commit is contained in:
@@ -102,6 +102,35 @@ pub(crate) fn render_glyph_for(
|
|||||||
render_fallback(fallback_initial, size)
|
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 {
|
fn render_notion(size: f32) -> AnyElement {
|
||||||
flat_square(size, 0xffffff, fontable(size, 0.65, 700.0, 0x111111, "N"))
|
flat_square(size, 0xffffff, fontable(size, 0.65, 700.0, 0x111111, "N"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub(crate) mod typography;
|
|||||||
pub(crate) mod wallpaper;
|
pub(crate) mod wallpaper;
|
||||||
|
|
||||||
pub(crate) use appearance_form::render_appearance_form;
|
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 command_overlay::render_command_overlay;
|
||||||
pub(crate) use home::render_home_page;
|
pub(crate) use home::render_home_page;
|
||||||
pub(crate) use plugin_detail_view::render_plugin_detail_view;
|
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::{panel_bg, panel_shadow};
|
||||||
pub(crate) use sidebar_header::render_sidebar_header;
|
pub(crate) use sidebar_header::render_sidebar_header;
|
||||||
pub(crate) use split_pane::{
|
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,
|
render_split_pane_header,
|
||||||
};
|
};
|
||||||
pub(crate) use topbar::render_topbar;
|
pub(crate) use topbar::render_topbar;
|
||||||
|
|||||||
@@ -7,20 +7,25 @@ use gpui::{
|
|||||||
use gpui_component::IconName;
|
use gpui_component::IconName;
|
||||||
|
|
||||||
use crate::shell::ElyShell;
|
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(
|
pub(crate) fn render_split_pane_header(
|
||||||
host: String,
|
host: String,
|
||||||
path: String,
|
title: String,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
glyph_initial: String,
|
|
||||||
close_tab_id: TabId,
|
close_tab_id: TabId,
|
||||||
cx: &mut Context<ElyShell>,
|
cx: &mut Context<ElyShell>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let lock_or_globe = if secure { IconName::Search } else { IconName::Globe };
|
let lock_or_globe = if secure { IconName::Search } else { IconName::Globe };
|
||||||
|
let accent = accent_color_for_host(Some(host.as_str()));
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.h(px(32.0))
|
.h(px(30.0))
|
||||||
.px(px(10.0))
|
.px(px(10.0))
|
||||||
.gap(px(8.0))
|
.gap(px(8.0))
|
||||||
.flex()
|
.flex()
|
||||||
@@ -29,7 +34,12 @@ pub(crate) fn render_split_pane_header(
|
|||||||
.border_b_1()
|
.border_b_1()
|
||||||
.border_color(rgb(colors::HAIRLINE))
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
.bg(rgb(0xf6f4ef))
|
.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(
|
.child(
|
||||||
div()
|
div()
|
||||||
.text_color(rgb(colors::INK_3))
|
.text_color(rgb(colors::INK_3))
|
||||||
@@ -38,7 +48,7 @@ pub(crate) fn render_split_pane_header(
|
|||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.text_size(px(11.5))
|
.text_size(px(11.0))
|
||||||
.font_weight(FontWeight(500.0))
|
.font_weight(FontWeight(500.0))
|
||||||
.text_color(rgb(colors::INK))
|
.text_color(rgb(colors::INK))
|
||||||
.child(host),
|
.child(host),
|
||||||
@@ -50,7 +60,7 @@ pub(crate) fn render_split_pane_header(
|
|||||||
.truncate()
|
.truncate()
|
||||||
.text_size(px(11.0))
|
.text_size(px(11.0))
|
||||||
.text_color(rgb(colors::INK_4))
|
.text_color(rgb(colors::INK_4))
|
||||||
.child(path),
|
.child(title),
|
||||||
)
|
)
|
||||||
.child(render_reload_glyph(close_tab_id.clone(), cx))
|
.child(render_reload_glyph(close_tab_id.clone(), cx))
|
||||||
.child(render_close_glyph(close_tab_id, 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())
|
.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 {
|
pub(crate) fn pane_url_is_secure(tab: &BrowserTab) -> bool {
|
||||||
let url = tab.url().as_str();
|
let url = tab.url().as_str();
|
||||||
url.starts_with("https://") || url.starts_with("ely://")
|
url.starts_with("https://") || url.starts_with("ely://")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use gpui_component::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::chrome::{
|
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,
|
render_split_pane_header,
|
||||||
};
|
};
|
||||||
use super::{ElyShell, ShellState};
|
use super::{ElyShell, ShellState};
|
||||||
@@ -190,14 +190,8 @@ impl ElyShell {
|
|||||||
let close_tab_id = tab.id().clone();
|
let close_tab_id = tab.id().clone();
|
||||||
let border = if active { colors::ACCENT } else { colors::HAIRLINE_STRONG };
|
let border = if active { colors::ACCENT } else { colors::HAIRLINE_STRONG };
|
||||||
let host = pane_host_label(tab);
|
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 secure = pane_url_is_secure(tab);
|
||||||
let glyph_initial = tab
|
|
||||||
.title()
|
|
||||||
.chars()
|
|
||||||
.next()
|
|
||||||
.unwrap_or('?')
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(SharedString::from(format!("split-pane-{}", tab.id().as_str())))
|
.id(SharedString::from(format!("split-pane-{}", tab.id().as_str())))
|
||||||
@@ -217,7 +211,7 @@ impl ElyShell {
|
|||||||
.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);
|
||||||
}))
|
}))
|
||||||
.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 {
|
.child(div().flex_1().min_h_0().overflow_hidden().child(if compact_canvas {
|
||||||
render_compact_split_canvas(tab)
|
render_compact_split_canvas(tab)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user