mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
feat: Add edit functionality for custom themes
- Add Sliders icon edit button to custom theme cards in PresetGallery - Edit button positioned between Apply and Delete buttons - Implement handleEditTheme to load theme colors into editor - Track editing state with editingThemeId to update existing themes - Update save logic to reuse theme ID when editing vs creating new - Switch to customize tab and show toast when editing begins - Update success message to show 'updated' vs 'saved' appropriately
This commit is contained in:
+40
-20
@@ -11,14 +11,15 @@ import { ThemePreset } from '../../../../../themes/presets/types';
|
||||
import { getThemePresets, applyThemePreset } from '../../../../../api';
|
||||
import { getActiveTheme, deleteCustomTheme } from '../../../../../api/theme-api';
|
||||
import { useTheme } from '../../../../../contexts/ThemeContext';
|
||||
import { Check, Download, Trash2 } from 'lucide-react';
|
||||
import { Check, Download, Trash2, Sliders } from 'lucide-react';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '../../../../ui/Tooltip';
|
||||
|
||||
interface PresetGalleryProps {
|
||||
onApply?: () => void;
|
||||
onEdit?: (preset: ThemePreset) => void;
|
||||
}
|
||||
|
||||
export function PresetGallery({ onApply }: PresetGalleryProps) {
|
||||
export function PresetGallery({ onApply, onEdit }: PresetGalleryProps) {
|
||||
const { resolvedTheme } = useTheme();
|
||||
const [presets, setPresets] = useState<ThemePreset[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -243,25 +244,44 @@ export function PresetGallery({ onApply }: PresetGalleryProps) {
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* Delete Button (only for custom themes) */}
|
||||
{/* Edit and Delete Buttons (only for custom themes) */}
|
||||
{isCustom && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
onClick={() => handleDeleteTheme(preset.id, preset.name)}
|
||||
disabled={applying !== null || deleting !== null}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
shape="round"
|
||||
className="text-text-danger hover:bg-background-danger"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{deleting === preset.id ? 'Deleting...' : 'Delete Theme'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<>
|
||||
{/* Edit Button */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
onClick={() => onEdit?.(preset)}
|
||||
disabled={applying !== null || deleting !== null}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
shape="round"
|
||||
>
|
||||
<Sliders className="w-4 h-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Edit Theme</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* Delete Button */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
onClick={() => handleDeleteTheme(preset.id, preset.name)}
|
||||
disabled={applying !== null || deleting !== null}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
shape="round"
|
||||
className="text-text-danger hover:bg-background-danger"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{deleting === preset.id ? 'Deleting...' : 'Delete Theme'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,6 +29,7 @@ export function ThemeColorEditor({ onClose }: ThemeColorEditorProps) {
|
||||
const [selectedVariable, setSelectedVariable] = useState<string | null>(null);
|
||||
const [themeName, setThemeName] = useState('My Custom Theme');
|
||||
const [themeDescription, setThemeDescription] = useState('');
|
||||
const [editingThemeId, setEditingThemeId] = useState<string | null>(null);
|
||||
|
||||
// Use system theme instead of separate mode state
|
||||
const activeMode: ColorMode = resolvedTheme;
|
||||
@@ -88,8 +89,8 @@ export function ThemeColorEditor({ onClose }: ThemeColorEditorProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate a unique theme ID from the name
|
||||
const themeId = `custom-${themeName.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${Date.now()}`;
|
||||
// Use existing ID if editing, otherwise generate new one
|
||||
const themeId = editingThemeId || `custom-${themeName.toLowerCase().replace(/[^a-z0-9]+/g, '-')}-${Date.now()}`;
|
||||
|
||||
// Convert back to CSS format
|
||||
const cssLines: string[] = [];
|
||||
@@ -131,7 +132,8 @@ export function ThemeColorEditor({ onClose }: ThemeColorEditorProps) {
|
||||
},
|
||||
});
|
||||
|
||||
toast.success(`Theme "${themeName}" saved and applied successfully!`);
|
||||
const action = editingThemeId ? 'updated' : 'saved';
|
||||
toast.success(`Theme "${themeName}" ${action} and applied successfully!`);
|
||||
|
||||
// Reload the page to apply changes
|
||||
window.location.reload();
|
||||
@@ -161,6 +163,24 @@ export function ThemeColorEditor({ onClose }: ThemeColorEditorProps) {
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditTheme = (preset: any) => {
|
||||
// Load the preset's colors into the editor
|
||||
setThemeColors({
|
||||
light: preset.colors.light || {},
|
||||
dark: preset.colors.dark || {},
|
||||
});
|
||||
|
||||
// Set the theme metadata
|
||||
setThemeName(preset.name);
|
||||
setThemeDescription(preset.description || '');
|
||||
setEditingThemeId(preset.id);
|
||||
|
||||
// Switch to customize tab
|
||||
setActiveTab('customize');
|
||||
|
||||
toast.info(`Editing "${preset.name}"`);
|
||||
};
|
||||
|
||||
const groupedVariables = COLOR_VARIABLES.reduce((acc, variable) => {
|
||||
if (!acc[variable.category]) {
|
||||
acc[variable.category] = [];
|
||||
@@ -256,7 +276,7 @@ export function ThemeColorEditor({ onClose }: ThemeColorEditorProps) {
|
||||
|
||||
{/* Presets Tab */}
|
||||
<TabsContent value="presets" className="flex-1 overflow-auto px-6 py-4">
|
||||
<PresetGallery onApply={onClose} />
|
||||
<PresetGallery onApply={onClose} onEdit={handleEditTheme} />
|
||||
</TabsContent>
|
||||
|
||||
{/* Customize Tab */}
|
||||
|
||||
Reference in New Issue
Block a user