feat: Refine filters and dropdown UI for task table
Update task table filters and dropdowns, including due-date options, layout tweaks, and style polish. Keep panel style refinement intact so layout stays stable.
This commit is contained in:
@@ -3,17 +3,31 @@ use std::sync::Arc;
|
||||
use gpui::prelude::*;
|
||||
|
||||
use crate::components::button::Button;
|
||||
use crate::components::label::Label;
|
||||
use crate::theme::ActiveTheme;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DropdownItem {
|
||||
pub label: gpui::SharedString,
|
||||
pub value: gpui::SharedString,
|
||||
}
|
||||
|
||||
impl DropdownItem {
|
||||
pub fn new(label: impl Into<gpui::SharedString>) -> Self {
|
||||
let label = label.into();
|
||||
Self {
|
||||
value: label.clone(),
|
||||
label,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_value(
|
||||
label: impl Into<gpui::SharedString>,
|
||||
value: impl Into<gpui::SharedString>,
|
||||
) -> Self {
|
||||
Self {
|
||||
label: label.into(),
|
||||
value: value.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +41,7 @@ pub struct Dropdown {
|
||||
disabled: bool,
|
||||
loading: bool,
|
||||
placeholder: gpui::SharedString,
|
||||
label_prefix: Option<gpui::SharedString>,
|
||||
on_select: Option<Arc<dyn Fn(usize, &DropdownItem, &mut gpui::Context<Self>) + Send + Sync>>,
|
||||
}
|
||||
|
||||
@@ -41,6 +56,7 @@ impl Dropdown {
|
||||
disabled: false,
|
||||
loading: false,
|
||||
placeholder: "Seleccionar".into(),
|
||||
label_prefix: None,
|
||||
on_select: None,
|
||||
}
|
||||
}
|
||||
@@ -68,6 +84,11 @@ impl Dropdown {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn label_prefix(mut self, prefix: impl Into<gpui::SharedString>) -> Self {
|
||||
self.label_prefix = Some(prefix.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn selected_index(mut self, index: usize) -> Self {
|
||||
self.selected_index = Some(index);
|
||||
self
|
||||
@@ -108,6 +129,23 @@ impl Dropdown {
|
||||
.and_then(|index| self.items.get(index).map(|item| item.label.clone()))
|
||||
}
|
||||
|
||||
pub fn set_selected_index(&mut self, index: usize, cx: &mut gpui::Context<Self>) {
|
||||
if index < self.items.len() {
|
||||
self.selected_index = Some(index);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_items(&mut self, items: Vec<DropdownItem>, cx: &mut gpui::Context<Self>) {
|
||||
self.items = items;
|
||||
if let Some(selected) = self.selected_index {
|
||||
if selected >= self.items.len() {
|
||||
self.selected_index = None;
|
||||
}
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn toggle_open(&mut self, cx: &mut gpui::Context<Self>) {
|
||||
if self.disabled || self.loading || self.items.is_empty() {
|
||||
return;
|
||||
@@ -168,15 +206,21 @@ impl Dropdown {
|
||||
let is_selected = self.selected_index == Some(index);
|
||||
let mut row = gpui::div()
|
||||
.id(index)
|
||||
.w_full()
|
||||
.px_2()
|
||||
.py_1()
|
||||
.text_sm()
|
||||
.whitespace_nowrap()
|
||||
.bg(theme.background)
|
||||
.text_color(if is_selected {
|
||||
theme.selection_foreground
|
||||
} else {
|
||||
theme.foreground
|
||||
})
|
||||
.when(is_selected, |el| el.bg(theme.selection))
|
||||
.hover(|s: gpui::StyleRefinement| s.bg(theme.selection))
|
||||
.when(!is_disabled, |el| {
|
||||
el.hover(|s: gpui::StyleRefinement| s.bg(theme.selection))
|
||||
})
|
||||
.child(item.label.clone());
|
||||
|
||||
if is_disabled {
|
||||
@@ -198,13 +242,17 @@ impl Dropdown {
|
||||
.absolute()
|
||||
.top_full()
|
||||
.left_0()
|
||||
.right_0()
|
||||
.min_w(gpui::rems(12.0))
|
||||
.min_w_full()
|
||||
.mt_1()
|
||||
.occlude()
|
||||
.p_1()
|
||||
.border_1()
|
||||
.border_color(theme.border)
|
||||
.bg(theme.panel)
|
||||
.bg(theme.background)
|
||||
.rounded_md()
|
||||
.overflow_hidden()
|
||||
.shadow_lg()
|
||||
.children(items)
|
||||
.into_any_element()
|
||||
}
|
||||
@@ -216,28 +264,60 @@ impl gpui::Render for Dropdown {
|
||||
_window: &mut gpui::Window,
|
||||
cx: &mut gpui::Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let theme = cx.theme();
|
||||
let is_disabled = self.disabled || self.loading;
|
||||
let label = self
|
||||
let disabled = is_disabled || self.items.is_empty();
|
||||
let mut label = self
|
||||
.selected_label()
|
||||
.unwrap_or_else(|| self.placeholder.clone());
|
||||
|
||||
let mut trigger = if let Some(button) = self.button.clone() {
|
||||
let mut button = button;
|
||||
button.on_click = None;
|
||||
button.label = Some(label.clone());
|
||||
button.disabled(is_disabled).loading(self.loading)
|
||||
} else {
|
||||
Button::label(self.id.clone(), label)
|
||||
.disabled(is_disabled)
|
||||
.loading(self.loading)
|
||||
};
|
||||
|
||||
if is_disabled || self.items.is_empty() {
|
||||
trigger = trigger.disabled(true);
|
||||
if let Some(prefix) = &self.label_prefix {
|
||||
label = format!("{}: {}", prefix, label).into();
|
||||
}
|
||||
|
||||
let mut trigger_wrap = gpui::div().child(trigger);
|
||||
if !is_disabled && !self.items.is_empty() {
|
||||
let arrow = "▾";
|
||||
|
||||
let trigger: gpui::AnyElement = if let Some(button) = self.button.clone() {
|
||||
let mut button = button;
|
||||
button.on_click = None;
|
||||
button.label = Some(format!("{} {}", label, arrow).into());
|
||||
button
|
||||
.disabled(disabled)
|
||||
.loading(self.loading)
|
||||
.bg(theme.background)
|
||||
.border_color(theme.border)
|
||||
.text_color(theme.foreground)
|
||||
.into_any_element()
|
||||
} else {
|
||||
let mut trigger = gpui::div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.px_3()
|
||||
.py_2()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(theme.border)
|
||||
.bg(theme.background)
|
||||
.text_sm()
|
||||
.text_color(theme.foreground)
|
||||
.child(Label::new(label.clone()))
|
||||
.child(Label::new(arrow).text_color(theme.muted));
|
||||
|
||||
if disabled {
|
||||
trigger = trigger.text_color(theme.muted).cursor_not_allowed();
|
||||
} else {
|
||||
trigger = trigger
|
||||
.cursor_pointer()
|
||||
.hover(|s: gpui::StyleRefinement| s.bg(theme.selection));
|
||||
}
|
||||
|
||||
trigger.into_any_element()
|
||||
};
|
||||
|
||||
let mut trigger_wrap = gpui::div()
|
||||
.min_w(gpui::rems(12.0))
|
||||
.child(trigger);
|
||||
if !disabled {
|
||||
trigger_wrap = trigger_wrap.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(Self::handle_trigger_mouse_down),
|
||||
|
||||
Reference in New Issue
Block a user