refactor: add native ui theme tokens

This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 01:36:21 -04:00
1 parent 5e6e929779
commit 308be17264
14 files changed
+248 -108

No files matched your search

+27 -12
View File
@@ -1,5 +1,5 @@
use crate::{
SharedStore,
SharedStore, theme,
widgets::{
button::{primary_button, secondary_button},
text_input::TextInput,
@@ -7,7 +7,7 @@ use crate::{
};
use app_models::AppState;
use domain::{ApprovalState, ProfileSnapshot, SectionId};
use gpui::{App, Context, Entity, SharedString, Window, div, prelude::*, px, rgb};
use gpui::{App, Context, Entity, SharedString, Window, div, prelude::*, px};
use storage::NewCompanyInput;
mod approvals;
@@ -234,11 +234,21 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.child(div().text_sm().text_color(rgb(0x6f665d)).child(label))
.child(div().text_3xl().text_color(rgb(0x171411)).child(value))
.child(div().text_sm().text_color(rgb(0x6f665d)).child(detail))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_sm().text_color(theme::text_muted()).child(label))
.child(
div()
.text_3xl()
.text_color(theme::text_primary())
.child(value),
)
.child(
div()
.text_sm()
.text_color(theme::text_muted())
.child(detail),
)
}
}
@@ -257,7 +267,7 @@ impl Render for AppRoot {
div()
.size_full()
.flex()
.bg(rgb(0xf3efe8))
.bg(theme::canvas())
.child(self.render_sidebar(cx))
.child(
div()
@@ -269,10 +279,15 @@ impl Render for AppRoot {
.px_6()
.py_4()
.border_b_1()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xf8f2e9))
.child(div().text_xl().text_color(rgb(0x171411)).child(header))
.child(div().text_sm().text_color(rgb(0x6f665d)).child(
.border_color(theme::panel_border())
.bg(theme::shell_header())
.child(
div()
.text_xl()
.text_color(theme::text_primary())
.child(header),
)
.child(div().text_sm().text_color(theme::text_muted()).child(
self.state.status_line.clone().unwrap_or_else(|| {
"Native Rust shell is reading the shared local profile."
.to_string()
@@ -24,8 +24,8 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.overflow_scroll()
.child(div().text_lg().child("Approval queue"))
.children(self.snapshot.approvals.iter().map(|item| {
@@ -38,8 +38,12 @@ impl AppRoot {
.py_2()
.rounded_md()
.cursor_pointer()
.bg(if active { rgb(0xefe2d4) } else { rgb(0xfffbf5) })
.hover(|style| style.bg(rgb(0xf4ede4)))
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_approval_id = Some(approval_id.clone());
cx.notify();
@@ -54,13 +58,13 @@ impl AppRoot {
.gap_3()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Decision"))
.child(
div()
.text_sm()
.text_color(rgb(0x6f665d))
.text_color(theme::text_muted())
.child(approval_type),
)
.child(
@@ -68,9 +72,9 @@ impl AppRoot {
.min_h(px(160.0))
.p_3()
.border_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.rounded_md()
.bg(rgb(0xf7f0e7))
.bg(theme::panel_inset())
.child(approval_summary),
)
.child(
@@ -24,8 +24,8 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.overflow_scroll()
.child(div().text_lg().child("Document center"))
.children(self.snapshot.documents.iter().map(|item| {
@@ -38,8 +38,12 @@ impl AppRoot {
.py_2()
.rounded_md()
.cursor_pointer()
.bg(if active { rgb(0xefe2d4) } else { rgb(0xfffbf5) })
.hover(|style| style.bg(rgb(0xf4ede4)))
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_document_id = Some(document_id.clone());
cx.notify();
@@ -54,19 +58,19 @@ impl AppRoot {
.gap_3()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Quick draft"))
.child(self.document_title_input.clone())
.child(self.document_body_input.clone())
.child(primary_button("Save draft", cx, |this, cx| {
this.create_document(cx)
}))
.child(div().h(px(1.0)).bg(rgb(0xeee3d7)))
.child(div().h(px(1.0)).bg(theme::panel_inset_border()))
.child(
div()
.text_sm()
.text_color(rgb(0x6f665d))
.text_color(theme::text_muted())
.child(document_title),
)
.child(
@@ -74,9 +78,9 @@ impl AppRoot {
.min_h(px(200.0))
.p_3()
.border_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.rounded_md()
.bg(rgb(0xf7f0e7))
.bg(theme::panel_inset())
.child(document_content),
),
)
@@ -12,8 +12,8 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Unread messages"))
.children(
self.snapshot
@@ -25,7 +25,7 @@ impl AppRoot {
div()
.py_2()
.border_b_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.child(format!("{} · {}", item.subject, item.body))
}),
),
@@ -37,8 +37,8 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Pending approvals"))
.children(
self.snapshot
@@ -47,9 +47,14 @@ impl AppRoot {
.filter(|item| item.state == "pending")
.take(8)
.map(|item| {
div().py_2().border_b_1().border_color(rgb(0xeee3d7)).child(
format!("{} · {}", item.approval_type, item.payload_summary),
)
div()
.py_2()
.border_b_1()
.border_color(theme::panel_inset_border())
.child(format!(
"{} · {}",
item.approval_type, item.payload_summary
))
}),
),
)
@@ -25,8 +25,8 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.overflow_scroll()
.child(div().text_lg().child("Channels"))
.children(self.snapshot.agent_messages.iter().map(|item| {
@@ -39,8 +39,12 @@ impl AppRoot {
.py_2()
.rounded_md()
.cursor_pointer()
.bg(if active { rgb(0xefe2d4) } else { rgb(0xfffbf5) })
.hover(|style| style.bg(rgb(0xf4ede4)))
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_message_id = Some(message_id.clone());
cx.notify();
@@ -55,13 +59,13 @@ impl AppRoot {
.gap_3()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Conversation"))
.child(
div()
.text_sm()
.text_color(rgb(0x6f665d))
.text_color(theme::text_muted())
.child(selected_subject),
)
.child(
@@ -69,9 +73,9 @@ impl AppRoot {
.min_h(px(220.0))
.p_3()
.border_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.rounded_md()
.bg(rgb(0xf7f0e7))
.bg(theme::panel_inset())
.child(selected_body),
)
.child(self.message_input.clone())
@@ -7,13 +7,13 @@ impl AppRoot {
.p_8()
.flex()
.gap_8()
.bg(rgb(0xf3efe8))
.bg(theme::canvas())
.child(
div()
.flex_1()
.gap_4()
.child(div().text_3xl().text_color(rgb(0x171411)).child("Start a native AgentCompany profile"))
.child(div().text_sm().text_color(rgb(0x6f665d)).child("Create the first company, point it at a workspace, and keep the SQLite profile local."))
.child(div().text_3xl().text_color(theme::text_primary()).child("Start a native AgentCompany profile"))
.child(div().text_sm().text_color(theme::text_muted()).child("Create the first company, point it at a workspace, and keep the SQLite profile local."))
.child(self.company_name_input.clone())
.child(self.mission_input.clone())
.child(self.workspace_input.clone())
@@ -26,13 +26,13 @@ impl AppRoot {
.gap_3()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("What lands in SQLite"))
.child(div().text_sm().text_color(rgb(0x6f665d)).child("Company"))
.child(div().text_sm().text_color(rgb(0x6f665d)).child("Primary workspace"))
.child(div().text_sm().text_color(rgb(0x6f665d)).child("Connector catalog"))
.child(div().text_sm().text_color(rgb(0x6f665d)).child("Shared profile settings")),
.child(div().text_sm().text_color(theme::text_muted()).child("Company"))
.child(div().text_sm().text_color(theme::text_muted()).child("Primary workspace"))
.child(div().text_sm().text_color(theme::text_muted()).child("Connector catalog"))
.child(div().text_sm().text_color(theme::text_muted()).child("Shared profile settings")),
)
}
}
@@ -46,14 +46,14 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child(company_name))
.children(self.snapshot.tasks.iter().take(6).map(|task| {
div()
.py_2()
.border_b_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.child(format!("{} · {}", task.status, task.title))
})),
)
@@ -64,14 +64,14 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Recent activity"))
.children(self.snapshot.activity.iter().take(6).map(|item| {
div()
.py_2()
.border_b_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.child(format!("{} · {}", item.action, item.detail))
})),
),
@@ -52,8 +52,8 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.overflow_scroll()
.child(div().text_lg().child("Run queue"))
.children(self.snapshot.runs.iter().map(|item| {
@@ -71,8 +71,12 @@ impl AppRoot {
.py_2()
.rounded_md()
.cursor_pointer()
.bg(if active { rgb(0xefe2d4) } else { rgb(0xfffbf5) })
.hover(|style| style.bg(rgb(0xf4ede4)))
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_run_id = Some(run_id.clone());
cx.notify();
@@ -87,13 +91,13 @@ impl AppRoot {
.gap_3()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(rgb(0xfffbf5))
.border_color(theme::panel_border())
.bg(theme::panel())
.child(div().text_lg().child("Run inspector"))
.child(
div()
.text_sm()
.text_color(rgb(0x6f665d))
.text_color(theme::text_muted())
.child(selected_status),
)
.child(
@@ -131,9 +135,9 @@ impl AppRoot {
.min_h(px(180.0))
.p_3()
.border_1()
.border_color(rgb(0xeee3d7))
.border_color(theme::panel_inset_border())
.rounded_md()
.bg(rgb(0xf7f0e7))
.bg(theme::panel_inset())
.child(selected_summary),
)
.when(!selected_error.is_empty(), |container| {
@@ -141,9 +145,9 @@ impl AppRoot {
div()
.p_3()
.border_1()
.border_color(rgb(0x9e3d2d))
.border_color(theme::primary_action())
.rounded_md()
.bg(rgb(0xffefe8))
.bg(theme::danger_bg())
.child(selected_error),
)
}),
@@ -19,8 +19,8 @@ impl AppRoot {
.gap_4()
.flex()
.flex_col()
.bg(rgb(0x161514))
.text_color(rgb(0xf5eee4))
.bg(theme::sidebar_bg())
.text_color(theme::sidebar_text())
.child(div().text_lg().child("AgentCompany"))
.children(self.snapshot.companies.iter().map(|company| {
let active =
@@ -32,14 +32,18 @@ impl AppRoot {
.py_2()
.rounded_md()
.cursor_pointer()
.bg(if active { rgb(0x9e3d2d) } else { rgb(0x211d1a) })
.hover(|style| style.bg(rgb(0x362c27)))
.bg(if active {
theme::primary_action()
} else {
theme::sidebar_surface()
})
.hover(|style| style.bg(theme::sidebar_surface_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.switch_company(company_id.clone(), cx)
}))
.child(company.name.clone())
}))
.child(div().h(px(1.0)).bg(rgb(0x2f2924)))
.child(div().h(px(1.0)).bg(theme::sidebar_divider()))
.children(sections.into_iter().map(|section| {
let active = self.state.section == section;
div()
@@ -51,9 +55,17 @@ impl AppRoot {
.py_2()
.rounded_md()
.cursor_pointer()
.bg(if active { rgb(0xefe2d4) } else { rgb(0x161514) })
.text_color(if active { rgb(0x171411) } else { rgb(0xf5eee4) })
.hover(|style| style.bg(rgb(0x2c2825)))
.bg(if active {
theme::selection_fill()
} else {
theme::sidebar_bg()
})
.text_color(if active {
theme::text_primary()
} else {
theme::sidebar_text()
})
.hover(|style| style.bg(theme::sidebar_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.section = section;
cx.notify();
@@ -16,10 +16,14 @@ impl AppRoot {
.gap_2()
.border_1()
.rounded_md()
.border_color(rgb(0xd9cdbf))
.bg(if active { rgb(0xf7f0e7) } else { rgb(0xfffbf5) })
.border_color(theme::panel_border())
.bg(if active {
theme::panel_inset()
} else {
theme::panel()
})
.cursor_pointer()
.hover(|style| style.bg(rgb(0xf4ede4)))
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_workspace_id = Some(workspace_id.clone());
cx.notify();
@@ -28,18 +32,23 @@ impl AppRoot {
.child(
div()
.text_sm()
.text_color(rgb(0x6f665d))
.text_color(theme::text_muted())
.child(workspace.local_path.clone()),
)
.child(div().text_sm().text_color(rgb(0x6f665d)).child(format!(
"{} · {}",
workspace.state,
if workspace.is_primary {
"primary"
} else {
"linked"
}
)))
.child(
div()
.text_sm()
.text_color(theme::text_muted())
.child(format!(
"{} · {}",
workspace.state,
if workspace.is_primary {
"primary"
} else {
"linked"
}
)),
)
}))
}
}
@@ -1,4 +1,5 @@
mod app_root;
mod theme;
mod widgets;
use app_root::AppRoot;
@@ -0,0 +1,81 @@
use gpui::{Hsla, rgb};
pub fn canvas() -> Hsla {
rgb(0xf3efe8).into()
}
pub fn shell_header() -> Hsla {
rgb(0xf8f2e9).into()
}
pub fn panel() -> Hsla {
rgb(0xfffbf5).into()
}
pub fn panel_border() -> Hsla {
rgb(0xd9cdbf).into()
}
pub fn panel_hover() -> Hsla {
rgb(0xf4ede4).into()
}
pub fn panel_inset() -> Hsla {
rgb(0xf7f0e7).into()
}
pub fn panel_inset_border() -> Hsla {
rgb(0xeee3d7).into()
}
pub fn text_primary() -> Hsla {
rgb(0x171411).into()
}
pub fn text_muted() -> Hsla {
rgb(0x6f665d).into()
}
pub fn primary_action() -> Hsla {
rgb(0x9e3d2d).into()
}
pub fn primary_action_hover() -> Hsla {
rgb(0xb24f3e).into()
}
pub fn primary_action_text() -> Hsla {
rgb(0xfff7f0).into()
}
pub fn danger_bg() -> Hsla {
rgb(0xffefe8).into()
}
pub fn sidebar_bg() -> Hsla {
rgb(0x161514).into()
}
pub fn sidebar_surface() -> Hsla {
rgb(0x211d1a).into()
}
pub fn sidebar_hover() -> Hsla {
rgb(0x2c2825).into()
}
pub fn sidebar_surface_hover() -> Hsla {
rgb(0x362c27).into()
}
pub fn sidebar_divider() -> Hsla {
rgb(0x2f2924).into()
}
pub fn sidebar_text() -> Hsla {
rgb(0xf5eee4).into()
}
pub fn selection_fill() -> Hsla {
rgb(0xefe2d4).into()
}
@@ -1,4 +1,5 @@
use gpui::{Context, SharedString, Window, div, prelude::*, rgb};
use crate::theme;
use gpui::{Context, SharedString, Window, div, prelude::*};
pub fn primary_button<V>(
label: &'static str,
@@ -14,9 +15,9 @@ where
.py_2()
.rounded_md()
.cursor_pointer()
.bg(rgb(0x9e3d2d))
.text_color(rgb(0xfff7f0))
.hover(|style| style.bg(rgb(0xb24f3e)))
.bg(theme::primary_action())
.text_color(theme::primary_action_text())
.hover(|style| style.bg(theme::primary_action_hover()))
.on_click(
cx.listener(move |this, _: &gpui::ClickEvent, _: &mut Window, cx| on_click(this, cx)),
)
@@ -37,11 +38,11 @@ where
.py_2()
.rounded_md()
.cursor_pointer()
.bg(rgb(0xfffbf5))
.bg(theme::panel())
.border_1()
.border_color(rgb(0xd9cdbf))
.text_color(rgb(0x171411))
.hover(|style| style.bg(rgb(0xf4ede4)))
.border_color(theme::panel_border())
.text_color(theme::text_primary())
.hover(|style| style.bg(theme::panel_hover()))
.on_click(
cx.listener(move |this, _: &gpui::ClickEvent, _: &mut Window, cx| on_click(this, cx)),
)
@@ -1,9 +1,9 @@
use crate::theme;
use gpui::{
App, Bounds, Context, CursorStyle, Element, ElementId, ElementInputHandler, Entity,
EntityInputHandler, FocusHandle, Focusable, GlobalElementId, KeyBinding, LayoutId, MouseButton,
MouseDownEvent, PaintQuad, Pixels, Point, ShapedLine, SharedString, Style, TextRun,
UTF16Selection, Window, actions, div, fill, hsla, point, prelude::*, px, relative, rgb, size,
white,
UTF16Selection, Window, actions, div, fill, hsla, point, prelude::*, px, relative, size, white,
};
use std::ops::Range;
use unicode_segmentation::UnicodeSegmentation;
@@ -371,7 +371,7 @@ impl Element for TextElement {
point(cursor_x, bounds.top()),
size(px(2.0), bounds.bottom() - bounds.top()),
),
rgb(0x9e3d2d),
theme::primary_action(),
);
PrepaintState { line, cursor }
}
@@ -422,9 +422,9 @@ impl Render for TextInput {
.on_action(cx.listener(Self::paste))
.on_action(cx.listener(Self::show_character_palette))
.on_mouse_down(MouseButton::Left, cx.listener(Self::on_mouse_down))
.bg(rgb(0xfffbf5))
.bg(theme::panel())
.border_1()
.border_color(rgb(0xd9cdbf))
.border_color(theme::panel_border())
.rounded_md()
.px_3()
.py_2()