Implement right-click color editor modal for customizable calendar colors

- Add ColorEditorModal component with full color picker interface
- Replace theme-dependent colors with unified color palette
- Store custom colors in database via preferences API for cross-device sync
- Add right-click handlers on color dots to open editor modal
- Fix event bubbling to prevent calendar context menu conflicts
- Add comprehensive CSS styling for modal with proper positioning

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-09-19 11:56:16 -04:00
parent fd80624429
commit 4aca6c7fae
6 changed files with 512 additions and 36 deletions

View File

@@ -99,6 +99,7 @@ pub struct SidebarProps {
pub on_color_change: Callback<(String, String)>,
pub on_color_picker_toggle: Callback<String>,
pub available_colors: Vec<String>,
pub on_color_editor_open: Callback<(usize, String)>, // (index, current_color)
pub refreshing_calendar_id: Option<i32>,
pub on_calendar_context_menu: Callback<(MouseEvent, String)>,
pub on_calendar_visibility_toggle: Callback<String>,
@@ -209,6 +210,7 @@ pub fn sidebar(props: &SidebarProps) -> Html {
on_color_change={props.on_color_change.clone()}
on_color_picker_toggle={props.on_color_picker_toggle.clone()}
available_colors={props.available_colors.clone()}
on_color_editor_open={props.on_color_editor_open.clone()}
on_context_menu={props.on_calendar_context_menu.clone()}
on_visibility_toggle={props.on_calendar_visibility_toggle.clone()}
/>
@@ -289,6 +291,17 @@ pub fn sidebar(props: &SidebarProps) -> Html {
let on_color_select = Callback::from(move |_: MouseEvent| {
on_color_change.emit((external_id.clone(), color_str.clone()));
});
let on_color_right_click = {
let on_color_editor_open = props.on_color_editor_open.clone();
let color_index = props.available_colors.iter().position(|c| c == color).unwrap_or(0);
let color_str = color.clone();
Callback::from(move |e: MouseEvent| {
e.prevent_default();
e.stop_propagation();
on_color_editor_open.emit((color_index, color_str.clone()));
})
};
let is_selected = cal.color == *color;
@@ -298,6 +311,7 @@ pub fn sidebar(props: &SidebarProps) -> Html {
class={if is_selected { "color-option selected" } else { "color-option" }}
style={format!("background-color: {}", color)}
onclick={on_color_select}
oncontextmenu={on_color_right_click}
/>
}
}).collect::<Html>()