diff --git a/frontend/src/components/calendar_list_item.rs b/frontend/src/components/calendar_list_item.rs index 555bd31..db5066f 100644 --- a/frontend/src/components/calendar_list_item.rs +++ b/frontend/src/components/calendar_list_item.rs @@ -55,7 +55,7 @@ pub fn calendar_list_item(props: &CalendarListItemProps) -> Html { { if props.color_picker_open { html! { -
+
{ props.available_colors.iter().map(|color| { let color_str = color.clone(); diff --git a/frontend/src/components/calendar_management_modal.rs b/frontend/src/components/calendar_management_modal.rs index f6827be..5b8d7e9 100644 --- a/frontend/src/components/calendar_management_modal.rs +++ b/frontend/src/components/calendar_management_modal.rs @@ -32,7 +32,7 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html { // External Calendar state let external_name_ref = use_node_ref(); let external_url_ref = use_node_ref(); - let external_color_ref = use_node_ref(); + let external_selected_color = use_state(|| Some("#4285f4".to_string())); let external_is_loading = use_state(|| false); let external_error_message = use_state(|| None::); @@ -45,6 +45,7 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html { let is_creating = is_creating.clone(); let external_is_loading = external_is_loading.clone(); let external_error_message = external_error_message.clone(); + let external_selected_color = external_selected_color.clone(); let active_tab = active_tab.clone(); move |is_open| { @@ -57,6 +58,7 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html { is_creating.set(false); external_is_loading.set(false); external_error_message.set(None); + external_selected_color.set(Some("#4285f4".to_string())); active_tab.set(CalendarTab::Create); } } @@ -105,6 +107,13 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html { }) }; + let on_external_color_select = { + let external_selected_color = external_selected_color.clone(); + Callback::from(move |color: String| { + external_selected_color.set(Some(color)); + }) + }; + let on_create_submit = { let calendar_name = calendar_name.clone(); let description = description.clone(); @@ -139,7 +148,7 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html { let on_external_submit = { let external_name_ref = external_name_ref.clone(); let external_url_ref = external_url_ref.clone(); - let external_color_ref = external_color_ref.clone(); + let external_selected_color = external_selected_color.clone(); let external_is_loading = external_is_loading.clone(); let external_error_message = external_error_message.clone(); let on_close = props.on_close.clone(); @@ -162,10 +171,7 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html { .trim() .to_string(); - let color = external_color_ref - .cast::() - .map(|input| input.value()) - .unwrap_or_else(|| "#4285f4".to_string()); + let color = (*external_selected_color).clone().unwrap_or_else(|| "#4285f4".to_string()); if name.is_empty() || url.is_empty() { external_error_message.set(Some("Name and URL are required".to_string())); @@ -348,14 +354,27 @@ pub fn calendar_management_modal(props: &CalendarManagementModalProps) -> Html {
- - + +
+ { + props.available_colors.iter().map(|color| { + let is_selected = external_selected_color.as_ref() == Some(color); + let color_clone = color.clone(); + let on_external_color_select = on_external_color_select.clone(); + + html! { +
+ } + }).collect::() + } +
{ diff --git a/frontend/styles.css b/frontend/styles.css index 2c2a989..b920918 100644 --- a/frontend/styles.css +++ b/frontend/styles.css @@ -260,7 +260,20 @@ body { transform: scale(1.1); } +/* Inline color picker for forms */ .color-picker { + background: white; + border-radius: 4px; + padding: 1rem; + border: 1px solid #e5e7eb; + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0.75rem; + max-width: 220px; +} + +/* Dropdown color picker for sidebar calendars */ +.color-picker-dropdown { position: absolute; top: 100%; left: 0; @@ -277,23 +290,42 @@ body { } .color-option { - width: 20px; - height: 20px; - border-radius: 50%; - border: 2px solid rgba(0,0,0,0.1); + width: 38px; + height: 38px; + border-radius: 6px; + border: 3px solid rgba(0,0,0,0.15); cursor: pointer; - transition: all 0.2s; + transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + box-shadow: 0 1px 2px rgba(0,0,0,0.08); + box-sizing: border-box; } .color-option:hover { - transform: scale(1.2); - border-color: rgba(0,0,0,0.3); + transform: translateY(-2px); + border-color: rgba(0,0,0,0.2); + box-shadow: 0 4px 8px rgba(0,0,0,0.15); } .color-option.selected { - border-color: #333; + border-color: #2563eb; border-width: 3px; - transform: scale(1.1); + transform: translateY(-2px) scale(1.05); + box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.3), + 0 4px 8px rgba(0,0,0,0.15); +} + +.color-option.selected::after { + content: '✓'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + font-size: 16px; + font-weight: bold; + text-shadow: 0 1px 3px rgba(0,0,0,0.7); + z-index: 1; } .color-picker-overlay {