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 {
{
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 {