Implement comprehensive calendar UX improvements

- Add time range display to week view events showing "start - end" format
- Optimize time display with smart AM/PM formatting to reduce redundancy
- Fix context menu overlap by adding stop_propagation to event handlers
- Implement persistent view mode (Month/Week) across page refreshes using localStorage
- Replace month-based tracking with intelligent selected date tracking
- Add day selection in month view with visual feedback and click handlers
- Fix view switching to navigate to week containing selected day, not first week of month
- Separate selected_date from display_date for proper context switching
- Simplify week view header to show "Month Year" instead of "Week of Month Day"
- Add backward compatibility for existing localStorage keys

Greatly improves calendar navigation and user experience with persistent state

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-08-29 10:44:44 -04:00
parent 5d0628878b
commit a8bb2c8164
5 changed files with 169 additions and 46 deletions

View File

@@ -147,7 +147,8 @@ pub fn week_view(props: &WeekViewProps) -> Html {
let onclick = {
let on_event_click = props.on_event_click.clone();
let event = event.clone();
Callback::from(move |_: MouseEvent| {
Callback::from(move |e: MouseEvent| {
e.stop_propagation(); // Prevent calendar click events from also triggering
on_event_click.emit(event.clone());
})
};
@@ -158,6 +159,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
let event = event.clone();
Some(Callback::from(move |e: web_sys::MouseEvent| {
e.prevent_default();
e.stop_propagation(); // Prevent calendar context menu from also triggering
callback.emit((e, event.clone()));
}))
} else {
@@ -170,7 +172,30 @@ pub fn week_view(props: &WeekViewProps) -> Html {
"All Day".to_string()
} else {
let local_start = event.start.with_timezone(&Local);
format!("{}", local_start.format("%I:%M %p"))
if let Some(end) = event.end {
let local_end = end.with_timezone(&Local);
// Check if both times are in same AM/PM period to avoid redundancy
let start_is_am = local_start.hour() < 12;
let end_is_am = local_end.hour() < 12;
if start_is_am == end_is_am {
// Same AM/PM period - show "9:00 - 10:30 AM"
format!("{} - {}",
local_start.format("%I:%M").to_string().trim_start_matches('0'),
local_end.format("%I:%M %p")
)
} else {
// Different AM/PM periods - show "9:00 AM - 2:30 PM"
format!("{} - {}",
local_start.format("%I:%M %p"),
local_end.format("%I:%M %p")
)
}
} else {
// No end time, just show start time
format!("{}", local_start.format("%I:%M %p"))
}
};
Some(html! {