From c2824eb01e12a5ab5a84bcbc383291583015ef04 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 4 Nov 2024 19:25:30 +0800 Subject: [PATCH] calendar: Add small, medium, large size support to Calendar. (#393) Fix #272 --- crates/story/src/calendar_story.rs | 30 +++++++- crates/ui/src/time/calendar.rs | 107 ++++++++++++++++++++--------- crates/ui/src/time/date_picker.rs | 14 ++-- 3 files changed, 110 insertions(+), 41 deletions(-) diff --git a/crates/story/src/calendar_story.rs b/crates/story/src/calendar_story.rs index 951e9aa7..e70f0e99 100644 --- a/crates/story/src/calendar_story.rs +++ b/crates/story/src/calendar_story.rs @@ -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, date_picker_small: View, date_picker_large: View, @@ -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.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) -> impl IntoElement { + fn render(&mut self, cx: &mut ViewContext) -> 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()) diff --git a/crates/ui/src/time/calendar.rs b/crates/ui/src/time/calendar.rs index 41fa6ace..0663c3b9 100644 --- a/crates/ui/src/time/calendar.rs +++ b/crates/ui/src/time/calendar.rs @@ -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.size = size; + cx.notify(); + } + pub fn set_number_of_months(&mut self, number_of_months: usize, cx: &mut ViewContext) { self.number_of_months = number_of_months; cx.notify(); @@ -338,9 +345,11 @@ impl Calendar { cx: &mut ViewContext, ) -> 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) -> 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) -> Self { + self.size = size.into(); + self + } +} impl EventEmitter for Calendar {} impl Render for Calendar { diff --git a/crates/ui/src/time/date_picker.rs b/crates/ui/src/time/date_picker.rs index 5b830ff4..95e573d5 100644 --- a/crates/ui/src/time/date_picker.rs +++ b/crates/ui/src/time/date_picker.rs @@ -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.size = size; + cx.notify(); + } + fn escape(&mut self, _: &Escape, cx: &mut ViewContext) { 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()