calendar: Add small, medium, large size support to Calendar. (#393)
Fix #272
This commit is contained in:
parent
1c5d63edb1
commit
c2824eb01e
3 changed files with 110 additions and 41 deletions
|
|
@ -4,11 +4,13 @@ use gpui::{
|
||||||
VisualContext as _, WindowContext,
|
VisualContext as _, WindowContext,
|
||||||
};
|
};
|
||||||
use ui::{
|
use ui::{
|
||||||
|
button::Button,
|
||||||
date_picker::{DatePicker, DatePickerEvent, DateRangePreset},
|
date_picker::{DatePicker, DatePickerEvent, DateRangePreset},
|
||||||
v_flex, Sizable as _,
|
v_flex, Sizable as _, Size,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CalendarStory {
|
pub struct CalendarStory {
|
||||||
|
size: Size,
|
||||||
date_picker: View<DatePicker>,
|
date_picker: View<DatePicker>,
|
||||||
date_picker_small: View<DatePicker>,
|
date_picker_small: View<DatePicker>,
|
||||||
date_picker_large: View<DatePicker>,
|
date_picker_large: View<DatePicker>,
|
||||||
|
|
@ -134,6 +136,7 @@ impl CalendarStory {
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
size: Size::default(),
|
||||||
date_picker,
|
date_picker,
|
||||||
date_picker_large,
|
date_picker_large,
|
||||||
date_picker_small,
|
date_picker_small,
|
||||||
|
|
@ -142,6 +145,20 @@ impl CalendarStory {
|
||||||
date_picker_value: None,
|
date_picker_value: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn change_size(&mut self, size: Size, cx: &mut ViewContext<Self>) {
|
||||||
|
self.size = size;
|
||||||
|
self.date_picker
|
||||||
|
.update(cx, |picker, cx| picker.set_size(size, cx));
|
||||||
|
self.date_picker_large
|
||||||
|
.update(cx, |picker, cx| picker.set_size(size, cx));
|
||||||
|
self.date_picker_small
|
||||||
|
.update(cx, |picker, cx| picker.set_size(size, cx));
|
||||||
|
self.date_range_picker
|
||||||
|
.update(cx, |picker, cx| picker.set_size(size, cx));
|
||||||
|
self.default_range_mode_picker
|
||||||
|
.update(cx, |picker, cx| picker.set_size(size, cx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl gpui::FocusableView for CalendarStory {
|
impl gpui::FocusableView for CalendarStory {
|
||||||
|
|
@ -151,9 +168,18 @@ impl gpui::FocusableView for CalendarStory {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for CalendarStory {
|
impl Render for CalendarStory {
|
||||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_3()
|
.gap_3()
|
||||||
|
.child(
|
||||||
|
Button::new("change-size")
|
||||||
|
.label(format!("size: {:?}", self.size))
|
||||||
|
.on_click(cx.listener(|this, _, cx| match this.size {
|
||||||
|
Size::Small => this.change_size(Size::Medium, cx),
|
||||||
|
Size::Large => this.change_size(Size::Small, cx),
|
||||||
|
_ => this.change_size(Size::Large, cx),
|
||||||
|
})),
|
||||||
|
)
|
||||||
.child(self.date_picker.clone())
|
.child(self.date_picker.clone())
|
||||||
.child(self.date_picker_small.clone())
|
.child(self.date_picker_small.clone())
|
||||||
.child(self.date_picker_large.clone())
|
.child(self.date_picker_large.clone())
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use chrono::{Datelike, Local, NaiveDate};
|
use chrono::{Datelike, Local, NaiveDate};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
prelude::FluentBuilder as _, relative, ClickEvent, ElementId, EventEmitter, FocusHandle,
|
prelude::FluentBuilder as _, px, relative, ClickEvent, ElementId, EventEmitter, FocusHandle,
|
||||||
InteractiveElement, IntoElement, ParentElement, Render, SharedString,
|
InteractiveElement, IntoElement, ParentElement, Render, SharedString,
|
||||||
StatefulInteractiveElement, Styled, ViewContext,
|
StatefulInteractiveElement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
button::{Button, ButtonStyled as _},
|
button::{Button, ButtonStyled as _},
|
||||||
h_flex,
|
h_flex,
|
||||||
theme::ActiveTheme,
|
theme::ActiveTheme,
|
||||||
v_flex, Disableable as _, IconName, Selectable,
|
v_flex, Disableable as _, IconName, Selectable, Sizable, Size,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::utils::days_in_month;
|
use super::utils::days_in_month;
|
||||||
|
|
@ -151,6 +151,7 @@ impl ViewMode {
|
||||||
|
|
||||||
pub struct Calendar {
|
pub struct Calendar {
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
|
size: Size,
|
||||||
date: Date,
|
date: Date,
|
||||||
view_mode: ViewMode,
|
view_mode: ViewMode,
|
||||||
current_year: i32,
|
current_year: i32,
|
||||||
|
|
@ -167,6 +168,7 @@ impl Calendar {
|
||||||
let today = Local::now().naive_local().date();
|
let today = Local::now().naive_local().date();
|
||||||
Self {
|
Self {
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
size: Size::default(),
|
||||||
view_mode: ViewMode::Day,
|
view_mode: ViewMode::Day,
|
||||||
date: Date::Single(None),
|
date: Date::Single(None),
|
||||||
current_month: today.month() as u8,
|
current_month: today.month() as u8,
|
||||||
|
|
@ -211,6 +213,11 @@ impl Calendar {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_size(&mut self, size: Size, cx: &mut ViewContext<Self>) {
|
||||||
|
self.size = size;
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_number_of_months(&mut self, number_of_months: usize, cx: &mut ViewContext<Self>) {
|
pub fn set_number_of_months(&mut self, number_of_months: usize, cx: &mut ViewContext<Self>) {
|
||||||
self.number_of_months = number_of_months;
|
self.number_of_months = number_of_months;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
@ -338,9 +345,11 @@ impl Calendar {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
h_flex()
|
h_flex()
|
||||||
.w_9()
|
.map(|this| match self.size {
|
||||||
.h_9()
|
Size::Small => this.size_7().rounded_sm(),
|
||||||
.rounded_md()
|
Size::Large => this.size_10().rounded_md(),
|
||||||
|
_ => this.size_9().rounded_md(),
|
||||||
|
})
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.text_color(cx.theme().muted_foreground)
|
.text_color(cx.theme().muted_foreground)
|
||||||
.text_sm()
|
.text_sm()
|
||||||
|
|
@ -358,9 +367,11 @@ impl Calendar {
|
||||||
) -> impl IntoElement + Styled + StatefulInteractiveElement {
|
) -> impl IntoElement + Styled + StatefulInteractiveElement {
|
||||||
h_flex()
|
h_flex()
|
||||||
.id(id.into())
|
.id(id.into())
|
||||||
.w_9()
|
.map(|this| match self.size {
|
||||||
.h_9()
|
Size::Small => this.size_7().rounded_md(),
|
||||||
.rounded_lg()
|
Size::Large => this.size_10().rounded_lg(),
|
||||||
|
_ => this.size_9().rounded_lg(),
|
||||||
|
})
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.cursor_pointer()
|
.cursor_pointer()
|
||||||
.when(muted, |this| {
|
.when(muted, |this| {
|
||||||
|
|
@ -470,6 +481,11 @@ impl Calendar {
|
||||||
let current_year = self.current_year;
|
let current_year = self.current_year;
|
||||||
let disabled = self.view_mode.is_month();
|
let disabled = self.view_mode.is_month();
|
||||||
let multiple_months = self.number_of_months > 1;
|
let multiple_months = self.number_of_months > 1;
|
||||||
|
let icon_size = match self.size {
|
||||||
|
Size::Small => Size::Small,
|
||||||
|
Size::Large => Size::Medium,
|
||||||
|
_ => Size::Medium,
|
||||||
|
};
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_0p5()
|
.gap_0p5()
|
||||||
|
|
@ -480,6 +496,7 @@ impl Calendar {
|
||||||
.icon(IconName::ArrowLeft)
|
.icon(IconName::ArrowLeft)
|
||||||
.ghost()
|
.ghost()
|
||||||
.disabled(disabled)
|
.disabled(disabled)
|
||||||
|
.with_size(icon_size)
|
||||||
.when(self.view_mode.is_day(), |this| {
|
.when(self.view_mode.is_day(), |this| {
|
||||||
this.on_click(cx.listener(Self::prev_month))
|
this.on_click(cx.listener(Self::prev_month))
|
||||||
})
|
})
|
||||||
|
|
@ -497,8 +514,9 @@ impl Calendar {
|
||||||
Button::new("month")
|
Button::new("month")
|
||||||
.ghost()
|
.ghost()
|
||||||
.label(self.month_name(0))
|
.label(self.month_name(0))
|
||||||
.selected(self.view_mode.is_month())
|
|
||||||
.compact()
|
.compact()
|
||||||
|
.with_size(self.size)
|
||||||
|
.selected(self.view_mode.is_month())
|
||||||
.on_click(cx.listener(|view, _, cx| {
|
.on_click(cx.listener(|view, _, cx| {
|
||||||
if view.view_mode.is_month() {
|
if view.view_mode.is_month() {
|
||||||
view.set_view_mode(ViewMode::Day, cx);
|
view.set_view_mode(ViewMode::Day, cx);
|
||||||
|
|
@ -513,6 +531,7 @@ impl Calendar {
|
||||||
.ghost()
|
.ghost()
|
||||||
.label(current_year.to_string())
|
.label(current_year.to_string())
|
||||||
.compact()
|
.compact()
|
||||||
|
.with_size(self.size)
|
||||||
.selected(self.view_mode.is_year())
|
.selected(self.view_mode.is_year())
|
||||||
.on_click(cx.listener(|view, _, cx| {
|
.on_click(cx.listener(|view, _, cx| {
|
||||||
if view.view_mode.is_year() {
|
if view.view_mode.is_year() {
|
||||||
|
|
@ -530,7 +549,11 @@ impl Calendar {
|
||||||
(0..self.number_of_months).map(|n| {
|
(0..self.number_of_months).map(|n| {
|
||||||
h_flex()
|
h_flex()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.gap_3()
|
.map(|this| match self.size {
|
||||||
|
Size::Small => this.gap_2(),
|
||||||
|
Size::Large => this.gap_4(),
|
||||||
|
_ => this.gap_3(),
|
||||||
|
})
|
||||||
.child(self.month_name(n))
|
.child(self.month_name(n))
|
||||||
.child(current_year.to_string())
|
.child(current_year.to_string())
|
||||||
}),
|
}),
|
||||||
|
|
@ -541,6 +564,7 @@ impl Calendar {
|
||||||
.icon(IconName::ArrowRight)
|
.icon(IconName::ArrowRight)
|
||||||
.ghost()
|
.ghost()
|
||||||
.disabled(disabled)
|
.disabled(disabled)
|
||||||
|
.with_size(icon_size)
|
||||||
.when(self.view_mode.is_day(), |this| {
|
.when(self.view_mode.is_day(), |this| {
|
||||||
this.on_click(cx.listener(Self::next_month))
|
this.on_click(cx.listener(Self::next_month))
|
||||||
})
|
})
|
||||||
|
|
@ -562,27 +586,32 @@ impl Calendar {
|
||||||
t!("Calendar.week.6"),
|
t!("Calendar.week.6"),
|
||||||
];
|
];
|
||||||
|
|
||||||
h_flex().gap_4().justify_between().text_sm().children(
|
h_flex()
|
||||||
self.days()
|
.map(|this| match self.size {
|
||||||
.chunks(5)
|
Size::Small => this.gap_3().text_sm(),
|
||||||
.enumerate()
|
Size::Large => this.gap_5().text_base(),
|
||||||
.map(|(offset_month, days)| {
|
_ => this.gap_4().text_sm(),
|
||||||
v_flex()
|
})
|
||||||
.gap_0p5()
|
.justify_between()
|
||||||
.child(
|
.children(
|
||||||
h_flex().gap_0p5().justify_between().children(
|
self.days()
|
||||||
|
.chunks(5)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(offset_month, days)| {
|
||||||
|
v_flex()
|
||||||
|
.gap_0p5()
|
||||||
|
.child(h_flex().gap_0p5().justify_between().children(
|
||||||
weeks.iter().map(|week| self.render_week(week.clone(), cx)),
|
weeks.iter().map(|week| self.render_week(week.clone(), cx)),
|
||||||
),
|
))
|
||||||
)
|
.children(days.iter().map(|week| {
|
||||||
.children(days.iter().map(|week| {
|
h_flex().gap_0p5().justify_between().children(
|
||||||
h_flex().gap_0p5().justify_between().children(
|
week.iter()
|
||||||
week.iter()
|
.enumerate()
|
||||||
.enumerate()
|
.map(|(ix, d)| self.render_day(ix, d, offset_month, cx)),
|
||||||
.map(|(ix, d)| self.render_day(ix, d, offset_month, cx)),
|
)
|
||||||
)
|
}))
|
||||||
}))
|
}),
|
||||||
}),
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_months(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render_months(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
|
@ -592,6 +621,11 @@ impl Calendar {
|
||||||
.mt_3()
|
.mt_3()
|
||||||
.gap_0p5()
|
.gap_0p5()
|
||||||
.gap_y_3()
|
.gap_y_3()
|
||||||
|
.map(|this| match self.size {
|
||||||
|
Size::Small => this.mt_2().gap_y_2().w(px(208.)),
|
||||||
|
Size::Large => this.mt_4().gap_y_4().w(px(292.)),
|
||||||
|
_ => this.mt_3().gap_y_3().w(px(264.)),
|
||||||
|
})
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.flex_wrap()
|
.flex_wrap()
|
||||||
.children(
|
.children(
|
||||||
|
|
@ -619,9 +653,12 @@ impl Calendar {
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id("years")
|
.id("years")
|
||||||
.mt_3()
|
|
||||||
.gap_0p5()
|
.gap_0p5()
|
||||||
.gap_y_3()
|
.map(|this| match self.size {
|
||||||
|
Size::Small => this.mt_2().gap_y_2().w(px(208.)),
|
||||||
|
Size::Large => this.mt_4().gap_y_4().w(px(292.)),
|
||||||
|
_ => this.mt_3().gap_y_3().w(px(264.)),
|
||||||
|
})
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.flex_wrap()
|
.flex_wrap()
|
||||||
.children(
|
.children(
|
||||||
|
|
@ -645,6 +682,12 @@ impl Calendar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sizable for Calendar {
|
||||||
|
fn with_size(mut self, size: impl Into<Size>) -> Self {
|
||||||
|
self.size = size.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
impl EventEmitter<CalendarEvent> for Calendar {}
|
impl EventEmitter<CalendarEvent> for Calendar {}
|
||||||
|
|
||||||
impl Render for Calendar {
|
impl Render for Calendar {
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,12 @@ impl DatePicker {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set size of the date picker.
|
||||||
|
pub fn set_size(&mut self, size: Size, cx: &mut ViewContext<Self>) {
|
||||||
|
self.size = size;
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
fn escape(&mut self, _: &Escape, cx: &mut ViewContext<Self>) {
|
fn escape(&mut self, _: &Escape, cx: &mut ViewContext<Self>) {
|
||||||
self.open = false;
|
self.open = false;
|
||||||
self.focus_handle.focus(cx);
|
self.focus_handle.focus(cx);
|
||||||
|
|
@ -239,13 +245,10 @@ impl Render for DatePicker {
|
||||||
.unwrap_or(placeholder.clone());
|
.unwrap_or(placeholder.clone());
|
||||||
|
|
||||||
self.calendar.update(cx, |view, cx| {
|
self.calendar.update(cx, |view, cx| {
|
||||||
|
view.set_size(self.size, cx);
|
||||||
view.set_number_of_months(self.number_of_months, cx);
|
view.set_number_of_months(self.number_of_months, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
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()
|
div()
|
||||||
.id(self.id.clone())
|
.id(self.id.clone())
|
||||||
.key_context("DatePicker")
|
.key_context("DatePicker")
|
||||||
|
|
@ -304,12 +307,9 @@ impl Render for DatePicker {
|
||||||
div()
|
div()
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.occlude()
|
.occlude()
|
||||||
.absolute()
|
|
||||||
.mt_1p5()
|
.mt_1p5()
|
||||||
.overflow_hidden()
|
|
||||||
.rounded_lg()
|
.rounded_lg()
|
||||||
.p_3()
|
.p_3()
|
||||||
.w(px(popover_width))
|
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_color(cx.theme().border)
|
.border_color(cx.theme().border)
|
||||||
.shadow_lg()
|
.shadow_lg()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue