From 53815c481467b2d139f6b95085b8eea00f393319 Mon Sep 17 00:00:00 2001 From: Connor Johnstone Date: Fri, 29 Aug 2025 11:04:13 -0400 Subject: [PATCH] Add 15-minute snapping and time display to drag-to-create functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhance the drag-to-create event feature with precision improvements: - Add snap_to_15_minutes() function to align drag coordinates to 15-minute increments - Update mousedown and mousemove handlers to use coordinate snapping - Replace pixel coordinate display with actual time ranges in temporary event box - Display times in 12-hour format with AM/PM (e.g., "2:15 PM - 3:30 PM") - Remove unused wasm_bindgen::JsCast import for cleaner code Users can now create events that automatically align to 15-minute boundaries with clear visual feedback showing the exact time range being selected. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/components/week_view.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/components/week_view.rs b/src/components/week_view.rs index d240157..f5f97f2 100644 --- a/src/components/week_view.rs +++ b/src/components/week_view.rs @@ -2,7 +2,6 @@ use yew::prelude::*; use chrono::{Datelike, NaiveDate, Duration, Weekday, Local, Timelike, NaiveDateTime, NaiveTime}; use std::collections::HashMap; use web_sys::MouseEvent; -use wasm_bindgen::JsCast; use crate::services::calendar_service::{CalendarEvent, UserInfo}; #[derive(Properties, PartialEq)] @@ -126,11 +125,14 @@ pub fn week_view(props: &WeekViewProps) -> Html { let relative_y = e.layer_y() as f64; let relative_y = if relative_y > 0.0 { relative_y } else { e.offset_y() as f64 }; + // Snap to 15-minute increments + let snapped_y = snap_to_15_minutes(relative_y); + drag_state.set(Some(DragState { is_dragging: true, start_date: date_for_drag, - start_y: relative_y, - current_y: relative_y, + start_y: snapped_y, + current_y: snapped_y, })); e.prevent_default(); }) @@ -145,7 +147,10 @@ pub fn week_view(props: &WeekViewProps) -> Html { let relative_y = e.layer_y() as f64; let relative_y = if relative_y > 0.0 { relative_y } else { e.offset_y() as f64 }; - current_drag.current_y = relative_y; + // Snap to 15-minute increments + let snapped_y = snap_to_15_minutes(relative_y); + + current_drag.current_y = snapped_y; drag_state.set(Some(current_drag)); } } @@ -323,16 +328,19 @@ pub fn week_view(props: &WeekViewProps) -> Html { if let Some(drag) = (*drag_state).clone() { if drag.is_dragging && drag.start_date == *date { let start_y = drag.start_y.min(drag.current_y); + let end_y = drag.start_y.max(drag.current_y); let height = (drag.current_y - drag.start_y).abs().max(20.0); - // Debug logging + // Convert pixels to times for display + let start_time = pixels_to_time(start_y); + let end_time = pixels_to_time(end_y); html! {
- {format!("{}px - {}px", start_y as u32, (start_y + height) as u32)} + {format!("{} - {}", start_time.format("%I:%M %p"), end_time.format("%I:%M %p"))}
} } else { @@ -381,6 +389,12 @@ fn get_weekday_name(weekday: Weekday) -> &'static str { // Calculate the pixel position of an event based on its time // Each hour is 60px, so we convert time to pixels +// Snap pixel position to 15-minute increments (15px = 15 minutes since 60px = 60 minutes) +fn snap_to_15_minutes(pixels: f64) -> f64 { + let increment = 15.0; // 15px = 15 minutes + (pixels / increment).round() * increment +} + // Convert pixel position to time (inverse of time to pixels) fn pixels_to_time(pixels: f64) -> NaiveTime { let total_minutes = (pixels / 60.0) * 60.0; // 60px per hour, 60 minutes per hour