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, 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())

View file

@ -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 {

View file

@ -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()