Files
shell-rs/src/shared/host_mark.rs
T
XuzandClaude Opus 5 698b9ed925 主机徽章去掉描边,开始页也用它
- 去掉徽章的边框。加描边本来是防纯黑或纯白的品牌在同色主题下糊掉,
  但那两个(Apple、AlmaLinux)用的是 foreground / background,跟着
  主题翻转,天然高对比,描边是多余的。
- 徽章抽成 shared::HostMark,会话树和「最近连接」开始页共用一份。
  尺寸走 Sizable:树里 small(20px),开始页默认 medium(32px),
  照着那行两行文字的高度定的。尺寸和字号都用 rem 助手,跟着缩放走。
- 开始页原来那个通用服务器图标换掉了;空状态里的大图标保留,那是
  插图不是主机标记。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Ub6VpmWWAJB15MnYLT9G5
2026-09-12 17:13:33 +08:00

113 lines
3.6 KiB
Rust

use gpui_kit::component::{
ActiveTheme as _, Icon, Sizable, Size, ThemeStyled as _, h_flex, tooltip::Tooltip,
};
use gpui_kit::prelude::FluentBuilder as _;
use gpui_kit::*;
use crate::session::HostOs;
/// The mark that stands for a session: the operating system found on its host,
/// drawn on a badge in that project's own colour, or the first character of
/// the session name until a probe succeeds.
///
/// Shared so the session tree and the start page show one identity for the
/// same host. The badge borrows `Avatar`'s treatment, a circle at the theme's
/// radius, so identity marks look alike wherever the product shows one.
#[derive(IntoElement)]
pub struct HostMark {
id: ElementId,
name: SharedString,
os: Option<HostOs>,
size: Size,
}
impl HostMark {
pub fn new(
id: impl Into<ElementId>,
name: impl Into<SharedString>,
os: Option<HostOs>,
) -> Self {
Self {
id: id.into(),
name: name.into(),
os,
size: Size::Medium,
}
}
}
impl Sizable for HostMark {
fn with_size(mut self, size: impl Into<Size>) -> Self {
self.size = size.into();
self
}
}
impl RenderOnce for HostMark {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let compact = matches!(self.size, Size::XSmall | Size::Small);
let (background, ink, glyph, description) = match self.os {
Some(os) => {
let (background, ink) = match (os.brand_color(), os.brand_foreground()) {
(Some(background), Some(ink)) => (background.into(), ink.into()),
// A monochrome mark follows the theme, which is also how
// Apple's own guidance draws it.
_ => (cx.theme().foreground, cx.theme().background),
};
let glyph = Icon::default().path(os.icon_path());
(
background,
ink,
if compact {
glyph.size_3()
} else {
glyph.size_5()
}
.into_any_element(),
SharedString::from(os.label()),
)
}
None => (
cx.theme().muted,
cx.theme().muted_foreground,
div()
.map(|text| {
if compact {
text.text_xs()
} else {
text.text_base()
}
})
.child(
self.name
.chars()
.next()
.map(|character| character.to_uppercase().to_string())
.unwrap_or_default(),
)
.into_any_element(),
SharedString::from("未探测到系统"),
),
};
let tooltip = description.clone();
h_flex()
.id(self.id)
.test_support()
.aria_label(description)
.tooltip(move |window, cx| Tooltip::new(tooltip.clone()).build(window, cx))
.flex_shrink_0()
.map(|badge| {
if compact {
badge.size_5()
} else {
badge.size_8()
}
})
.justify_center()
.rounded_full_style(cx)
.bg(background)
.text_color(ink)
.child(glyph)
}
}