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
This commit is contained in:
luoxiaozero 2023-12-18 22:05:11 +08:00 committed by GitHub
parent 89ee294040
commit 6c9e0c397f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 887 additions and 8 deletions

View file

@ -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"] }

View file

@ -80,6 +80,7 @@ fn TheRouter(is_routing: RwSignal<bool>) -> impl IntoView {
<Route path="/typography" view=TypographyPage/>
<Route path="/calendar" view=CalendarPage/>
<Route path="/time-picker" view=TimePickerPage/>
<Route path="/date-picker" view=DatePickerPage/>
</Route>
<Route path="/mobile/tabbar" view=TabbarDemoPage/>
<Route path="/mobile/nav-bar" view=NavBarDemoPage/>

View file

@ -126,13 +126,17 @@ pub(crate) fn gen_menu_data() -> Vec<MenuGroupOption> {
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(),

View file

@ -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! {
<div style="width: 896px; margin: 0 auto;">
<h1>"Date Picker"</h1>
<Demo>
<DatePicker value/>
<DemoCode slot>
{highlight_str!(
r#"
use thaw::chrono::prelude::*;
let value = create_rw_signal(Some(Local::now().date_naive()));
view! {
<DatePicker value/>
}
"#,
"rust"
)}
</DemoCode>
</Demo>
<h3>"DatePicker Props"</h3>
<Table single_column=true>
<thead>
<tr>
<th>"Name"</th>
<th>"Type"</th>
<th>"Default"</th>
<th>"Description"</th>
</tr>
</thead>
<tbody>
<tr>
<td>"value"</td>
<td>
<Text code=true>"RwSignal<Option<NaiveDate>>"</Text>
</td>
<td>
<Text code=true>"Default::default()"</Text>
</td>
<td>
"Set the date picker value"
</td>
</tr>
</tbody>
</Table>
</div>
}
}

View file

@ -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::*;

View file

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

View file

@ -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;
}

89
src/date_picker/mod.rs Normal file
View file

@ -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<Option<NaiveDate>>) -> impl IntoView {
mount_style("date-picker", include_str!("./date-picker.css"));
let date_picker_ref = create_node_ref::<html::Div>();
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::<PanelRef>::default();
let panel_selected_date = create_rw_signal(None::<NaiveDate>);
_ = 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<NaiveDate>| {
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! {
<Binder target_ref=date_picker_ref>
<div ref=date_picker_ref>
<Input value=show_date_text on_focus=open_panel on_blur=on_input_blur>
<InputSuffix slot>
<Icon icon=Icon::from(AiIcon::AiCalendarOutlined) style="font-size: 18px"/>
</InputSuffix>
</Input>
</div>
<Follower slot show=is_show_panel placement=FollowerPlacement::BottomStart>
<Panel
date_picker_ref
close_panel
selected_date=panel_selected_date
comp_ref=panel_ref
/>
</Follower>
</Binder>
}
}

View file

@ -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<Option<NaiveDate>>,
show_date: RwSignal<NaiveDate>,
close_panel: Callback<Option<NaiveDate>>,
panel_variant: RwSignal<PanelVariant>,
) -> 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::<u32>;
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! {
<div>
<div class="thaw-date-picker-date-panel__calendar">
<div class="thaw-date-picker-date-panel__header">
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiArrowLeftOutlined
on_click=previous_year
/>
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiLeftOutlined
on_click=previous_month
/>
<div class="thaw-date-picker-date-panel__header-month-year">
<Button
variant=ButtonVariant::Text
size=ButtonSize::Small
on_click=move |_| panel_variant.set(PanelVariant::Month)
>
{move || Month::try_from(show_date.get().month() as u8).unwrap().name()}
</Button>
<Button
variant=ButtonVariant::Text
size=ButtonSize::Small
on_click=move |_| panel_variant.set(PanelVariant::Year)
>
{move || show_date.get().year()}
</Button>
</div>
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiRightOutlined
on_click=next_month
/>
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiArrowRightOutlined
on_click=next_year
/>
</div>
<div class="thaw-date-picker-date-panel__weekdays">
<span>"Su"</span>
<span>"Mo"</span>
<span>"Tu"</span>
<span>"We"</span>
<span>"Th"</span>
<span>"Fr"</span>
<span>"Sa"</span>
</div>
<div class="thaw-date-picker-date-panel__dates">
{move || {
dates
.get()
.into_iter()
.map(|date| {
let on_click = {
let date = date.clone();
move |_| {
close_panel.call(Some(*date.deref()));
}
};
view! { <DatePanelItem value date=date on:click=on_click/> }
})
.collect_view()
}}
</div>
</div>
<div class="thaw-date-picker-date-panel__footer">
<Button variant=ButtonVariant::Solid size=ButtonSize::Tiny on_click=now>
"Now"
</Button>
</div>
</div>
}
}
#[component]
fn DatePanelItem(value: RwSignal<Option<NaiveDate>>, 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! {
<div
class="thaw-date-picker-date-panel__item"
class=("thaw-date-picker-date-panel__item--other-month", date.is_other_month())
class=("thaw-date-picker-date-panel__item--selected", move || is_selected.get())
>
<div class="thaw-date-picker-date-panel__item-day">
{date.day()}
{if date.is_today() {
view! { <div class="thaw-date-picker-date-panel__item-sup"></div> }.into()
} else {
None
}}
</div>
</div>
}
}

View file

@ -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<Option<NaiveDate>>,
date_picker_ref: NodeRef<html::Div>,
close_panel: Callback<Option<NaiveDate>>,
#[prop(optional)] comp_ref: ComponentRef<PanelRef>,
) -> 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::<html::Div>();
#[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<web_sys::Element> =
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! {
<div class="thaw-date-picker-panel" style=move || css_vars.get() ref=panel_ref>
{move || {
match panel_variant.get() {
PanelVariant::Date => {
view! {
<DatePanel value=selected_date show_date close_panel panel_variant/>
}
}
PanelVariant::Month => {
view! { <MonthPanel date_panel_show_date=show_date panel_variant/> }
}
PanelVariant::Year => {
view! { <YearPanel date_panel_show_date=show_date panel_variant/> }
}
}
}}
</div>
}
}
#[derive(Clone)]
pub struct PanelRef {
show_date: RwSignal<NaiveDate>,
variant: RwSignal<PanelVariant>,
}
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,
}

View file

@ -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<NaiveDate>,
panel_variant: RwSignal<PanelVariant>,
) -> 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! {
<div class="thaw-date-picker-month-panel">
<div class="thaw-date-picker-month-panel__header">
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiArrowLeftOutlined
on_click=previous_year
/>
<div class="thaw-date-picker-date-panel__header-year">
<Button
variant=ButtonVariant::Text
size=ButtonSize::Small
on_click=move |_| panel_variant.set(PanelVariant::Year)
>
{move || show_date.get().year()}
</Button>
</div>
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiArrowRightOutlined
on_click=next_year
/>
</div>
<div class="thaw-date-picker-month-panel__months">
{(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! { <MonthPanelItem date_panel_show_date month on:click=on_click/> }
})
.collect_view()}
</div>
</div>
}
}
#[component]
fn MonthPanelItem(date_panel_show_date: RwSignal<NaiveDate>, month: Month) -> impl IntoView {
let is_selected = create_memo(move |_| {
date_panel_show_date.with(|date| date.month() == month.number_from_month())
});
view! {
<div
class="thaw-date-picker-month-panel__item"
class=("thaw-date-picker-month-panel__item--selected", move || is_selected.get())
>
<div class="thaw-date-picker-month-panel__item-month">{month.name().split_at(3).0}</div>
</div>
}
}

View file

@ -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<NaiveDate>,
panel_variant: RwSignal<PanelVariant>,
) -> 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! {
<div>
<div class="thaw-date-picker-year-panel__header">
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiArrowLeftOutlined
on_click=previous_year_range
/>
<div>
{move || {
let year = show_min_year.get();
format!("{}0 - {}9", year, year)
}}
</div>
<Button
variant=ButtonVariant::Link
size=ButtonSize::Small
icon=AiIcon::AiArrowRightOutlined
on_click=next_year_range
/>
</div>
<div class="thaw-date-picker-year-panel__years">
{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! { <YearPanelItem date_panel_show_date year on:click=on_click/> }
})
.collect_view()
}}
</div>
</div>
}
}
#[component]
fn YearPanelItem(date_panel_show_date: RwSignal<NaiveDate>, year: i32) -> impl IntoView {
let is_selected = create_memo(move |_| date_panel_show_date.with(|date| date.year() == year));
view! {
<div
class="thaw-date-picker-year-panel__item"
class=("thaw-date-picker-year-panel__item--selected", move || is_selected.get())
>
<div class="thaw-date-picker-year-panel__item-year">{year}</div>
</div>
}
}

29
src/date_picker/theme.rs Normal file
View file

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

View file

@ -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::*;

View file

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

View file

@ -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<T>(f: impl FnOnce() -> T) -> T {
#[cfg(feature = "hydrate")]

5
src/utils/time.rs Normal file
View file

@ -0,0 +1,5 @@
use crate::chrono::{Local, NaiveDate};
pub fn now_date() -> NaiveDate {
Local::now().date_naive()
}