Add the Preset Ranges and add border for today (#365)
Preset Ranges have been added. The “Today” border has also been added.  --------- Co-authored-by: Jason Lee <huacnlee@gmail.com>
This commit is contained in:
parent
a798bd81c6
commit
8dbf1dd5d5
3 changed files with 135 additions and 10 deletions
|
|
@ -1,10 +1,10 @@
|
|||
use chrono::Days;
|
||||
use chrono::{Days, Duration, Utc};
|
||||
use gpui::{
|
||||
px, IntoElement, ParentElement as _, Render, Styled as _, View, ViewContext,
|
||||
VisualContext as _, WindowContext,
|
||||
};
|
||||
use ui::{
|
||||
date_picker::{DatePicker, DatePickerEvent},
|
||||
date_picker::{DatePicker, DatePickerEvent, DateRangePreset},
|
||||
v_flex, Sizable as _,
|
||||
};
|
||||
|
||||
|
|
@ -37,11 +37,48 @@ impl CalendarStory {
|
|||
}
|
||||
|
||||
fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||
let presets = vec![
|
||||
DateRangePreset::single(
|
||||
"Yesterday",
|
||||
(Utc::now() - Duration::days(1)).naive_local().date(),
|
||||
),
|
||||
DateRangePreset::single(
|
||||
"Last Week",
|
||||
(Utc::now() - Duration::weeks(1)).naive_local().date(),
|
||||
),
|
||||
DateRangePreset::single(
|
||||
"Last Month",
|
||||
(Utc::now() - Duration::days(30)).naive_local().date(),
|
||||
),
|
||||
];
|
||||
let range_presets = vec![
|
||||
DateRangePreset::range(
|
||||
"Last 7 Days",
|
||||
(Utc::now() - Duration::days(7)).naive_local().date(),
|
||||
Utc::now().naive_local().date(),
|
||||
),
|
||||
DateRangePreset::range(
|
||||
"Last 14 Days",
|
||||
(Utc::now() - Duration::days(14)).naive_local().date(),
|
||||
Utc::now().naive_local().date(),
|
||||
),
|
||||
DateRangePreset::range(
|
||||
"Last 30 Days",
|
||||
(Utc::now() - Duration::days(30)).naive_local().date(),
|
||||
Utc::now().naive_local().date(),
|
||||
),
|
||||
DateRangePreset::range(
|
||||
"Last 90 Days",
|
||||
(Utc::now() - Duration::days(90)).naive_local().date(),
|
||||
Utc::now().naive_local().date(),
|
||||
),
|
||||
];
|
||||
let now = chrono::Local::now().naive_local().date();
|
||||
let date_picker = cx.new_view(|cx| {
|
||||
let mut picker = DatePicker::new("date_picker_medium", cx)
|
||||
.cleanable()
|
||||
.width(px(220.));
|
||||
.width(px(220.))
|
||||
.presets(presets);
|
||||
picker.set_date(now, cx);
|
||||
picker
|
||||
});
|
||||
|
|
@ -62,7 +99,8 @@ impl CalendarStory {
|
|||
let mut picker = DatePicker::new("date_range_picker", cx)
|
||||
.width(px(300.))
|
||||
.number_of_months(2)
|
||||
.cleanable();
|
||||
.cleanable()
|
||||
.presets(range_presets.clone());
|
||||
picker.set_date((now, now.checked_add_days(Days::new(4)).unwrap()), cx);
|
||||
picker
|
||||
});
|
||||
|
|
@ -85,6 +123,7 @@ impl CalendarStory {
|
|||
.width(px(300.))
|
||||
.placeholder("Range mode picker")
|
||||
.cleanable()
|
||||
.presets(range_presets.clone())
|
||||
});
|
||||
|
||||
cx.subscribe(&default_range_mode_picker, |this, _, ev, _| match ev {
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ pub struct Calendar {
|
|||
year_page: i32,
|
||||
/// Number of the months view to show.
|
||||
number_of_months: usize,
|
||||
today: NaiveDate,
|
||||
}
|
||||
|
||||
impl Calendar {
|
||||
|
|
@ -173,6 +174,7 @@ impl Calendar {
|
|||
years: vec![],
|
||||
year_page: 0,
|
||||
number_of_months: 1,
|
||||
today,
|
||||
}
|
||||
.year_range((today.year() - 50, today.year() + 50))
|
||||
}
|
||||
|
|
@ -399,6 +401,7 @@ impl Calendar {
|
|||
let is_in_range = self.date.is_in_range(d);
|
||||
|
||||
let date = *d;
|
||||
let is_today = *d == self.today;
|
||||
|
||||
self.item_button(
|
||||
ix,
|
||||
|
|
@ -408,6 +411,9 @@ impl Calendar {
|
|||
!is_current_month,
|
||||
cx,
|
||||
)
|
||||
.when(is_today && !is_active, |this| {
|
||||
this.border_1().border_color(cx.theme().border)
|
||||
}) // Add border for today
|
||||
.on_click(cx.listener(move |view, _: &ClickEvent, cx| {
|
||||
if view.date.is_single() {
|
||||
view.set_date(date, cx);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
use chrono::NaiveDate;
|
||||
use gpui::{
|
||||
anchored, deferred, div, prelude::FluentBuilder as _, px, AppContext, ElementId, EventEmitter,
|
||||
FocusHandle, FocusableView, InteractiveElement as _, KeyBinding, Length, MouseButton,
|
||||
ParentElement as _, Render, SharedString, StatefulInteractiveElement as _, Styled as _, View,
|
||||
ParentElement as _, Render, SharedString, StatefulInteractiveElement as _, Styled, View,
|
||||
ViewContext, VisualContext as _,
|
||||
};
|
||||
use rust_i18n::t;
|
||||
|
||||
use crate::{
|
||||
dropdown::Escape, h_flex, input::ClearButton, theme::ActiveTheme as _, Icon, IconName, Sizable,
|
||||
Size, StyleSized as _, StyledExt as _,
|
||||
button::{Button, ButtonStyled as _},
|
||||
dropdown::Escape,
|
||||
h_flex,
|
||||
input::ClearButton,
|
||||
theme::ActiveTheme,
|
||||
v_flex, Icon, IconName, Sizable, Size, StyleSized as _, StyledExt as _,
|
||||
};
|
||||
|
||||
use super::calendar::{Calendar, CalendarEvent, Date};
|
||||
|
|
@ -23,6 +28,34 @@ pub enum DatePickerEvent {
|
|||
Change(Date),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum DateRangePresetValue {
|
||||
Single(NaiveDate),
|
||||
Range(NaiveDate, NaiveDate),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DateRangePreset {
|
||||
label: SharedString,
|
||||
value: DateRangePresetValue,
|
||||
}
|
||||
|
||||
impl DateRangePreset {
|
||||
/// Creates a new DateRangePreset with single date.
|
||||
pub fn single(label: impl Into<SharedString>, single: NaiveDate) -> Self {
|
||||
DateRangePreset {
|
||||
label: label.into(),
|
||||
value: DateRangePresetValue::Single(single),
|
||||
}
|
||||
}
|
||||
/// Creates a new DateRangePreset with a range of dates.
|
||||
pub fn range(label: impl Into<SharedString>, start: NaiveDate, end: NaiveDate) -> Self {
|
||||
DateRangePreset {
|
||||
label: label.into(),
|
||||
value: DateRangePresetValue::Range(start, end),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct DatePicker {
|
||||
id: ElementId,
|
||||
focus_handle: FocusHandle,
|
||||
|
|
@ -35,6 +68,7 @@ pub struct DatePicker {
|
|||
date_format: SharedString,
|
||||
calendar: View<Calendar>,
|
||||
number_of_months: usize,
|
||||
presets: Option<Vec<DateRangePreset>>,
|
||||
}
|
||||
|
||||
impl DatePicker {
|
||||
|
|
@ -82,6 +116,7 @@ impl DatePicker {
|
|||
cleanable: false,
|
||||
number_of_months: 1,
|
||||
placeholder: None,
|
||||
presets: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +150,12 @@ impl DatePicker {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set preset ranges for the date picker.
|
||||
pub fn presets(mut self, presets: Vec<DateRangePreset>) -> Self {
|
||||
self.presets = Some(presets);
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the date of the date picker.
|
||||
pub fn date(&self) -> Date {
|
||||
self.date
|
||||
|
|
@ -158,6 +199,17 @@ impl DatePicker {
|
|||
self.open = !self.open;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn select_preset(&mut self, preset: &DateRangePreset, cx: &mut ViewContext<Self>) {
|
||||
match preset.value {
|
||||
DateRangePresetValue::Single(single) => {
|
||||
self.update_date(Date::Single(Some(single)), true, cx)
|
||||
}
|
||||
DateRangePresetValue::Range(start, end) => {
|
||||
self.update_date(Date::Range(Some(start), Some(end)), true, cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<DatePickerEvent> for DatePicker {}
|
||||
|
|
@ -190,8 +242,9 @@ impl Render for DatePicker {
|
|||
view.set_number_of_months(self.number_of_months, cx);
|
||||
});
|
||||
|
||||
let popover_width =
|
||||
285.0 * self.number_of_months as f32 + (self.number_of_months - 1) as f32 * 16.0;
|
||||
let popover_width = self.presets.as_ref().map_or(0.0, |_| 136.0)
|
||||
+ 285.0 * self.number_of_months as f32
|
||||
+ (self.number_of_months - 1) as f32 * 16.0;
|
||||
|
||||
div()
|
||||
.id(self.id.clone())
|
||||
|
|
@ -266,7 +319,34 @@ impl Render for DatePicker {
|
|||
MouseButton::Left,
|
||||
cx.listener(|view, _, cx| view.escape(&Escape, cx)),
|
||||
)
|
||||
.child(self.calendar.clone()),
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_3()
|
||||
.h_full()
|
||||
.items_start()
|
||||
.when_some(self.presets.clone(), |this, presets| {
|
||||
this.child(
|
||||
v_flex().my_1().gap_2().justify_end().children(
|
||||
presets.into_iter().enumerate().map(
|
||||
|(i, preset)| {
|
||||
Button::new(("preset", i))
|
||||
.small()
|
||||
.ghost()
|
||||
.label(preset.label.clone())
|
||||
.on_click(cx.listener(
|
||||
move |this, _, cx| {
|
||||
this.select_preset(
|
||||
&preset, cx,
|
||||
);
|
||||
},
|
||||
))
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
.child(self.calendar.clone()),
|
||||
),
|
||||
),
|
||||
)
|
||||
.with_priority(2),
|
||||
|
|
|
|||
Loading…
Reference in a new issue