calendar: Add small, medium, large size support to Calendar. (#393)

Fix #272
This commit is contained in:
Jason Lee 2024-11-04 19:25:30 +08:00 committed by GitHub
parent 1c5d63edb1
commit c2824eb01e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 110 additions and 41 deletions

View file

@ -4,11 +4,13 @@ use gpui::{
VisualContext as _, WindowContext,
};
use ui::{
button::Button,
date_picker::{DatePicker, DatePickerEvent, DateRangePreset},
v_flex, Sizable as _,
v_flex, Sizable as _, Size,
};
pub struct CalendarStory {
size: Size,
date_picker: View<DatePicker>,
date_picker_small: View<DatePicker>,
date_picker_large: View<DatePicker>,
@ -134,6 +136,7 @@ impl CalendarStory {
.detach();
Self {
size: Size::default(),
date_picker,
date_picker_large,
date_picker_small,
@ -142,6 +145,20 @@ impl CalendarStory {
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 {
@ -151,9 +168,18 @@ impl gpui::FocusableView 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()
.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_small.clone())
.child(self.date_picker_large.clone())

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use chrono::{Datelike, Local, NaiveDate};
use gpui::{
prelude::FluentBuilder as _, relative, ClickEvent, ElementId, EventEmitter, FocusHandle,
prelude::FluentBuilder as _, px, relative, ClickEvent, ElementId, EventEmitter, FocusHandle,
InteractiveElement, IntoElement, ParentElement, Render, SharedString,
StatefulInteractiveElement, Styled, ViewContext,
};
@ -12,7 +12,7 @@ use crate::{
button::{Button, ButtonStyled as _},
h_flex,
theme::ActiveTheme,
v_flex, Disableable as _, IconName, Selectable,
v_flex, Disableable as _, IconName, Selectable, Sizable, Size,
};
use super::utils::days_in_month;
@ -151,6 +151,7 @@ impl ViewMode {
pub struct Calendar {
focus_handle: FocusHandle,
size: Size,
date: Date,
view_mode: ViewMode,
current_year: i32,
@ -167,6 +168,7 @@ impl Calendar {
let today = Local::now().naive_local().date();
Self {
focus_handle: cx.focus_handle(),
size: Size::default(),
view_mode: ViewMode::Day,
date: Date::Single(None),
current_month: today.month() as u8,
@ -211,6 +213,11 @@ impl Calendar {
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>) {
self.number_of_months = number_of_months;
cx.notify();
@ -338,9 +345,11 @@ impl Calendar {
cx: &mut ViewContext<Self>,
) -> impl IntoElement {
h_flex()
.w_9()
.h_9()
.rounded_md()
.map(|this| match self.size {
Size::Small => this.size_7().rounded_sm(),
Size::Large => this.size_10().rounded_md(),
_ => this.size_9().rounded_md(),
})
.justify_center()
.text_color(cx.theme().muted_foreground)
.text_sm()
@ -358,9 +367,11 @@ impl Calendar {
) -> impl IntoElement + Styled + StatefulInteractiveElement {
h_flex()
.id(id.into())
.w_9()
.h_9()
.rounded_lg()
.map(|this| match self.size {
Size::Small => this.size_7().rounded_md(),
Size::Large => this.size_10().rounded_lg(),
_ => this.size_9().rounded_lg(),
})
.justify_center()
.cursor_pointer()
.when(muted, |this| {
@ -470,6 +481,11 @@ impl Calendar {
let current_year = self.current_year;
let disabled = self.view_mode.is_month();
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()
.gap_0p5()
@ -480,6 +496,7 @@ impl Calendar {
.icon(IconName::ArrowLeft)
.ghost()
.disabled(disabled)
.with_size(icon_size)
.when(self.view_mode.is_day(), |this| {
this.on_click(cx.listener(Self::prev_month))
})
@ -497,8 +514,9 @@ impl Calendar {
Button::new("month")
.ghost()
.label(self.month_name(0))
.selected(self.view_mode.is_month())
.compact()
.with_size(self.size)
.selected(self.view_mode.is_month())
.on_click(cx.listener(|view, _, cx| {
if view.view_mode.is_month() {
view.set_view_mode(ViewMode::Day, cx);
@ -513,6 +531,7 @@ impl Calendar {
.ghost()
.label(current_year.to_string())
.compact()
.with_size(self.size)
.selected(self.view_mode.is_year())
.on_click(cx.listener(|view, _, cx| {
if view.view_mode.is_year() {
@ -530,7 +549,11 @@ impl Calendar {
(0..self.number_of_months).map(|n| {
h_flex()
.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(current_year.to_string())
}),
@ -541,6 +564,7 @@ impl Calendar {
.icon(IconName::ArrowRight)
.ghost()
.disabled(disabled)
.with_size(icon_size)
.when(self.view_mode.is_day(), |this| {
this.on_click(cx.listener(Self::next_month))
})
@ -562,27 +586,32 @@ impl Calendar {
t!("Calendar.week.6"),
];
h_flex().gap_4().justify_between().text_sm().children(
self.days()
.chunks(5)
.enumerate()
.map(|(offset_month, days)| {
v_flex()
.gap_0p5()
.child(
h_flex().gap_0p5().justify_between().children(
h_flex()
.map(|this| match self.size {
Size::Small => this.gap_3().text_sm(),
Size::Large => this.gap_5().text_base(),
_ => this.gap_4().text_sm(),
})
.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)),
),
)
.children(days.iter().map(|week| {
h_flex().gap_0p5().justify_between().children(
week.iter()
.enumerate()
.map(|(ix, d)| self.render_day(ix, d, offset_month, cx)),
)
}))
}),
)
))
.children(days.iter().map(|week| {
h_flex().gap_0p5().justify_between().children(
week.iter()
.enumerate()
.map(|(ix, d)| self.render_day(ix, d, offset_month, cx)),
)
}))
}),
)
}
fn render_months(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
@ -592,6 +621,11 @@ impl Calendar {
.mt_3()
.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()
.flex_wrap()
.children(
@ -619,9 +653,12 @@ impl Calendar {
h_flex()
.id("years")
.mt_3()
.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()
.flex_wrap()
.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 Render for Calendar {

View file

@ -178,6 +178,12 @@ impl DatePicker {
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>) {
self.open = false;
self.focus_handle.focus(cx);
@ -239,13 +245,10 @@ impl Render for DatePicker {
.unwrap_or(placeholder.clone());
self.calendar.update(cx, |view, cx| {
view.set_size(self.size, 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()
.id(self.id.clone())
.key_context("DatePicker")
@ -304,12 +307,9 @@ impl Render for DatePicker {
div()
.track_focus(&self.focus_handle)
.occlude()
.absolute()
.mt_1p5()
.overflow_hidden()
.rounded_lg()
.p_3()
.w(px(popover_width))
.border_1()
.border_color(cx.theme().border)
.shadow_lg()