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;