feat: Add card-based layout with theme tokens
Add a card-based UI layout with consistent spacing and visual hierarchy. The main content and sidebar are now wrapped in styled cards with gaps between them. New theme tokens (card, raised, hover, divider, disabled_fg) provide semantic colors for different surface levels and states. Create ui.rs module with helper functions (card_style, divider_h, section_header, priority_badge) to keep styling consistent across views.
This commit is contained in:
+21
-15
@@ -3,6 +3,7 @@ use gpui::prelude::*;
|
||||
use crate::models::{FilterState, ProjectTree};
|
||||
use crate::task::{TaskOverview, TaskService};
|
||||
use crate::theme::ActiveTheme;
|
||||
use crate::ui::{card_style, SECTION_GAP, ROOT_PADDING};
|
||||
use crate::view::sidebar::{Sidebar, TagItem};
|
||||
use crate::view::status_bar::StatusBar;
|
||||
use crate::view::task_table::TaskTable;
|
||||
@@ -24,31 +25,36 @@ impl gpui::Render for App {
|
||||
) -> impl gpui::IntoElement {
|
||||
let theme = cx.theme();
|
||||
|
||||
let sidebar = card_style(div(), theme)
|
||||
.w(gpui::px(250.))
|
||||
.h_full()
|
||||
.flex_shrink_0()
|
||||
.overflow_hidden()
|
||||
.child(self.sidebar.clone());
|
||||
|
||||
let main = card_style(div(), theme)
|
||||
.flex_1()
|
||||
.h_full()
|
||||
.min_w_0()
|
||||
.overflow_hidden()
|
||||
.p_0()
|
||||
.child(self.task_table.clone());
|
||||
|
||||
let content = div()
|
||||
.flex()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
div()
|
||||
.w(gpui::px(250.))
|
||||
.h_full()
|
||||
.flex_shrink_0()
|
||||
.child(self.sidebar.clone()),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.h_full()
|
||||
.min_w_0()
|
||||
.child(self.task_table.clone()),
|
||||
);
|
||||
.gap(SECTION_GAP)
|
||||
.child(sidebar)
|
||||
.child(main);
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.size_full()
|
||||
.bg(theme.background)
|
||||
.p(ROOT_PADDING)
|
||||
.gap(SECTION_GAP)
|
||||
.child(content)
|
||||
.child(self.status_bar.clone())
|
||||
}
|
||||
|
||||
@@ -300,6 +300,7 @@ impl gpui::Render for Dropdown {
|
||||
.bg(theme.background)
|
||||
.text_sm()
|
||||
.text_color(theme.foreground)
|
||||
.whitespace_nowrap()
|
||||
.child(Label::new(label.clone()))
|
||||
.child(Label::new(arrow).text_color(theme.muted));
|
||||
|
||||
@@ -308,14 +309,14 @@ impl gpui::Render for Dropdown {
|
||||
} else {
|
||||
trigger = trigger
|
||||
.cursor_pointer()
|
||||
.hover(|s: gpui::StyleRefinement| s.bg(theme.selection));
|
||||
.hover(|s: gpui::StyleRefinement| s.bg(theme.hover));
|
||||
}
|
||||
|
||||
trigger.into_any_element()
|
||||
};
|
||||
|
||||
let mut trigger_wrap = gpui::div()
|
||||
.min_w(gpui::rems(12.0))
|
||||
.flex_shrink_0()
|
||||
.child(trigger);
|
||||
if !disabled {
|
||||
trigger_wrap = trigger_wrap.on_mouse_down(
|
||||
|
||||
@@ -5,6 +5,7 @@ mod components;
|
||||
mod models;
|
||||
mod task;
|
||||
mod theme;
|
||||
mod ui;
|
||||
mod view;
|
||||
|
||||
fn main() {
|
||||
|
||||
+144
-41
@@ -1,79 +1,182 @@
|
||||
use gpui::prelude::*;
|
||||
|
||||
pub type Color = gpui::Rgba;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Theme {
|
||||
pub background: Color,
|
||||
pub foreground: Color,
|
||||
pub panel: Color,
|
||||
pub card: Color,
|
||||
pub raised: Color,
|
||||
|
||||
pub foreground: Color,
|
||||
pub muted: Color,
|
||||
pub disabled_fg: Color,
|
||||
|
||||
pub accent: Color,
|
||||
pub focus_ring: Color,
|
||||
|
||||
pub border: Color,
|
||||
pub divider: Color,
|
||||
|
||||
pub field_bg: Color,
|
||||
pub field_border: Color,
|
||||
pub field_placeholder: Color,
|
||||
|
||||
pub hover: Color,
|
||||
pub selection: Color,
|
||||
pub selection_foreground: Color,
|
||||
|
||||
pub backdrop: Color,
|
||||
|
||||
pub error: Color,
|
||||
pub success: Color,
|
||||
pub warning: Color,
|
||||
pub info: Color,
|
||||
pub selection: Color,
|
||||
pub selection_foreground: Color,
|
||||
pub text: Color,
|
||||
pub text_size: Option<gpui::Size<u32>>,
|
||||
|
||||
pub high: Color,
|
||||
pub medium: Color,
|
||||
pub low: Color,
|
||||
|
||||
pub text_size: Option<gpui::Size<u32>>,
|
||||
}
|
||||
|
||||
impl Theme {
|
||||
pub fn alpha(c: Color, a: f32) -> Color {
|
||||
gpui::Rgba { r: c.r, g: c.g, b: c.b, a: a.clamp(0.0, 1.0) }
|
||||
}
|
||||
|
||||
pub fn dark() -> Self {
|
||||
let background = gpui::rgb(0x0A0E14);
|
||||
let panel = gpui::rgb(0x0F1419);
|
||||
let foreground = gpui::rgb(0xB3B1AD);
|
||||
let muted = gpui::rgb(0x5C6773);
|
||||
let accent = gpui::rgb(0xFFB454);
|
||||
let border = gpui::rgb(0x1F2430);
|
||||
|
||||
let card = gpui::rgb(0x111823);
|
||||
let raised = gpui::rgb(0x151E2B);
|
||||
|
||||
let divider = Self::alpha(foreground, 0.10);
|
||||
let hover = Self::alpha(foreground, 0.05);
|
||||
let field_bg = raised;
|
||||
let field_border = Self::alpha(foreground, 0.14);
|
||||
let field_placeholder = Self::alpha(foreground, 0.45);
|
||||
let focus_ring = Self::alpha(accent, 0.75);
|
||||
let disabled_fg = Self::alpha(foreground, 0.35);
|
||||
let backdrop = gpui::rgba(0x0000008C);
|
||||
|
||||
let selection = gpui::rgb(0x273747);
|
||||
let selection_foreground = gpui::rgb(0xE6E1CF);
|
||||
|
||||
let error = gpui::rgb(0xF07178);
|
||||
let success = gpui::rgb(0xAAD94C);
|
||||
let warning = gpui::rgb(0xFFB454);
|
||||
let info = gpui::rgb(0x59C2FF);
|
||||
|
||||
Self {
|
||||
// ayu-dark
|
||||
background: gpui::rgb(0x0A0E14),
|
||||
panel: gpui::rgb(0x0F1419),
|
||||
foreground: gpui::rgb(0xB3B1AD),
|
||||
muted: gpui::rgb(0x5C6773),
|
||||
accent: gpui::rgb(0xFFB454),
|
||||
border: gpui::rgb(0x1F2430),
|
||||
background,
|
||||
panel,
|
||||
card,
|
||||
raised,
|
||||
|
||||
error: gpui::rgb(0xF07178),
|
||||
success: gpui::rgb(0xAAD94C),
|
||||
warning: gpui::rgb(0xFFB454),
|
||||
info: gpui::rgb(0x59C2FF),
|
||||
foreground,
|
||||
muted,
|
||||
disabled_fg,
|
||||
|
||||
selection: gpui::rgb(0x273747),
|
||||
selection_foreground: gpui::rgb(0xE6E1CF),
|
||||
accent,
|
||||
focus_ring,
|
||||
|
||||
border,
|
||||
divider,
|
||||
|
||||
field_bg,
|
||||
field_border,
|
||||
field_placeholder,
|
||||
|
||||
hover,
|
||||
selection,
|
||||
selection_foreground,
|
||||
|
||||
backdrop,
|
||||
|
||||
error,
|
||||
success,
|
||||
warning,
|
||||
info,
|
||||
|
||||
high: error,
|
||||
medium: warning,
|
||||
low: success,
|
||||
|
||||
text: gpui::rgb(0xB3B1AD),
|
||||
text_size: Some(gpui::Size::new(14, 14)),
|
||||
|
||||
high: gpui::rgb(0xF07178),
|
||||
medium: gpui::rgb(0xFFB454),
|
||||
low: gpui::rgb(0xAAD94C),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn light() -> Self {
|
||||
let background = gpui::rgb(0xFAFAFA);
|
||||
let panel = gpui::rgb(0xFFFFFF);
|
||||
let foreground = gpui::rgb(0x5C6166);
|
||||
let muted = gpui::rgb(0x8A9199);
|
||||
let accent = gpui::rgb(0xFF8F40);
|
||||
let border = gpui::rgb(0xE6E6E6);
|
||||
|
||||
let card = gpui::rgb(0xF6F7F9);
|
||||
let raised = gpui::rgb(0xEFF1F5);
|
||||
|
||||
let divider = Self::alpha(foreground, 0.12);
|
||||
let hover = Self::alpha(foreground, 0.06);
|
||||
let field_bg = gpui::rgb(0xFFFFFF);
|
||||
let field_border = Self::alpha(foreground, 0.18);
|
||||
let field_placeholder = Self::alpha(foreground, 0.55);
|
||||
let focus_ring = Self::alpha(accent, 0.70);
|
||||
let disabled_fg = Self::alpha(foreground, 0.40);
|
||||
let backdrop = gpui::rgba(0x00000040);
|
||||
|
||||
let selection = gpui::rgb(0xD3EBFF);
|
||||
let selection_foreground = foreground;
|
||||
|
||||
let error = gpui::rgb(0xE65050);
|
||||
let success = gpui::rgb(0x86B300);
|
||||
let warning = gpui::rgb(0xF2AE49);
|
||||
let info = gpui::rgb(0x399EE6);
|
||||
|
||||
Self {
|
||||
// ayu-light
|
||||
background: gpui::rgb(0xFAFAFA),
|
||||
panel: gpui::rgb(0xFFFFFF),
|
||||
foreground: gpui::rgb(0x5C6166),
|
||||
muted: gpui::rgb(0x8A9199),
|
||||
accent: gpui::rgb(0xFF8F40),
|
||||
border: gpui::rgb(0xE6E6E6),
|
||||
background,
|
||||
panel,
|
||||
card,
|
||||
raised,
|
||||
|
||||
error: gpui::rgb(0xE65050),
|
||||
success: gpui::rgb(0x86B300),
|
||||
warning: gpui::rgb(0xF2AE49),
|
||||
info: gpui::rgb(0x399EE6),
|
||||
foreground,
|
||||
muted,
|
||||
disabled_fg,
|
||||
|
||||
selection: gpui::rgb(0xD3EBFF),
|
||||
selection_foreground: gpui::rgb(0x5C6166),
|
||||
accent,
|
||||
focus_ring,
|
||||
|
||||
border,
|
||||
divider,
|
||||
|
||||
field_bg,
|
||||
field_border,
|
||||
field_placeholder,
|
||||
|
||||
hover,
|
||||
selection,
|
||||
selection_foreground,
|
||||
|
||||
backdrop,
|
||||
|
||||
error,
|
||||
success,
|
||||
warning,
|
||||
info,
|
||||
|
||||
high: error,
|
||||
medium: warning,
|
||||
low: success,
|
||||
|
||||
text: gpui::rgb(0x5C6166),
|
||||
text_size: Some(gpui::Size::new(14, 14)),
|
||||
|
||||
high: gpui::rgb(0xE65050),
|
||||
medium: gpui::rgb(0xF2AE49),
|
||||
low: gpui::rgb(0x86B300),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
use gpui::prelude::*;
|
||||
use gpui::{px, Pixels};
|
||||
|
||||
use crate::theme::Theme;
|
||||
|
||||
pub const CARD_RADIUS: Pixels = px(6.0);
|
||||
pub const CARD_PADDING: Pixels = px(8.0);
|
||||
pub const SECTION_GAP: Pixels = px(12.0);
|
||||
pub const INSET_GAP: Pixels = px(8.0);
|
||||
pub const ROOT_PADDING: Pixels = px(12.0);
|
||||
|
||||
pub fn card_style(div: gpui::Div, theme: &Theme) -> gpui::Div {
|
||||
div.bg(theme.card)
|
||||
.border_1()
|
||||
.border_color(theme.divider)
|
||||
.rounded(CARD_RADIUS)
|
||||
.p(CARD_PADDING)
|
||||
}
|
||||
|
||||
pub fn raised_style(div: gpui::Div, theme: &Theme) -> gpui::Div {
|
||||
div.bg(theme.raised)
|
||||
.border_1()
|
||||
.border_color(theme.divider)
|
||||
.rounded(CARD_RADIUS)
|
||||
.p(CARD_PADDING)
|
||||
}
|
||||
|
||||
pub fn panel_style(div: gpui::Div, theme: &Theme) -> gpui::Div {
|
||||
div.bg(theme.panel)
|
||||
.border_1()
|
||||
.border_color(theme.border)
|
||||
.rounded(CARD_RADIUS)
|
||||
}
|
||||
|
||||
pub fn field_style(div: gpui::Div, theme: &Theme, focused: bool) -> gpui::Div {
|
||||
div.bg(theme.field_bg)
|
||||
.border_1()
|
||||
.border_color(if focused {
|
||||
theme.focus_ring
|
||||
} else {
|
||||
theme.field_border
|
||||
})
|
||||
.rounded(CARD_RADIUS)
|
||||
.px_2()
|
||||
.py_1()
|
||||
}
|
||||
|
||||
pub fn divider_h(theme: &Theme) -> gpui::Div {
|
||||
gpui::div().w_full().h(px(1.0)).bg(theme.divider)
|
||||
}
|
||||
|
||||
pub fn divider_v(theme: &Theme) -> gpui::Div {
|
||||
gpui::div().h_full().w(px(1.0)).bg(theme.divider)
|
||||
}
|
||||
|
||||
pub fn section_header(label: &str, theme: &Theme) -> gpui::Div {
|
||||
gpui::div()
|
||||
.px_2()
|
||||
.py_1()
|
||||
.text_xs()
|
||||
.text_color(theme.muted)
|
||||
.child(label.to_uppercase())
|
||||
}
|
||||
|
||||
pub fn priority_badge(priority: &str, theme: &Theme) -> gpui::Div {
|
||||
let (bg, fg) = match priority {
|
||||
"High" | "H" => (Theme::alpha(theme.high, 0.15), theme.high),
|
||||
"Medium" | "M" => (Theme::alpha(theme.medium, 0.15), theme.medium),
|
||||
"Low" | "L" => (Theme::alpha(theme.low, 0.15), theme.low),
|
||||
_ => (gpui::rgba(0x00000000), theme.muted),
|
||||
};
|
||||
|
||||
gpui::div()
|
||||
.px_2()
|
||||
.py(px(2.0))
|
||||
.rounded(px(4.0))
|
||||
.bg(bg)
|
||||
.text_color(fg)
|
||||
.text_xs()
|
||||
.font_weight(gpui::FontWeight::MEDIUM)
|
||||
.child(priority.to_string())
|
||||
}
|
||||
+96
-112
@@ -1,6 +1,6 @@
|
||||
use crate::components::{label::Label, panel::Panel};
|
||||
use crate::models::{FilterState, ProjectTree};
|
||||
use crate::theme::ActiveTheme;
|
||||
use crate::ui::{divider_h, section_header};
|
||||
use gpui::{Context, Div, Entity, IntoElement, Window, div, prelude::*, px};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -100,9 +100,10 @@ impl Sidebar {
|
||||
.gap_2()
|
||||
.px_3()
|
||||
.py_1()
|
||||
.rounded_sm()
|
||||
.cursor_pointer()
|
||||
.when(is_all_selected, |this| this.bg(theme.selection))
|
||||
.hover(|style| style.bg(theme.panel))
|
||||
.when(!is_all_selected, |this| this.hover(|style| style.bg(theme.hover)))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|view, _event, window, cx| {
|
||||
@@ -149,9 +150,10 @@ impl Sidebar {
|
||||
.gap_1()
|
||||
.px_3()
|
||||
.py_1()
|
||||
.rounded_sm()
|
||||
.cursor_pointer()
|
||||
.when(is_selected, |this| this.bg(theme.selection))
|
||||
.hover(|style| style.bg(theme.panel))
|
||||
.when(!is_selected, |this| this.hover(|style| style.bg(theme.hover)))
|
||||
.child(div().w(px(indent as f32)))
|
||||
.child(
|
||||
div()
|
||||
@@ -230,9 +232,10 @@ impl Sidebar {
|
||||
.gap_2()
|
||||
.px_3()
|
||||
.py_1()
|
||||
.rounded_sm()
|
||||
.cursor_pointer()
|
||||
.when(is_active, |this| this.bg(theme.selection))
|
||||
.hover(|style| style.bg(theme.panel))
|
||||
.when(!is_active, |this| this.hover(|style| style.bg(theme.hover)))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(move |view, _event, window, cx| {
|
||||
@@ -279,115 +282,96 @@ impl Render for Sidebar {
|
||||
let has_project = filter.selected_project.is_some();
|
||||
let has_tags = !filter.active_tags.is_empty();
|
||||
|
||||
Panel::new("Sidebar").border(1.0).padding(0.0).child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.size_full()
|
||||
.bg(theme.background)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
div()
|
||||
.flex_shrink_0()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.px_3()
|
||||
.py_2()
|
||||
.border_b_1()
|
||||
.border_color(theme.border)
|
||||
.child(
|
||||
Label::new("PROJECTS")
|
||||
.text_sm()
|
||||
.font_weight(gpui::FontWeight::BOLD)
|
||||
.text_color(theme.foreground),
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.size_full()
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
div()
|
||||
.flex_shrink_0()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.px_2()
|
||||
.py_2()
|
||||
.child(section_header("Projects", &theme))
|
||||
.when(has_project, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.id("clear-project")
|
||||
.text_xs()
|
||||
.text_color(theme.muted)
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(theme.accent))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|view, _, window, cx| {
|
||||
view.handle_clear_project(window, cx);
|
||||
}),
|
||||
)
|
||||
.child("Clear"),
|
||||
)
|
||||
.when(has_project, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.id("clear-project")
|
||||
.text_xs()
|
||||
.text_color(theme.muted)
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(theme.accent))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|view, _, window, cx| {
|
||||
view.handle_clear_project(window, cx);
|
||||
}),
|
||||
)
|
||||
.child("Clear"),
|
||||
)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("sidebar-projects")
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.py_1()
|
||||
.overflow_y_scroll()
|
||||
.children(projects),
|
||||
),
|
||||
)
|
||||
.child(div().flex_shrink_0().h_px().bg(theme.border))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
div()
|
||||
.flex_shrink_0()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.px_3()
|
||||
.py_2()
|
||||
.border_b_1()
|
||||
.border_color(theme.border)
|
||||
.child(
|
||||
Label::new("TAGS")
|
||||
.text_sm()
|
||||
.font_weight(gpui::FontWeight::BOLD)
|
||||
.text_color(theme.foreground),
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("sidebar-projects")
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_y_scroll()
|
||||
.children(projects),
|
||||
),
|
||||
)
|
||||
.child(divider_h(&theme).my_1())
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
div()
|
||||
.flex_shrink_0()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.px_2()
|
||||
.py_2()
|
||||
.child(section_header("Tags", &theme))
|
||||
.when(has_tags, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.id("clear-tags")
|
||||
.text_xs()
|
||||
.text_color(theme.muted)
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(theme.accent))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|view, _, window, cx| {
|
||||
view.handle_clear_tags(window, cx);
|
||||
}),
|
||||
)
|
||||
.child("Clear"),
|
||||
)
|
||||
.when(has_tags, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.id("clear-tags")
|
||||
.text_xs()
|
||||
.text_color(theme.muted)
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.text_color(theme.accent))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|view, _, window, cx| {
|
||||
view.handle_clear_tags(window, cx);
|
||||
}),
|
||||
)
|
||||
.child("Clear"),
|
||||
)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("sidebar-tags")
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.py_1()
|
||||
.overflow_y_scroll()
|
||||
.children(tags),
|
||||
),
|
||||
),
|
||||
)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("sidebar-tags")
|
||||
.flex_1()
|
||||
.min_h_0()
|
||||
.overflow_y_scroll()
|
||||
.children(tags),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use gpui::{Context, IntoElement, Render, Window, div, prelude::*, px};
|
||||
|
||||
use crate::theme::ActiveTheme;
|
||||
use crate::ui::{card_style, CARD_RADIUS};
|
||||
|
||||
pub struct StatusBar {
|
||||
// TODO: Add vim_mode, sync_state, last_sync, etc.
|
||||
@@ -16,16 +17,14 @@ impl Render for StatusBar {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let theme = cx.theme().clone();
|
||||
|
||||
div()
|
||||
card_style(div(), &theme)
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.w_full()
|
||||
.h(px(30.0))
|
||||
.px_4()
|
||||
.h(px(28.0))
|
||||
.px_3()
|
||||
.py_1()
|
||||
.bg(theme.panel)
|
||||
.border_b_1()
|
||||
.border_color(theme.border)
|
||||
.rounded(CARD_RADIUS)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-23
@@ -13,6 +13,7 @@ use crate::{
|
||||
models::{DueFilter, FilterState, PriorityFilter, StatusFilter},
|
||||
task::{self, TaskFilter, TaskService},
|
||||
theme::{self, ActiveTheme},
|
||||
ui::priority_badge,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -604,15 +605,14 @@ impl TaskTable {
|
||||
let bar = gpui::div()
|
||||
.id("filter-bar")
|
||||
.flex()
|
||||
.flex_wrap()
|
||||
.gap_2()
|
||||
.gap_3()
|
||||
.items_center()
|
||||
.px_4()
|
||||
.py_2()
|
||||
.bg(theme.panel)
|
||||
.child(
|
||||
gpui::div()
|
||||
.w(gpui::rems(14.0))
|
||||
.flex_1()
|
||||
.min_w(gpui::rems(12.0))
|
||||
.child(self.search_input.clone()),
|
||||
)
|
||||
.child(self.status_dropdown.clone())
|
||||
@@ -622,13 +622,14 @@ impl TaskTable {
|
||||
this.child(
|
||||
gpui::div()
|
||||
.id("clear-all-filters")
|
||||
.flex_shrink_0()
|
||||
.px_2()
|
||||
.py_1()
|
||||
.rounded_md()
|
||||
.text_sm()
|
||||
.text_color(theme.error)
|
||||
.cursor_pointer()
|
||||
.hover(|s| s.bg(theme.selection))
|
||||
.hover(|s| s.bg(theme.hover))
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|table, _, _, cx| {
|
||||
@@ -702,10 +703,9 @@ impl TaskTable {
|
||||
.gap_2()
|
||||
.px_4()
|
||||
.py_2()
|
||||
.border_t_1()
|
||||
.border_color(theme.border)
|
||||
.bg(theme.raised)
|
||||
.border_b_1()
|
||||
.bg(theme.panel)
|
||||
.border_color(theme.divider)
|
||||
.text_sm()
|
||||
.font_weight(gpui::FontWeight::MEDIUM)
|
||||
.child(
|
||||
@@ -756,12 +756,12 @@ impl TaskTable {
|
||||
.px_4()
|
||||
.py_1()
|
||||
.border_b_1()
|
||||
.border_color(theme.border)
|
||||
.border_color(theme.divider)
|
||||
.text_color(theme.foreground)
|
||||
.when(selected, |d| {
|
||||
d.bg(theme.selection).text_color(theme.selection_foreground)
|
||||
})
|
||||
.when(!selected, |d| d.hover(|s| s.bg(theme.panel)))
|
||||
.when(!selected, |d| d.hover(|s| s.bg(theme.hover)))
|
||||
.cursor_pointer()
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
@@ -802,11 +802,9 @@ impl TaskTable {
|
||||
components::label::Label::new(row.due.clone()).text_color(self.due_color(row, cx)),
|
||||
))
|
||||
.child(
|
||||
gpui::div().w(gpui::rems(5.0)).child(
|
||||
components::label::Label::new(row.priority.clone())
|
||||
.text_color(self.priority_color(row, cx))
|
||||
.font_weight(gpui::FontWeight::BOLD),
|
||||
),
|
||||
gpui::div()
|
||||
.w(gpui::rems(5.0))
|
||||
.child(priority_badge(&row.priority, theme)),
|
||||
)
|
||||
.child(
|
||||
gpui::div().w(gpui::rems(6.0)).child(
|
||||
@@ -831,8 +829,8 @@ impl TaskTable {
|
||||
.px_4()
|
||||
.py_2()
|
||||
.border_t_1()
|
||||
.border_color(theme.border)
|
||||
.bg(theme.panel)
|
||||
.border_color(theme.divider)
|
||||
.bg(theme.raised)
|
||||
.text_sm()
|
||||
.child(
|
||||
components::label::Label::new(format!(
|
||||
@@ -866,13 +864,15 @@ impl TaskTable {
|
||||
.px_2()
|
||||
.py_1()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(theme.divider)
|
||||
.text_color(if can_prev {
|
||||
theme.foreground
|
||||
} else {
|
||||
theme.muted
|
||||
theme.disabled_fg
|
||||
})
|
||||
.when(can_prev, |d| {
|
||||
d.cursor_pointer().hover(|s| s.bg(theme.selection))
|
||||
d.cursor_pointer().hover(|s| s.bg(theme.hover))
|
||||
})
|
||||
.when(!can_prev, |d| d.cursor_not_allowed())
|
||||
.on_mouse_down(
|
||||
@@ -887,13 +887,15 @@ impl TaskTable {
|
||||
.px_2()
|
||||
.py_1()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(theme.divider)
|
||||
.text_color(if can_next {
|
||||
theme.foreground
|
||||
} else {
|
||||
theme.muted
|
||||
theme.disabled_fg
|
||||
})
|
||||
.when(can_next, |d| {
|
||||
d.cursor_pointer().hover(|s| s.bg(theme.selection))
|
||||
d.cursor_pointer().hover(|s| s.bg(theme.hover))
|
||||
})
|
||||
.when(!can_next, |d| d.cursor_not_allowed())
|
||||
.on_mouse_down(
|
||||
@@ -924,7 +926,7 @@ impl gpui::Render for TaskTable {
|
||||
.size_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.child(components::label::Label::new("Loading...").text_color(theme.text));
|
||||
.child(components::label::Label::new("Loading...").text_color(theme.foreground));
|
||||
}
|
||||
|
||||
let current_page = self.get_current_page_rows();
|
||||
@@ -945,7 +947,7 @@ impl gpui::Render for TaskTable {
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
.bg(theme.background)
|
||||
.child(gpui::div().h(self.filter_bar_height))
|
||||
.child(gpui::div().h(self.filter_bar_height).mb_4())
|
||||
.child(header)
|
||||
.child(
|
||||
gpui::div()
|
||||
|
||||
Reference in New Issue
Block a user