From 6c9e0c397fcb8a2cde9814499763327494c6a47f Mon Sep 17 00:00:00 2001 From: luoxiaozero <48741584+luoxiaozero@users.noreply.github.com> Date: Mon, 18 Dec 2023 22:05:11 +0800 Subject: [PATCH] Feat/date picker (#53) * feat: add date picker component * feat: add date panel * feat: add month panel * feat: add month panel logic * feat: add year panel * style: date picker component * feat: optimized date picker style * fix: nightly mode build --- Cargo.toml | 3 + demo/src/app.rs | 1 + demo/src/pages/components.rs | 6 +- demo/src/pages/date_picker/mod.rs | 58 ++++++++ demo/src/pages/mod.rs | 2 + src/calendar/mod.rs | 8 +- src/date_picker/date-picker.css | 174 ++++++++++++++++++++++++ src/date_picker/mod.rs | 89 ++++++++++++ src/date_picker/panel/date_panel.rs | 194 +++++++++++++++++++++++++++ src/date_picker/panel/mod.rs | 135 +++++++++++++++++++ src/date_picker/panel/month_panel.rs | 89 ++++++++++++ src/date_picker/panel/year_panel.rs | 89 ++++++++++++ src/date_picker/theme.rs | 29 ++++ src/lib.rs | 2 + src/theme/mod.rs | 9 +- src/utils/mod.rs | 2 + src/utils/time.rs | 5 + 17 files changed, 887 insertions(+), 8 deletions(-) create mode 100644 demo/src/pages/date_picker/mod.rs create mode 100644 src/date_picker/date-picker.css create mode 100644 src/date_picker/mod.rs create mode 100644 src/date_picker/panel/date_panel.rs create mode 100644 src/date_picker/panel/mod.rs create mode 100644 src/date_picker/panel/month_panel.rs create mode 100644 src/date_picker/panel/year_panel.rs create mode 100644 src/date_picker/theme.rs create mode 100644 src/utils/time.rs diff --git a/Cargo.toml b/Cargo.toml index 14dec62..7051df6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,9 @@ icondata = { version = "0.1.0", features = [ "AiMinusOutlined", "AiRightOutlined", "AiClockCircleOutlined", + "AiCalendarOutlined", + "AiArrowLeftOutlined", + "AiArrowRightOutlined", ] } icondata_core = "0.0.2" uuid = { version = "1.5.0", features = ["v4"] } diff --git a/demo/src/app.rs b/demo/src/app.rs index 32f3270..9fada06 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -80,6 +80,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index a83bd2a..c5ead86 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -126,13 +126,17 @@ pub(crate) fn gen_menu_data() -> Vec { value: "checkbox".into(), label: "Checkbox".into(), }, + MenuItemOption { + value: "date-picker".into(), + label: "Date Picker".into(), + }, MenuItemOption { value: "input".into(), label: "Input".into(), }, MenuItemOption { value: "input-number".into(), - label: "InputNumber".into(), + label: "Input Number".into(), }, MenuItemOption { value: "radio".into(), diff --git a/demo/src/pages/date_picker/mod.rs b/demo/src/pages/date_picker/mod.rs new file mode 100644 index 0000000..0a7a3e7 --- /dev/null +++ b/demo/src/pages/date_picker/mod.rs @@ -0,0 +1,58 @@ +use crate::components::{Demo, DemoCode}; +use leptos::*; +use prisms::highlight_str; +use thaw::chrono::prelude::*; +use thaw::*; + +#[component] +pub fn DatePickerPage() -> impl IntoView { + let value = create_rw_signal(Some(Local::now().date_naive())); + view! { +
+

"Date Picker"

+ + + + + {highlight_str!( + r#" + use thaw::chrono::prelude::*; + + let value = create_rw_signal(Some(Local::now().date_naive())); + view! { + + } + "#, + "rust" + )} + + + +

"DatePicker Props"

+ + + + + + + + + + + + + + + + + +
"Name""Type""Default""Description"
"value" + "RwSignal>" + + "Default::default()" + + "Set the date picker value" +
+
+ } +} diff --git a/demo/src/pages/mod.rs b/demo/src/pages/mod.rs index 1e0c7c0..a813b43 100644 --- a/demo/src/pages/mod.rs +++ b/demo/src/pages/mod.rs @@ -9,6 +9,7 @@ mod card; mod checkbox; mod color_picker; mod components; +mod date_picker; mod divider; mod grid; mod guide; @@ -53,6 +54,7 @@ pub use card::*; pub use checkbox::*; pub use color_picker::*; pub use components::*; +pub use date_picker::*; pub use divider::*; pub use grid::*; pub use guide::*; diff --git a/src/calendar/mod.rs b/src/calendar/mod.rs index 9626f7c..7b2f8b0 100644 --- a/src/calendar/mod.rs +++ b/src/calendar/mod.rs @@ -208,21 +208,21 @@ fn CalendarItem( } #[derive(Clone, PartialEq)] -enum CalendarItemDate { +pub(crate) enum CalendarItemDate { Previous(NaiveDate), Current(NaiveDate), Next(NaiveDate), } impl CalendarItemDate { - fn is_other_month(&self) -> bool { + pub fn is_other_month(&self) -> bool { match self { CalendarItemDate::Previous(_) | CalendarItemDate::Next(_) => true, CalendarItemDate::Current(_) => false, } } - fn is_today(&self) -> bool { + pub fn is_today(&self) -> bool { let date = self.deref(); let now_date = now_date(); &now_date == date @@ -241,6 +241,6 @@ impl Deref for CalendarItemDate { } } -fn now_date() -> NaiveDate { +pub(crate) fn now_date() -> NaiveDate { Local::now().date_naive() } diff --git a/src/date_picker/date-picker.css b/src/date_picker/date-picker.css new file mode 100644 index 0000000..2a90402 --- /dev/null +++ b/src/date_picker/date-picker.css @@ -0,0 +1,174 @@ +.thaw-date-picker-panel { + width: 300px; + background-color: var(--thaw-background-color); + border-radius: 3px; + box-sizing: border-box; + box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); +} + +.thaw-date-picker-date-panel__calendar { + padding: 6px 12px 4px; +} + +.thaw-date-picker-date-panel__header { + display: grid; + grid-template-columns: 28px 28px 1fr 28px 28px; + align-items: center; + justify-content: space-between; +} + +.thaw-date-picker-date-panel__header > button { + color: var(--thaw-font-color-other-month); +} + +.thaw-date-picker-date-panel__header-month-year { + flex: 1; + display: flex; + align-items: center; + justify-content: center; +} + +.thaw-date-picker-date-panel__weekdays, +.thaw-date-picker-date-panel__dates { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + grid-auto-rows: 1fr; +} + +.thaw-date-picker-date-panel__weekdays { + border-bottom: 1px solid var(--thaw-item-border-color); + margin-bottom: 2px; + padding: 6px 4px; +} + +.thaw-date-picker-date-panel__weekdays span, +.thaw-date-picker-date-panel__item { + display: flex; + justify-content: center; + align-items: center; +} + +.thaw-date-picker-date-panel__item { + padding: 4px; + cursor: pointer; +} + +.thaw-date-picker-date-panel__item--other-month { + color: var(--thaw-font-color-other-month); +} + +.thaw-date-picker-date-panel__item-day { + position: relative; + display: flex; + justify-content: center; + align-items: center; + width: 24px; + height: 24px; + border-radius: 3px; +} + +.thaw-date-picker-date-panel__item-sup { + position: absolute; + top: 2px; + right: 0; + height: 4px; + width: 4px; + border-radius: 2px; + background-color: var(--thaw-background-color-today); +} + +.thaw-date-picker-date-panel__item:hover + .thaw-date-picker-date-panel__item-day { + background-color: var(--thaw-item-background-color-hover); +} + +.thaw-date-picker-date-panel__item--selected + .thaw-date-picker-date-panel__item-day { + background-color: var(--thaw-background-color-today) !important; + color: white; +} + +.thaw-date-picker-date-panel__footer { + padding: 8px 12px; + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + align-items: center; + border-top: 1px solid var(--thaw-item-border-color); +} + +.thaw-date-picker-date-panel__header-year { + flex: 1; + display: flex; + align-items: center; + justify-content: center; +} + +.thaw-date-picker-month-panel__header { + display: grid; + grid-template-columns: 28px 1fr 28px; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid var(--thaw-item-border-color); + padding: 2px 6px; +} + +.thaw-date-picker-year-panel__header { + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid var(--thaw-item-border-color); + padding: 4px 6px; +} + +.thaw-date-picker-year-panel__header > button, +.thaw-date-picker-month-panel__header > button { + color: var(--thaw-font-color-other-month); +} + +.thaw-date-picker-year-panel__years, +.thaw-date-picker-month-panel__months { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-auto-rows: 1fr; + padding: 4px 0 6px; +} + +.thaw-date-picker-year-panel__item:first-child, +.thaw-date-picker-year-panel__item:last-child { + color: var(--thaw-font-color-other-month); +} + +.thaw-date-picker-year-panel__item, +.thaw-date-picker-month-panel__item { + display: flex; + justify-content: center; + align-items: center; + padding: 4px; + cursor: pointer; +} + +.thaw-date-picker-year-panel__item--selected + .thaw-date-picker-year-panel__item-year, +.thaw-date-picker-month-panel__item--selected + .thaw-date-picker-month-panel__item-month { + background-color: var(--thaw-background-color-today) !important; + color: white; +} + +.thaw-date-picker-year-panel__item:hover + .thaw-date-picker-year-panel__item-year, +.thaw-date-picker-month-panel__item:hover + .thaw-date-picker-month-panel__item-month { + background-color: var(--thaw-item-background-color-hover); +} + +.thaw-date-picker-year-panel__item-year, +.thaw-date-picker-month-panel__item-month { + width: 52px; + line-height: 24px; + height: 24px; + text-align: center; + border-radius: 3px; +} diff --git a/src/date_picker/mod.rs b/src/date_picker/mod.rs new file mode 100644 index 0000000..e61fe90 --- /dev/null +++ b/src/date_picker/mod.rs @@ -0,0 +1,89 @@ +mod panel; +mod theme; + +use crate::{ + chrono::NaiveDate, + components::{Binder, Follower, FollowerPlacement}, + utils::{mount_style, now_date, ComponentRef}, + AiIcon, Icon, Input, InputSuffix, SignalWatch, +}; +use leptos::*; +use panel::{Panel, PanelRef}; +pub use theme::DatePickerTheme; + +#[component] +pub fn DatePicker(#[prop(optional, into)] value: RwSignal>) -> impl IntoView { + mount_style("date-picker", include_str!("./date-picker.css")); + let date_picker_ref = create_node_ref::(); + let is_show_panel = create_rw_signal(false); + let show_date_text = create_rw_signal(String::new()); + let show_date_format = "%Y-%m-%d"; + let update_show_date_text = move || { + value.with_untracked(move |date| { + let text = date.as_ref().map_or(String::new(), |date| { + date.format(show_date_format).to_string() + }); + show_date_text.set(text); + }); + }; + update_show_date_text(); + let panel_ref = ComponentRef::::default(); + let panel_selected_date = create_rw_signal(None::); + _ = panel_selected_date.watch(move |date| { + let text = date.as_ref().map_or(String::new(), |date| { + date.format(show_date_format).to_string() + }); + show_date_text.set(text); + }); + + let on_input_blur = Callback::new(move |_| { + if let Ok(date) = + NaiveDate::parse_from_str(&show_date_text.get_untracked(), show_date_format) + { + if value.get_untracked() != Some(date) { + value.set(Some(date)); + update_show_date_text(); + } + } else { + update_show_date_text(); + } + }); + + let close_panel = Callback::new(move |date: Option| { + if value.get_untracked() != date { + if date.is_some() { + value.set(date); + } + update_show_date_text(); + } + is_show_panel.set(false); + }); + + let open_panel = Callback::new(move |_| { + panel_selected_date.set(value.get_untracked()); + if let Some(panel_ref) = panel_ref.get_untracked() { + panel_ref.init_panel(value.get_untracked().unwrap_or(now_date())); + } + is_show_panel.set(true); + }); + + view! { + +
+ + + + + +
+ + + +
+ } +} diff --git a/src/date_picker/panel/date_panel.rs b/src/date_picker/panel/date_panel.rs new file mode 100644 index 0000000..624c1e6 --- /dev/null +++ b/src/date_picker/panel/date_panel.rs @@ -0,0 +1,194 @@ +use super::PanelVariant; +use crate::{ + chrono::{Datelike, Days, Month, Months, NaiveDate}, + utils::now_date, + AiIcon, Button, ButtonSize, ButtonVariant, CalendarItemDate, +}; +use leptos::*; +use std::ops::Deref; + +#[component] +pub fn DatePanel( + value: RwSignal>, + show_date: RwSignal, + close_panel: Callback>, + panel_variant: RwSignal, +) -> impl IntoView { + let dates = create_memo(move |_| { + let show_date = show_date.get(); + let show_date_month = show_date.month(); + let mut dates = vec![]; + + let mut current_date = show_date; + let mut current_weekday_number = None::; + loop { + let date = current_date - Days::new(1); + if date.month() != show_date_month { + if current_weekday_number.is_none() { + current_weekday_number = Some(current_date.weekday().num_days_from_sunday()); + } + let weekday_number = current_weekday_number.unwrap(); + if weekday_number == 0 { + break; + } + current_weekday_number = Some(weekday_number - 1); + + dates.push(CalendarItemDate::Previous(date)); + } else { + dates.push(CalendarItemDate::Current(date)); + } + current_date = date; + } + dates.reverse(); + dates.push(CalendarItemDate::Current(show_date)); + current_date = show_date; + current_weekday_number = None; + loop { + let date = current_date + Days::new(1); + if date.month() != show_date_month { + if current_weekday_number.is_none() { + current_weekday_number = Some(current_date.weekday().num_days_from_sunday()); + } + let weekday_number = current_weekday_number.unwrap(); + if weekday_number == 6 { + break; + } + current_weekday_number = Some(weekday_number + 1); + dates.push(CalendarItemDate::Next(date)); + } else { + dates.push(CalendarItemDate::Current(date)); + } + current_date = date; + } + dates + }); + let previous_year = move |_| { + show_date.update(|date| { + *date = *date - Months::new(12); + }); + }; + let next_year = move |_| { + show_date.update(|date| { + *date = *date + Months::new(12); + }); + }; + let previous_month = move |_| { + show_date.update(|date| { + *date = *date - Months::new(1); + }); + }; + let next_month = move |_| { + show_date.update(|date| { + *date = *date + Months::new(1); + }); + }; + let now = Callback::new(move |_| { + close_panel.call(Some(now_date())); + }); + view! { +
+
+
+ + +
+
+
+ "Su" + "Mo" + "Tu" + "We" + "Th" + "Fr" + "Sa" +
+
+ {move || { + dates + .get() + .into_iter() + .map(|date| { + let on_click = { + let date = date.clone(); + move |_| { + close_panel.call(Some(*date.deref())); + } + }; + view! { } + }) + .collect_view() + }} + +
+
+ + + } +} + +#[component] +fn DatePanelItem(value: RwSignal>, date: CalendarItemDate) -> impl IntoView { + let is_selected = create_memo({ + let date = date.clone(); + move |_| value.with(|value_date| value_date.as_ref() == Some(date.deref())) + }); + + view! { +
+
+ {date.day()} + {if date.is_today() { + view! {
}.into() + } else { + None + }} + +
+
+ } +} diff --git a/src/date_picker/panel/mod.rs b/src/date_picker/panel/mod.rs new file mode 100644 index 0000000..46f62f6 --- /dev/null +++ b/src/date_picker/panel/mod.rs @@ -0,0 +1,135 @@ +mod date_panel; +mod month_panel; +mod year_panel; + +use crate::{ + chrono::NaiveDate, + use_theme, + utils::{now_date, ComponentRef}, + Theme, +}; +use date_panel::DatePanel; +use leptos::*; +use month_panel::MonthPanel; +use year_panel::YearPanel; + +#[component] +pub fn Panel( + selected_date: RwSignal>, + date_picker_ref: NodeRef, + close_panel: Callback>, + #[prop(optional)] comp_ref: ComponentRef, +) -> impl IntoView { + let theme = use_theme(Theme::light); + let css_vars = create_memo(move |_| { + let mut css_vars = String::new(); + theme.with(|theme| { + css_vars.push_str(&format!( + "--thaw-background-color-today: {};", + theme.common.color_primary + )); + css_vars.push_str(&format!( + "--thaw-font-color-other-month: {};", + theme.date_picker.panel_other_month_font_color, + )); + css_vars.push_str(&format!( + "--thaw-background-color: {};", + theme.date_picker.panel_background_color + )); + css_vars.push_str(&format!( + "--thaw-item-background-color-hover: {};", + theme.date_picker.panel_date_item_background_color_hover + )); + css_vars.push_str(&format!( + "--thaw-item-border-color: {};", + theme.date_picker.panel_border_color + )); + }); + css_vars + }); + + let panel_ref = create_node_ref::(); + #[cfg(any(feature = "csr", feature = "hydrate"))] + { + use leptos::wasm_bindgen::__rt::IntoJsResult; + let handle = window_event_listener(ev::click, move |ev| { + let el = ev.target(); + let mut el: Option = + el.into_js_result().map_or(None, |el| Some(el.into())); + let body = document().body().unwrap(); + loop { + let Some(current_el) = el else { + return; + }; + if current_el == *body { + break; + }; + if panel_ref.get().is_none() { + return; + } + if current_el == ***panel_ref.get_untracked().unwrap() + || current_el == ***date_picker_ref.get_untracked().unwrap() + { + return; + } + el = current_el.parent_element(); + } + close_panel.call(None); + }); + on_cleanup(move || handle.remove()); + } + #[cfg(not(any(feature = "csr", feature = "hydrate")))] + { + _ = date_picker_ref; + _ = panel_ref; + } + let panel_variant = create_rw_signal(PanelVariant::Date); + let show_date = create_rw_signal(selected_date.get_untracked().unwrap_or(now_date())); + comp_ref.load(PanelRef { + show_date, + variant: panel_variant, + }); + + view! { +
+ + {move || { + match panel_variant.get() { + PanelVariant::Date => { + view! { + + } + } + PanelVariant::Month => { + view! { } + } + PanelVariant::Year => { + view! { } + } + } + }} + +
+ } +} + +#[derive(Clone)] +pub struct PanelRef { + show_date: RwSignal, + variant: RwSignal, +} + +impl PanelRef { + pub fn init_panel(&self, show_date: NaiveDate) { + self.show_date.set(show_date); + self.variant.set(PanelVariant::Date); + } +} + +#[derive(Default, Clone)] +pub enum PanelVariant { + #[default] + Date, + Month, + Year, +} diff --git a/src/date_picker/panel/month_panel.rs b/src/date_picker/panel/month_panel.rs new file mode 100644 index 0000000..d139291 --- /dev/null +++ b/src/date_picker/panel/month_panel.rs @@ -0,0 +1,89 @@ +use super::PanelVariant; +use crate::{ + chrono::{Datelike, Month, Months, NaiveDate}, + AiIcon, Button, ButtonSize, ButtonVariant, +}; +use leptos::*; + +#[component] +pub fn MonthPanel( + date_panel_show_date: RwSignal, + panel_variant: RwSignal, +) -> impl IntoView { + let show_date = create_rw_signal(date_panel_show_date.get_untracked()); + let previous_year = move |_| { + show_date.update(|date| { + *date = *date - Months::new(12); + }); + }; + let next_year = move |_| { + show_date.update(|date| { + *date = *date + Months::new(12); + }); + }; + view! { +
+
+ +
+
+
+ + {(1..=12) + .map(|index| { + let month = Month::try_from(index).unwrap(); + let on_click = move |_| { + date_panel_show_date + .update(|date| { + let show_date = show_date.get_untracked(); + *date = date + .with_month(index.into()) + .unwrap() + .with_year(show_date.year()) + .unwrap(); + }); + panel_variant.set(PanelVariant::Date); + }; + view! { } + }) + .collect_view()} + +
+ + } +} + +#[component] +fn MonthPanelItem(date_panel_show_date: RwSignal, month: Month) -> impl IntoView { + let is_selected = create_memo(move |_| { + date_panel_show_date.with(|date| date.month() == month.number_from_month()) + }); + + view! { +
+
{month.name().split_at(3).0}
+
+ } +} diff --git a/src/date_picker/panel/year_panel.rs b/src/date_picker/panel/year_panel.rs new file mode 100644 index 0000000..dae8eb2 --- /dev/null +++ b/src/date_picker/panel/year_panel.rs @@ -0,0 +1,89 @@ +use super::PanelVariant; +use crate::{ + chrono::{Datelike, NaiveDate}, + AiIcon, Button, ButtonSize, ButtonVariant, +}; +use leptos::*; + +const MAX_YEAR: i32 = (i32::MAX >> 13) / 10 - 1; +const MIN_YEAR: i32 = (i32::MIN >> 13) / 10 + 1; + +#[component] +pub fn YearPanel( + date_panel_show_date: RwSignal, + panel_variant: RwSignal, +) -> impl IntoView { + let show_min_year = create_rw_signal(date_panel_show_date.get_untracked().year() / 10); + let previous_year_range = move |_| { + show_min_year.update(|year| { + if *year > MIN_YEAR { + *year -= 1; + } + }); + }; + let next_year_range = move |_| { + show_min_year.update(|year| { + if *year < MAX_YEAR { + *year += 1; + } + }); + }; + view! { +
+
+
+
+ + {move || { + (-1..=10) + .map(|index| { + let year = show_min_year.get() * 10 + index; + let on_click = move |_| { + date_panel_show_date + .update(|date| { + *date = date.with_year(year).unwrap(); + }); + panel_variant.set(PanelVariant::Month); + }; + view! { } + }) + .collect_view() + }} + +
+
+ } +} + +#[component] +fn YearPanelItem(date_panel_show_date: RwSignal, year: i32) -> impl IntoView { + let is_selected = create_memo(move |_| date_panel_show_date.with(|date| date.year() == year)); + + view! { +
+
{year}
+
+ } +} diff --git a/src/date_picker/theme.rs b/src/date_picker/theme.rs new file mode 100644 index 0000000..c7597ca --- /dev/null +++ b/src/date_picker/theme.rs @@ -0,0 +1,29 @@ +use crate::theme::ThemeMethod; + +#[derive(Clone)] +pub struct DatePickerTheme { + pub panel_background_color: String, + pub panel_date_item_background_color_hover: String, + pub panel_border_color: String, + pub panel_other_month_font_color: String, +} + +impl ThemeMethod for DatePickerTheme { + fn light() -> Self { + Self { + panel_background_color: "#fff".into(), + panel_date_item_background_color_hover: "#f1f3f5".into(), + panel_border_color: "#e0e0e6".into(), + panel_other_month_font_color: "#c2c2c2".into(), + } + } + + fn dark() -> Self { + Self { + panel_background_color: "#48484e".into(), + panel_date_item_background_color_hover: "#ffffff1a".into(), + panel_border_color: "#ffffff3d".into(), + panel_other_month_font_color: "#ffffff61".into(), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index b8baca3..6934546 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ mod checkbox; mod code; mod color_picker; mod components; +mod date_picker; mod divider; mod global_style; mod grid; @@ -52,6 +53,7 @@ pub use checkbox::*; pub use chrono; pub use code::*; pub use color_picker::*; +pub use date_picker::*; pub use divider::*; pub use global_style::*; pub use grid::*; diff --git a/src/theme/mod.rs b/src/theme/mod.rs index df40770..4e435c3 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -4,9 +4,9 @@ use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AutoCompleteTheme, AvatarTheme, BreadcrumbTheme, ButtonTheme, CalendarTheme, - ColorPickerTheme, InputTheme, MenuTheme, MessageTheme, ProgressTheme, SelectTheme, - SkeletionTheme, SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, - TypographyTheme, UploadTheme, + ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, ProgressTheme, + SelectTheme, SkeletionTheme, SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, + TimePickerTheme, TypographyTheme, UploadTheme, }; use leptos::*; @@ -42,6 +42,7 @@ pub struct Theme { pub typograph: TypographyTheme, pub calendar: CalendarTheme, pub time_picker: TimePickerTheme, + pub date_picker: DatePickerTheme, } impl Theme { @@ -72,6 +73,7 @@ impl Theme { typograph: TypographyTheme::light(), calendar: CalendarTheme::light(), time_picker: TimePickerTheme::light(), + date_picker: DatePickerTheme::light(), } } pub fn dark() -> Self { @@ -101,6 +103,7 @@ impl Theme { typograph: TypographyTheme::dark(), calendar: CalendarTheme::dark(), time_picker: TimePickerTheme::dark(), + date_picker: DatePickerTheme::dark(), } } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 19e0ac9..08c431d 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,6 +5,7 @@ mod event_listener; mod mount_style; mod signal; mod stored_maybe_signal; +mod time; // pub use callback::AsyncCallback; pub use component_ref::{create_component_ref, ComponentRef}; @@ -13,6 +14,7 @@ pub(crate) use event_listener::*; pub(crate) use mount_style::mount_style; pub use signal::SignalWatch; pub(crate) use stored_maybe_signal::*; +pub(crate) use time::*; pub(crate) fn with_hydration_off(f: impl FnOnce() -> T) -> T { #[cfg(feature = "hydrate")] diff --git a/src/utils/time.rs b/src/utils/time.rs new file mode 100644 index 0000000..ec718c5 --- /dev/null +++ b/src/utils/time.rs @@ -0,0 +1,5 @@ +use crate::chrono::{Local, NaiveDate}; + +pub fn now_date() -> NaiveDate { + Local::now().date_naive() +}