From b2198c754894deeef94edf2c66022e7f32f270d5 Mon Sep 17 00:00:00 2001 From: xrtxn Date: Mon, 13 Jul 2026 13:44:58 +0200 Subject: [PATCH] calendar: added custom starting day --- crates/ui/src/time/calendar.rs | 21 +++++++++++++++++---- crates/ui/src/time/date_picker.rs | 12 +++++++++++- crates/ui/src/time/utils.rs | 11 ++++++----- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/crates/ui/src/time/calendar.rs b/crates/ui/src/time/calendar.rs index d25d90230d..329fbff293 100644 --- a/crates/ui/src/time/calendar.rs +++ b/crates/ui/src/time/calendar.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, rc::Rc}; -use chrono::{Datelike, Local, NaiveDate}; +use chrono::{Datelike, Local, NaiveDate, Weekday}; use gpui::{ App, ClickEvent, Context, Div, ElementId, Empty, Entity, EventEmitter, FocusHandle, InteractiveElement, IntoElement, ParentElement, Render, RenderOnce, SharedString, Stateful, @@ -266,6 +266,8 @@ pub struct Calendar { style: StyleRefinement, /// Number of the months view to show. number_of_months: usize, + /// The first day of the week. Defaults to Sunday. + first_day_of_week: Weekday, } /// Use to store the state of the calendar. @@ -411,10 +413,14 @@ impl CalendarState { } /// Returns the days of the month in a 2D vector to render on calendar. - fn days(&self) -> Vec> { + fn days(&self, first_day: Weekday) -> Vec> { (0..self.number_of_months) .flat_map(|offset| { - days_in_month(self.current_year, self.current_month as u32 + offset as u32) + days_in_month( + self.current_year, + self.current_month as u32 + offset as u32, + first_day, + ) }) .collect() } @@ -539,6 +545,7 @@ impl Calendar { state: state.clone(), style: StyleRefinement::default(), number_of_months: 1, + first_day_of_week: Weekday::Sun, } } @@ -548,6 +555,12 @@ impl Calendar { self } + /// Set the first day of the week for the calendar. + pub fn first_day_of_week(mut self, day: Weekday) -> Self { + self.first_day_of_week = day; + self + } + fn render_day( &self, d: &NaiveDate, @@ -803,7 +816,7 @@ impl Calendar { .justify_between() .children( state - .days() + .days(self.first_day_of_week) .chunks(5) .enumerate() .map(|(offset_month, days)| { diff --git a/crates/ui/src/time/date_picker.rs b/crates/ui/src/time/date_picker.rs index b60cab28c6..a714a6ee19 100644 --- a/crates/ui/src/time/date_picker.rs +++ b/crates/ui/src/time/date_picker.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use chrono::NaiveDate; +use chrono::{NaiveDate, Weekday}; use gpui::{ App, AppContext, ClickEvent, Context, ElementId, Empty, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement as _, @@ -77,6 +77,8 @@ pub struct DatePickerState { number_of_months: usize, disabled_matcher: Option>, _subscriptions: Vec, + /// The first day of the week. Defaults to Sunday. + first_day_of_week: Weekday, } impl Focusable for DatePickerState { @@ -130,6 +132,7 @@ impl DatePickerState { number_of_months: 1, disabled_matcher: None, _subscriptions, + first_day_of_week: Weekday::Sun, } } @@ -145,6 +148,12 @@ impl DatePickerState { self } + /// Set the first day of the week. + pub fn first_day_of_week(mut self, day: Weekday) -> Self { + self.first_day_of_week = day; + self + } + /// Get the date of the date picker. pub fn date(&self) -> Date { self.date @@ -501,6 +510,7 @@ impl RenderOnce for DatePicker { .child( Calendar::new(&state.calendar) .number_of_months(self.number_of_months) + .first_day_of_week(state.first_day_of_week) .border_0() .rounded_none() .p_0() diff --git a/crates/ui/src/time/utils.rs b/crates/ui/src/time/utils.rs index 0c88ebb1d5..88ab0bbf12 100644 --- a/crates/ui/src/time/utils.rs +++ b/crates/ui/src/time/utils.rs @@ -1,4 +1,4 @@ -use chrono::{Datelike, Duration, NaiveDate}; +use chrono::{Datelike, Duration, NaiveDate, Weekday}; trait NaiveDateExt { fn days_in_month(&self) -> i32; @@ -28,7 +28,7 @@ impl NaiveDateExt for chrono::NaiveDate { } } -pub(crate) fn days_in_month(year: i32, month: u32) -> Vec> { +pub(crate) fn days_in_month(year: i32, month: u32, first_day: Weekday) -> Vec> { let mut year = year; let mut month = month; if month > 12 { @@ -42,7 +42,8 @@ pub(crate) fn days_in_month(year: i32, month: u32) -> Vec> { let date = NaiveDate::from_ymd_opt(year, month, 1).unwrap(); let num_days = date.days_in_month(); - let start_weekday = date.weekday().num_days_from_sunday(); + let start_weekday = + (date.weekday().num_days_from_sunday() + 7 - first_day.num_days_from_sunday()) % 7; // Get the days in the month, 2023-02 will returns // "29|30|31| 1| 2| 3| 4", @@ -87,7 +88,7 @@ pub(crate) fn days_in_month(year: i32, month: u32) -> Vec> { #[cfg(test)] mod tests { - use chrono::{Datelike, NaiveDate}; + use chrono::{Datelike, NaiveDate, Weekday}; use super::{days_in_month, NaiveDateExt}; @@ -115,7 +116,7 @@ mod tests { fn test_days() { #[track_caller] fn assert_case(date: NaiveDate, expected: Vec<&str>) { - let out = days_in_month(date.year(), date.month()) + let out = days_in_month(date.year(), date.month(), Weekday::Sun) .iter() .map(|week| { week.iter()