Add palette manager for multiple named palettes
This commit is contained in:
parent
3945887e62
commit
e23ac18cd9
1 changed files with 141 additions and 0 deletions
|
|
@ -226,6 +226,15 @@
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Palette</legend>
|
<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-list" class="palette-list"></div>
|
||||||
<div id="palette-form" style="display: none">
|
<div id="palette-form" style="display: none">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
|
|
@ -266,6 +275,7 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
let palette = structuredClone(DEFAULT_PALETTE);
|
let palette = structuredClone(DEFAULT_PALETTE);
|
||||||
|
let activePaletteName = 'default';
|
||||||
|
|
||||||
const DEFAULT_COLOR = [200, 200, 200]; // light gray
|
const DEFAULT_COLOR = [200, 200, 200]; // light gray
|
||||||
|
|
||||||
|
|
@ -453,6 +463,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadState() {
|
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');
|
const saved = localStorage.getItem('map_editor_state');
|
||||||
if (saved) {
|
if (saved) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -583,6 +601,117 @@ ${paletteStr}"""
|
||||||
m2Slot.style.color = `rgb(${c2[0]},${c2[1]},${c2[2]})`;
|
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
|
// Palette UI
|
||||||
function renderPalette() {
|
function renderPalette() {
|
||||||
const list = document.getElementById('palette-list');
|
const list = document.getElementById('palette-list');
|
||||||
|
|
@ -642,6 +771,7 @@ ${paletteStr}"""
|
||||||
renderPalette();
|
renderPalette();
|
||||||
renderCanvas();
|
renderCanvas();
|
||||||
updateSymbolSlotColors();
|
updateSymbolSlotColors();
|
||||||
|
saveCurrentPalette();
|
||||||
saveState();
|
saveState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -708,6 +838,7 @@ ${paletteStr}"""
|
||||||
renderPalette();
|
renderPalette();
|
||||||
renderCanvas();
|
renderCanvas();
|
||||||
updateSymbolSlotColors();
|
updateSymbolSlotColors();
|
||||||
|
saveCurrentPalette();
|
||||||
saveState();
|
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
|
// Palette buttons
|
||||||
document.getElementById('add-palette').addEventListener('click', () => {
|
document.getElementById('add-palette').addEventListener('click', () => {
|
||||||
showPaletteForm();
|
showPaletteForm();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue