Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/leptos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tailwind_fuse = { version = "0.3.2", features = [
"variant",
"tailwind_fuse_macro",
] }
chrono = { version = "0.4", default-features = false, features = ["clock", "wasmbind"] }
80 changes: 80 additions & 0 deletions crates/leptos/src/calendar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::{
button::{Button, Variant as ButtonVariant},
icons::{ArrowLeft, ArrowRight},
};
pub use chrono::NaiveDate;
use chrono::{Local, Months};
pub use date::{CalendarDay, MONTH_NAMES, calendar_days, month_label};
use leptos::prelude::*;
pub use selection::{CalendarRange, Selection};

mod date;
mod day_button;
mod selection;

use day_button::CalendarDayButton;

pub const WEEK_DAYS: [&str; 7] = [
"Lunes",
"Martes",
"Miercoles",
"Jueves",
"Viernes",
"Sabado",
"Domingo",
];

#[component]
pub fn Calendar(
selection: Selection,
#[prop(optional)] default_month: Option<NaiveDate>,
#[prop(into, optional)] class: String,
) -> impl IntoView {
let month = RwSignal::new(default_month.unwrap_or_else(|| Local::now().date_naive()));

let class = crate::tw!(
"shadow-rb-black grid gap-4 rounded-[20px] px-3 pt-4 pb-10",
"bg-light border-2 border-black text-black",
"dark:bg-neutral-900 dark:border-neutral-950 dark:text-neutral-50",
class
);

view! {
<div class=class>
<div class="flex items-center justify-between">
<Button
class="size-7 border-2"
variant=ButtonVariant::Icon
icon=view! { <ArrowLeft size=20 /> }.into_any()
on_click=move |_| month.update(|m| *m = *m - Months::new(1))
/>
<p class="flex-1 text-center text-sm font-medium">
{move || month_label(month.get())}
</p>
<Button
class="size-7 border-2"
variant=ButtonVariant::Icon
icon=view! { <ArrowRight size=20 /> }.into_any()
on_click=move |_| month.update(|m| *m = *m + Months::new(1))
/>
</div>
<ul class="grid grid-cols-7 gap-x-1 text-center" role="grid">
{WEEK_DAYS
.iter()
.map(|day| view! { <li class="mb-1.5 min-w-9 text-xs">{&day[..2]}</li> })
.collect_view()}
<For
each=move || calendar_days(month.get())
key=|day| day.date.to_string()
children=move |day| {
view! {
<li>
<CalendarDayButton day selection=selection />
</li>
}
}
/>
</ul>
</div>
}
}
45 changes: 45 additions & 0 deletions crates/leptos/src/calendar/date.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use chrono::{Datelike, Days, Months, NaiveDate, Weekday};

#[derive(Clone)]
pub struct CalendarDay {
pub date: NaiveDate,
pub current_month: bool,
}

pub const MONTH_NAMES: [&str; 12] = [
"Enero",
"Febrero",
"Marzo",
"Abril",
"Mayo",
"Junio",
"Julio",
"Agosto",
"Septiembre",
"Octubre",
"Noviembre",
"Diciembre",
];

pub fn month_label(date: NaiveDate) -> String {
let month = MONTH_NAMES[date.month0() as usize];
let year = date.year();
format!("{month} {year}")
}

pub fn calendar_days(date: NaiveDate) -> Vec<CalendarDay> {
let first = date.with_day(1).expect("every month has a day 1");
let last = first + Months::new(1) - Days::new(1);
let end = last.week(Weekday::Mon).last_day();

first
.week(Weekday::Mon)
.first_day()
.iter_days()
.take_while(|day| *day <= end)
.map(|day| CalendarDay {
date: day,
current_month: day.month() == date.month(),
})
.collect()
}
Loading
Loading