thaw 0.4.8

An easy to use leptos component library
Documentation
use super::PanelVariant;
use crate::{Button, ButtonAppearance, ButtonSize, CalendarItemDate};
use chrono::{Datelike, Days, Month, Months, NaiveDate};
use leptos::{html, prelude::*};
use std::ops::Deref;
use thaw_components::FollowerInjection;
use thaw_utils::{now_date, ArcOneCallback};

#[component]
pub fn DatePanel(
    value: RwSignal<Option<NaiveDate>>,
    show_date: RwSignal<NaiveDate>,
    close_panel: ArcOneCallback<Option<NaiveDate>>,
    panel_variant: RwSignal<PanelVariant>,
) -> impl IntoView {
    let follower = FollowerInjection::expect_context();
    let panel_ref = NodeRef::<html::Div>::new();
    Effect::new(move || {
        let Some(_) = panel_ref.get() else {
            return;
        };
        follower.refresh_position();
    });
    let dates = Memo::new(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 = {
        let close_panel = close_panel.clone();
        move |_| {
            close_panel(Some(now_date()));
        }
    };
    view! {
        <div class="thaw-date-picker-date-panel" node_ref=panel_ref>
            <div class="thaw-date-picker-date-panel__calendar">
                <div class="thaw-date-picker-date-panel__header">
                    <Button
                        appearance=ButtonAppearance::Transparent
                        size=ButtonSize::Small
                        icon=icondata_ai::AiArrowLeftOutlined
                        on_click=previous_year
                    />
                    <Button
                        appearance=ButtonAppearance::Transparent
                        size=ButtonSize::Small
                        icon=icondata_ai::AiLeftOutlined
                        on_click=previous_month
                    />
                    <div class="thaw-date-picker-date-panel__header-month-year">
                        <Button
                            appearance=ButtonAppearance::Subtle
                            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
                            appearance=ButtonAppearance::Subtle
                            size=ButtonSize::Small
                            on_click=move |_| panel_variant.set(PanelVariant::Year)
                        >
                            {move || show_date.get().year()}
                        </Button>
                    </div>
                    <Button
                        appearance=ButtonAppearance::Transparent
                        size=ButtonSize::Small
                        icon=icondata_ai::AiRightOutlined
                        on_click=next_month
                    />
                    <Button
                        appearance=ButtonAppearance::Transparent
                        size=ButtonSize::Small
                        icon=icondata_ai::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();
                                    let close_panel = close_panel.clone();
                                    move |_| {
                                        close_panel(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 size=ButtonSize::Small on_click=now>
                    "Now"
                </Button>
            </div>
        </div>
    }
}

#[component]
fn DatePanelItem(value: RwSignal<Option<NaiveDate>>, date: CalendarItemDate) -> impl IntoView {
    let is_selected = Memo::new({
        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>
    }
}