Implement interactive calendar color picker
Backend enhancements: - Add calendar_path field to CalendarEvent for color mapping - Generate consistent colors for calendars using path-based hashing - Update CalDAV parsing to associate events with their calendar paths - Add 16-color palette with hash-based assignment algorithm Frontend features: - Interactive color picker with 4x4 grid of selectable colors - Click color swatches to open dropdown with all available colors - Instant color changes for both sidebar and calendar events - Persistent color preferences using local storage - Enhanced UX with hover effects and visual feedback Styling improvements: - Larger 16px color swatches for better clickability - Professional color picker dropdown with smooth animations - Dynamic event coloring based on calendar assignment - Improved contrast with text shadows and borders - Click-outside-to-close functionality for better UX Users can now personalize their calendar organization with custom colors that persist across sessions and immediately update throughout the app. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use yew::prelude::*;
|
||||
use chrono::{Datelike, Local, NaiveDate, Duration, Weekday};
|
||||
use std::collections::HashMap;
|
||||
use crate::services::calendar_service::CalendarEvent;
|
||||
use crate::services::calendar_service::{CalendarEvent, UserInfo};
|
||||
use crate::components::EventModal;
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
@@ -11,6 +11,8 @@ pub struct CalendarProps {
|
||||
pub on_event_click: Callback<CalendarEvent>,
|
||||
#[prop_or_default]
|
||||
pub refreshing_event_uid: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub user_info: Option<UserInfo>,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
@@ -20,6 +22,21 @@ pub fn Calendar(props: &CalendarProps) -> Html {
|
||||
let selected_day = use_state(|| today);
|
||||
let selected_event = use_state(|| None::<CalendarEvent>);
|
||||
|
||||
// Helper function to get calendar color for an event
|
||||
let get_event_color = |event: &CalendarEvent| -> String {
|
||||
if let Some(user_info) = &props.user_info {
|
||||
if let Some(calendar_path) = &event.calendar_path {
|
||||
// Find the calendar that matches this event's path
|
||||
if let Some(calendar) = user_info.calendars.iter()
|
||||
.find(|cal| &cal.path == calendar_path) {
|
||||
return calendar.color.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Default color if no match found
|
||||
"#3B82F6".to_string()
|
||||
};
|
||||
|
||||
let first_day_of_month = current_month.with_day(1).unwrap();
|
||||
let days_in_month = get_days_in_month(*current_month);
|
||||
let first_weekday = first_day_of_month.weekday();
|
||||
@@ -118,10 +135,12 @@ pub fn Calendar(props: &CalendarProps) -> Html {
|
||||
let title = event.get_title();
|
||||
let is_refreshing = props.refreshing_event_uid.as_ref() == Some(&event.uid);
|
||||
let class_name = if is_refreshing { "event-box refreshing" } else { "event-box" };
|
||||
let event_color = get_event_color(&event);
|
||||
html! {
|
||||
<div class={class_name}
|
||||
title={title.clone()}
|
||||
onclick={event_click}>
|
||||
onclick={event_click}
|
||||
style={format!("background-color: {}", event_color)}>
|
||||
{
|
||||
if is_refreshing {
|
||||
"🔄 Refreshing...".to_string()
|
||||
|
||||
Reference in New Issue
Block a user