Add palette manager for multiple named palettes

This commit is contained in:
Jared Miller 2026-02-07 20:52:28 -05:00
parent 3945887e62
commit e23ac18cd9
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -226,6 +226,15 @@
<fieldset>
<legend>Palette</legend>
<div id="palette-manager" style="margin-bottom: 0.5rem;">
<select id="palette-select" style="width: 100%; margin-bottom: 0.25rem;"></select>
<div style="display: flex; gap: 0.25rem;">
<button id="palette-new" style="flex: 1; font-size: 0.85em; padding: 2px 4px;">new</button>
<button id="palette-save" style="flex: 1; font-size: 0.85em; padding: 2px 4px;">save</button>
<button id="palette-rename" style="flex: 1; font-size: 0.85em; padding: 2px 4px;">rename</button>
<button id="palette-delete" style="flex: 1; font-size: 0.85em; padding: 2px 4px;">delete</button>
</div>
</div>
<div id="palette-list" class="palette-list"></div>
<div id="palette-form" style="display: none">
<div class="form-row">
@ -266,6 +275,7 @@
];
let palette = structuredClone(DEFAULT_PALETTE);
let activePaletteName = 'default';
const DEFAULT_COLOR = [200, 200, 200]; // light gray
@ -453,6 +463,14 @@
}
function loadState() {
// Load palette manager state
activePaletteName = loadActivePaletteName();
const palettes = loadPalettesFromStorage();
if (palettes[activePaletteName]) {
palette = structuredClone(palettes[activePaletteName]);
}
updatePaletteSelect();
const saved = localStorage.getItem('map_editor_state');
if (saved) {
try {
@ -583,6 +601,117 @@ ${paletteStr}"""
m2Slot.style.color = `rgb(${c2[0]},${c2[1]},${c2[2]})`;
}
// Palette manager functions
function loadPalettesFromStorage() {
const saved = localStorage.getItem('map_editor_palettes');
if (saved) {
try {
return JSON.parse(saved);
} catch (e) {
console.error('Failed to load palettes:', e);
}
}
return { 'default': structuredClone(DEFAULT_PALETTE) };
}
function savePalettesToStorage(palettes) {
localStorage.setItem('map_editor_palettes', JSON.stringify(palettes));
}
function loadActivePaletteName() {
const saved = localStorage.getItem('map_editor_active_palette');
return saved || 'default';
}
function saveActivePaletteName(name) {
localStorage.setItem('map_editor_active_palette', name);
}
function saveCurrentPalette() {
const palettes = loadPalettesFromStorage();
palettes[activePaletteName] = structuredClone(palette);
savePalettesToStorage(palettes);
}
function loadPalette(name) {
const palettes = loadPalettesFromStorage();
if (palettes[name]) {
palette = structuredClone(palettes[name]);
activePaletteName = name;
saveActivePaletteName(name);
renderPalette();
renderCanvas();
updateSymbolSlotColors();
updatePaletteSelect();
saveState();
}
}
function updatePaletteSelect() {
const select = document.getElementById('palette-select');
const palettes = loadPalettesFromStorage();
select.innerHTML = '';
for (const name of Object.keys(palettes).sort()) {
const option = document.createElement('option');
option.value = name;
option.textContent = name;
option.selected = name === activePaletteName;
select.appendChild(option);
}
}
function createNewPalette() {
const name = prompt('Enter palette name:');
if (!name) return;
const palettes = loadPalettesFromStorage();
if (palettes[name]) {
alert('Palette with that name already exists.');
return;
}
palettes[name] = structuredClone(DEFAULT_PALETTE);
savePalettesToStorage(palettes);
loadPalette(name);
}
function renamePalette() {
const newName = prompt('Enter new name:', activePaletteName);
if (!newName || newName === activePaletteName) return;
const palettes = loadPalettesFromStorage();
if (palettes[newName]) {
alert('Palette with that name already exists.');
return;
}
palettes[newName] = palettes[activePaletteName];
delete palettes[activePaletteName];
savePalettesToStorage(palettes);
activePaletteName = newName;
saveActivePaletteName(newName);
updatePaletteSelect();
}
function deletePalette() {
const palettes = loadPalettesFromStorage();
const paletteNames = Object.keys(palettes);
if (paletteNames.length === 1) {
alert('Cannot delete the last palette.');
return;
}
if (!confirm(`Delete palette "${activePaletteName}"?`)) return;
delete palettes[activePaletteName];
savePalettesToStorage(palettes);
const remainingNames = Object.keys(palettes);
loadPalette(remainingNames[0]);
}
// Palette UI
function renderPalette() {
const list = document.getElementById('palette-list');
@ -642,6 +771,7 @@ ${paletteStr}"""
renderPalette();
renderCanvas();
updateSymbolSlotColors();
saveCurrentPalette();
saveState();
});
@ -708,6 +838,7 @@ ${paletteStr}"""
renderPalette();
renderCanvas();
updateSymbolSlotColors();
saveCurrentPalette();
saveState();
}
@ -824,6 +955,16 @@ ${paletteStr}"""
}
});
// Palette manager buttons
document.getElementById('palette-select').addEventListener('change', (e) => {
loadPalette(e.target.value);
});
document.getElementById('palette-new').addEventListener('click', createNewPalette);
document.getElementById('palette-save').addEventListener('click', saveCurrentPalette);
document.getElementById('palette-rename').addEventListener('click', renamePalette);
document.getElementById('palette-delete').addEventListener('click', deletePalette);
// Palette buttons
document.getElementById('add-palette').addEventListener('click', () => {
showPaletteForm();