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:
@@ -61,6 +61,9 @@ pub struct CalendarEvent {
|
||||
|
||||
/// URL/href of this event on the CalDAV server
|
||||
pub href: Option<String>,
|
||||
|
||||
/// Calendar path this event belongs to
|
||||
pub calendar_path: Option<String>,
|
||||
}
|
||||
|
||||
/// Event status enumeration
|
||||
@@ -182,11 +185,11 @@ impl CalDAVClient {
|
||||
}
|
||||
|
||||
let body = response.text().await.map_err(CalDAVError::RequestError)?;
|
||||
self.parse_calendar_response(&body)
|
||||
self.parse_calendar_response(&body, calendar_path)
|
||||
}
|
||||
|
||||
/// Parse CalDAV XML response containing calendar data
|
||||
fn parse_calendar_response(&self, xml_response: &str) -> Result<Vec<CalendarEvent>, CalDAVError> {
|
||||
fn parse_calendar_response(&self, xml_response: &str, calendar_path: &str) -> Result<Vec<CalendarEvent>, CalDAVError> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
// Extract calendar data from XML response
|
||||
@@ -198,6 +201,7 @@ impl CalDAVClient {
|
||||
for mut event in parsed_events {
|
||||
event.etag = calendar_data.etag.clone();
|
||||
event.href = calendar_data.href.clone();
|
||||
event.calendar_path = Some(calendar_path.to_string());
|
||||
events.push(event);
|
||||
}
|
||||
}
|
||||
@@ -377,6 +381,7 @@ impl CalDAVClient {
|
||||
reminders: self.parse_alarms(&event)?,
|
||||
etag: None, // Set by caller
|
||||
href: None, // Set by caller
|
||||
calendar_path: None, // Set by caller
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -145,8 +145,9 @@ pub async fn get_user_info(
|
||||
None
|
||||
} else {
|
||||
Some(CalendarInfo {
|
||||
path,
|
||||
path: path.clone(),
|
||||
display_name,
|
||||
color: generate_calendar_color(&path),
|
||||
})
|
||||
}
|
||||
}).collect();
|
||||
@@ -158,6 +159,39 @@ pub async fn get_user_info(
|
||||
}))
|
||||
}
|
||||
|
||||
// Helper function to generate a consistent color for a calendar based on its path
|
||||
fn generate_calendar_color(path: &str) -> String {
|
||||
// Predefined set of attractive, accessible colors for calendars
|
||||
let colors = [
|
||||
"#3B82F6", // Blue
|
||||
"#10B981", // Emerald
|
||||
"#F59E0B", // Amber
|
||||
"#EF4444", // Red
|
||||
"#8B5CF6", // Violet
|
||||
"#06B6D4", // Cyan
|
||||
"#84CC16", // Lime
|
||||
"#F97316", // Orange
|
||||
"#EC4899", // Pink
|
||||
"#6366F1", // Indigo
|
||||
"#14B8A6", // Teal
|
||||
"#F3B806", // Yellow
|
||||
"#8B5A2B", // Brown
|
||||
"#6B7280", // Gray
|
||||
"#DC2626", // Red-600
|
||||
"#7C3AED", // Violet-600
|
||||
];
|
||||
|
||||
// Create a simple hash from the path to ensure consistent color assignment
|
||||
let mut hash: u32 = 0;
|
||||
for byte in path.bytes() {
|
||||
hash = hash.wrapping_mul(31).wrapping_add(byte as u32);
|
||||
}
|
||||
|
||||
// Use the hash to select a color from our palette
|
||||
let color_index = (hash as usize) % colors.len();
|
||||
colors[color_index].to_string()
|
||||
}
|
||||
|
||||
// Helper function to extract a readable calendar name from path
|
||||
fn extract_calendar_name(path: &str) -> String {
|
||||
// Extract the last meaningful part of the path
|
||||
|
||||
@@ -31,6 +31,7 @@ pub struct UserInfo {
|
||||
pub struct CalendarInfo {
|
||||
pub path: String,
|
||||
pub display_name: String,
|
||||
pub color: String,
|
||||
}
|
||||
|
||||
// Error handling
|
||||
|
||||
Reference in New Issue
Block a user