Add reset buttons to color editor modal for individual and bulk color resets
All checks were successful
Build and Push Docker Image / docker (push) Successful in 31s

- Add "Reset This Color" button in color preview section for individual resets
- Add "Reset All Colors" button in modal footer for bulk palette reset
- Implement reset callbacks with database persistence via preferences API
- Reorganize color preview layout with flex column for better button placement
- Style reset buttons with appropriate warning colors and hover states
- Support both granular and comprehensive color customization workflows

🤖 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 12:03:25 -04:00
parent 4aca6c7fae
commit 5c406569af
3 changed files with 92 additions and 2 deletions

View File

@@ -365,6 +365,28 @@ pub fn App() -> Html {
})
};
let on_color_editor_reset_all = {
let available_colors = available_colors.clone();
let refresh_colors = refresh_colors.clone();
Callback::from(move |_| {
// Reset to default colors
let default_colors = get_default_event_colors();
available_colors.set(default_colors.clone());
// Save to preferences asynchronously
let colors_for_save = default_colors.clone();
let refresh_colors = refresh_colors.clone();
wasm_bindgen_futures::spawn_local(async move {
if let Err(e) = save_custom_colors_to_preferences(colors_for_save).await {
web_sys::console::log_1(&format!("Failed to save default colors: {}", e).into());
} else {
// Refresh colors to ensure UI is in sync
refresh_colors.emit(());
}
});
})
};
let on_view_change = {
let current_view = current_view.clone();
Callback::from(move |new_view: ViewMode| {
@@ -1801,8 +1823,14 @@ pub fn App() -> Html {
is_open={*color_editor_open}
current_color={color_editor_data.as_ref().map(|(_, color)| color.clone()).unwrap_or_default()}
color_index={color_editor_data.as_ref().map(|(index, _)| *index).unwrap_or(0)}
default_color={
let default_colors = get_default_event_colors();
let index = color_editor_data.as_ref().map(|(index, _)| *index).unwrap_or(0);
default_colors.get(index).cloned().unwrap_or_else(|| "#3B82F6".to_string())
}
on_close={on_color_editor_close}
on_save={on_color_editor_save}
on_reset_all={on_color_editor_reset_all}
/>
</div>

View File

@@ -7,8 +7,10 @@ pub struct ColorEditorModalProps {
pub is_open: bool,
pub current_color: String,
pub color_index: usize,
pub default_color: String, // Default color for this index
pub on_close: Callback<()>,
pub on_save: Callback<(usize, String)>, // (index, new_color)
pub on_reset_all: Callback<()>, // Reset all colors to defaults
}
#[function_component(ColorEditorModal)]
@@ -86,7 +88,18 @@ pub fn color_editor_modal(props: &ColorEditorModalProps) -> Html {
class="color-preview-large"
style={format!("background-color: {}", *selected_color)}
></div>
<div class="color-preview-info">
<span class="color-value">{&*selected_color}</span>
<button class="reset-this-color-button" onclick={{
let selected_color = selected_color.clone();
let default_color = props.default_color.clone();
Callback::from(move |_| {
selected_color.set(default_color.clone());
})
}}>
{"Reset This Color"}
</button>
</div>
</div>
<div class="color-input-section">
@@ -143,6 +156,16 @@ pub fn color_editor_modal(props: &ColorEditorModalProps) -> Html {
})}>
{"Cancel"}
</button>
<button class="reset-all-button" onclick={Callback::from({
let on_reset_all = props.on_reset_all.clone();
let on_close = props.on_close.clone();
move |_| {
on_reset_all.emit(());
on_close.emit(());
}
})}>
{"Reset All Colors"}
</button>
<button class="save-button" onclick={on_save_click}>
{"Save"}
</button>

View File

@@ -4270,6 +4270,13 @@ body {
flex-shrink: 0;
}
.color-preview-info {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
flex: 1;
}
.color-value {
font-family: monospace;
font-size: 0.9rem;
@@ -4277,6 +4284,25 @@ body {
font-weight: 500;
}
.reset-this-color-button {
background: var(--background-secondary);
color: var(--text-secondary);
border: 1px solid var(--border-secondary);
border-radius: var(--border-radius-small);
padding: var(--spacing-xs) var(--spacing-sm);
cursor: pointer;
font-size: 0.8rem;
font-weight: 500;
transition: var(--transition-fast);
align-self: flex-start;
}
.reset-this-color-button:hover {
background: var(--background-tertiary);
color: var(--text-primary);
border-color: var(--text-primary);
}
.color-input-section {
margin-bottom: var(--spacing-lg);
}
@@ -4359,7 +4385,7 @@ body {
border-radius: 0 0 var(--border-radius-medium) var(--border-radius-medium);
}
.cancel-button, .save-button {
.cancel-button, .reset-all-button, .save-button {
padding: var(--spacing-sm) var(--spacing-md);
border: 1px solid var(--border-secondary);
border-radius: var(--border-radius-small);
@@ -4379,6 +4405,19 @@ body {
color: var(--text-primary);
}
.reset-all-button {
background: var(--warning-color);
color: white;
border-color: var(--warning-color);
margin-left: auto;
margin-right: var(--spacing-sm);
}
.reset-all-button:hover {
background: #e0a800;
border-color: #e0a800;
}
.save-button {
background: var(--info-color);
color: white;