Files
Ely-GPUI-Components/src/dashboard/card.rs
T
ZacharyZhang-NY 9fddf4b6bf Dashboard: a grid of widgets, what fires, what is up, and the stream
DashboardGrid lays widgets on columns: a tile's strip drags it and its
corner resizes it a cell at a time, others move down and rise to fill
gaps, a focused tile steps with the arrows, and under the theme's
stack_below width the tiles stand in one column. DashboardCard frames a
widget. AlertList acknowledges a firing alert from its row and opens
one on Enter; IncidentCard shows an incident's gravity, phase and
updates. UptimeBar, ServiceStatus and HealthCheck show what is up, a
check's detail wrapping under its name when narrow. EventStream keeps
kinds and holds the list while new events count up.
RefreshIntervalSelector and DashboardFilterBar set the window, the
filters and the refresh. StatCard, MetricsChart, ResourceGauge,
LogStream, TraceWaterfall, SystemMonitor, ProcessTable and NetworkGraph
point to their homes; the maps wait for T41.
2026-09-27 11:51:19 -04:00

109 lines
3.4 KiB
Rust

use gpui::{
AnyElement, App, FontWeight, IntoElement, ParentElement, RenderOnce, SharedString, Styled,
Window, div,
};
use crate::{
theme::{ActiveTheme, Radius, TextSize},
typography::Ellipsis,
};
/// A widget's frame: its title with a line under it, actions at the end of the title's line, its body, and an optional footer. It fills the box it sits in, as a dashboard tile.
#[derive(IntoElement)]
pub struct DashboardCard {
title: SharedString,
subtitle: Option<SharedString>,
actions: Vec<AnyElement>,
body: Option<AnyElement>,
footer: Option<AnyElement>,
}
impl DashboardCard {
pub fn new(title: impl Into<SharedString>) -> Self {
Self {
title: title.into(),
subtitle: None,
actions: Vec::new(),
body: None,
footer: None,
}
}
pub fn subtitle(mut self, text: impl Into<SharedString>) -> Self {
self.subtitle = Some(text.into());
self
}
pub fn action(mut self, action: impl IntoElement) -> Self {
self.actions.push(action.into_any_element());
self
}
pub fn body(mut self, body: impl IntoElement) -> Self {
self.body = Some(body.into_any_element());
self
}
pub fn footer(mut self, footer: impl IntoElement) -> Self {
self.footer = Some(footer.into_any_element());
self
}
}
impl RenderOnce for DashboardCard {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let theme = cx.theme();
div()
.h_full()
.flex()
.flex_col()
.gap_3()
.p_4()
.rounded(theme.radius(Radius::Lg))
.border_1()
.border_color(theme.colors.border)
.bg(theme.colors.surface)
.overflow_hidden()
.child(
div()
.flex()
.items_start()
.justify_between()
.gap_2()
.child(
div()
.flex_1()
.min_w_0()
.flex()
.flex_col()
.child(
div()
.font_weight(FontWeight::SEMIBOLD)
.child(Ellipsis::new(self.title)),
)
.children(self.subtitle.map(|text| {
div()
.text_size(theme.text_size(TextSize::Xs))
.text_color(theme.colors.fg_muted)
.child(Ellipsis::new(text))
})),
)
.child(
div()
.flex_none()
.flex()
.items_center()
.gap_1()
.children(self.actions),
),
)
.child(div().flex_1().min_h_0().children(self.body))
.children(self.footer.map(|footer| {
div()
.text_size(theme.text_size(TextSize::Xs))
.text_color(theme.colors.fg_subtle)
.child(footer)
}))
}
}