Fix calendar management modal color picker issues
- Fix z-index issue by creating separate CSS classes for inline vs dropdown color pickers - Unify CalDAV and external calendar color pickers to use same grid interface - Improve color picker styling with 4x4 grid layout for 16 colors - Enhance color option appearance with proper border centering and sizing - Replace native HTML color input with consistent predefined color grid - Add visual improvements: larger swatches, better hover effects, checkmark selection 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,7 @@ pub fn calendar_list_item(props: &CalendarListItemProps) -> Html {
|
||||
{
|
||||
if props.color_picker_open {
|
||||
html! {
|
||||
<div class="color-picker">
|
||||
<div class="color-picker-dropdown">
|
||||
{
|
||||
props.available_colors.iter().map(|color| {
|
||||
let color_str = color.clone();
|
||||
|
||||
@@ -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::<String>);
|
||||
|
||||
@@ -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::<HtmlInputElement>()
|
||||
.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 {
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="external-color">{"Calendar Color"}</label>
|
||||
<input
|
||||
type="color"
|
||||
id="external-color"
|
||||
ref={external_color_ref.clone()}
|
||||
value="#4285f4"
|
||||
disabled={*external_is_loading}
|
||||
/>
|
||||
<label>{"Calendar Color"}</label>
|
||||
<div class="color-picker">
|
||||
{
|
||||
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! {
|
||||
<div
|
||||
key={color.clone()}
|
||||
class={if is_selected { "color-option selected" } else { "color-option" }}
|
||||
style={format!("background-color: {}", color)}
|
||||
onclick={Callback::from(move |_: MouseEvent| {
|
||||
on_external_color_select.emit(color_clone.clone());
|
||||
})}
|
||||
/>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user