diff --git a/src/components/week_view.rs b/src/components/week_view.rs index 1e2bf3e..0f72ac0 100644 --- a/src/components/week_view.rs +++ b/src/components/week_view.rs @@ -1,5 +1,5 @@ use yew::prelude::*; -use chrono::{Datelike, NaiveDate, Duration, Weekday}; +use chrono::{Datelike, NaiveDate, Duration, Weekday, Local, Timelike}; use std::collections::HashMap; use web_sys::MouseEvent; use crate::services::calendar_service::{CalendarEvent, UserInfo}; @@ -130,10 +130,17 @@ pub fn week_view(props: &WeekViewProps) -> Html { // Final boundary slot to match the final time label
- // Events positioned absolutely + // Events positioned absolutely based on their actual times
{ - day_events.iter().map(|event| { + day_events.iter().filter_map(|event| { + let (start_pixels, duration_pixels, is_all_day) = calculate_event_position(event, *date); + + // Skip events that don't belong on this date or have invalid positioning + if start_pixels == 0.0 && duration_pixels == 0.0 && !is_all_day { + return None; + } + let event_color = get_event_color(event); let is_refreshing = props.refreshing_event_uid.as_ref() == Some(&event.uid); @@ -158,17 +165,38 @@ pub fn week_view(props: &WeekViewProps) -> Html { } }; - // For now, position events at top of day (we'll improve this later with actual time positioning) - html! { + // Format time display for the event + let time_display = if event.all_day { + "All Day".to_string() + } else { + let local_start = event.start.with_timezone(&Local); + format!("{}", local_start.format("%I:%M %p")) + }; + + Some(html! {
- {event.summary.as_ref().unwrap_or(&"Untitled".to_string())} +
{event.summary.as_ref().unwrap_or(&"Untitled".to_string())}
+ {if !is_all_day { + html! {
{time_display}
} + } else { + html! {} + }}
- } + }) }).collect::() }
@@ -207,4 +235,48 @@ fn get_weekday_name(weekday: Weekday) -> &'static str { Weekday::Fri => "Fri", Weekday::Sat => "Sat", } +} + +// Calculate the pixel position of an event based on its time +// Each hour is 60px, so we convert time to pixels +fn calculate_event_position(event: &CalendarEvent, date: NaiveDate) -> (f32, f32, bool) { + // Convert UTC times to local time for display + let local_start = event.start.with_timezone(&Local); + let event_date = local_start.date_naive(); + + // Only position events that are on this specific date + if event_date != date { + return (0.0, 0.0, false); // Event not on this date + } + + // Handle all-day events - they appear at the top + if event.all_day { + return (0.0, 30.0, true); // Position at top, 30px height, is_all_day = true + } + + // Calculate start position in pixels from midnight + let start_hour = local_start.hour() as f32; + let start_minute = local_start.minute() as f32; + let start_pixels = (start_hour + start_minute / 60.0) * 60.0; // 60px per hour + + // Calculate duration and height + let duration_pixels = if let Some(end) = event.end { + let local_end = end.with_timezone(&Local); + let end_date = local_end.date_naive(); + + // Handle events that span multiple days by capping at midnight + if end_date > date { + // Event continues past midnight, cap at 24:00 (1440px) + 1440.0 - start_pixels + } else { + let end_hour = local_end.hour() as f32; + let end_minute = local_end.minute() as f32; + let end_pixels = (end_hour + end_minute / 60.0) * 60.0; + (end_pixels - start_pixels).max(20.0) // Minimum 20px height + } + } else { + 60.0 // Default 1 hour if no end time + }; + + (start_pixels, duration_pixels, false) // is_all_day = false } \ No newline at end of file diff --git a/styles.css b/styles.css index 75fca46..6cdf730 100644 --- a/styles.css +++ b/styles.css @@ -644,6 +644,27 @@ body { border-color: #ff9800; } +.week-event .event-title { + font-weight: 600; + margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.week-event .event-time { + font-size: 0.65rem; + opacity: 0.9; + font-weight: 400; +} + +.week-event.all-day { + opacity: 0.9; + border-left: 4px solid rgba(255,255,255,0.5); + font-style: italic; + background: linear-gradient(135deg, var(--event-color, #3B82F6), rgba(255,255,255,0.1)) !important; +} + /* Legacy Week Grid (for backward compatibility) */ .week-grid { display: grid;