Use modal color picker for classic palette

This commit is contained in:
chris 2025-12-17 17:40:28 -05:00
parent 540acedcab
commit f546662143

View File

@ -588,23 +588,30 @@ function distinctPaletteSlots(palette) {
const isArch = (model.patternName || '').toLowerCase().includes('arch');
let slideX = 80;
let slideY = 0;
const idx = typeof cell.balloonIndexInCluster === 'number' ? cell.balloonIndexInCluster : 0;
const spread = idx - 1.5;
if (isArch) {
// Radial slide outward; preserve layout.
const dist = Math.hypot(c.x, c.y) || 1;
const offset = 80;
slideX = (c.x / dist) * offset;
slideY = (c.y / dist) * offset;
const nx = c.x / dist, ny = c.y / dist;
slideX = nx * offset;
slideY = ny * offset;
// Slight tangent spread (~5px) to separate balloons without reshaping the quad.
const txDirX = -ny;
const txDirY = nx;
const fan = spread * 10;
slideX += txDirX * fan;
slideY += txDirY * fan;
}
let tx = c.x + slideX;
let ty = c.y + slideY;
// Keep shape intact; only fan columns slightly.
const idx = typeof cell.balloonIndexInCluster === 'number' ? cell.balloonIndexInCluster : 0;
const spread = idx - 1.5;
if (isArch) {
// no fan/scale for arches; preserve layout
} else {
tx += spread * 4;
ty += spread * 2;
tx += spread * 12;
ty += spread * 10;
}
const fanScale = 1;
// Nudge the top pair down slightly in columns so they remain easily clickable.
@ -1016,7 +1023,7 @@ function distinctPaletteSlots(palette) {
btn.className = 'slot-btn tab-btn';
btn.dataset.slot = String(i);
btn.textContent = `#${i}`;
btn.addEventListener('click', () => { activeTarget = String(i); updateUI(); });
btn.addEventListener('click', () => { activeTarget = String(i); updateUI(); openPalettePicker(); });
slotsContainer.appendChild(btn);
}
}
@ -1115,53 +1122,55 @@ function distinctPaletteSlots(palette) {
}
}
const allPaletteColors = flattenPalette(); swatchGrid.innerHTML = '';
(window.PALETTE || []).forEach(group => {
const title = document.createElement('div'); title.className = 'family-title'; title.textContent = group.family; swatchGrid.appendChild(title);
const row = document.createElement('div'); row.className = 'swatch-row';
(group.colors || []).forEach(colorItem => {
const sw = document.createElement('button'); sw.type = 'button'; sw.className = 'swatch'; sw.title = colorItem.name;
sw.setAttribute('aria-label', colorItem.name);
sw.dataset.hex = normHex(colorItem.hex);
if (colorItem.image) sw.dataset.image = colorItem.image;
sw.style.backgroundImage = colorItem.image ? `url("${colorItem.image}")` : 'none';
sw.style.backgroundColor = colorItem.hex;
sw.style.backgroundSize = '500%';
sw.style.backgroundPosition = 'center';
const allPaletteColors = flattenPalette();
swatchGrid.innerHTML = '';
swatchGrid.style.display = 'none'; // hide inline list; use modal picker instead
sw.addEventListener('click', () => {
const selectedColor = { hex: colorItem.hex, image: colorItem.image };
const currentType = document.querySelector('.topper-type-btn[aria-pressed="true"]')?.dataset.type || 'round';
if (activeTarget === 'T') {
if (currentType.startsWith('num-')) {
setNumberTintColor(selectedColor.hex);
setNumberTintOpacity(1);
if (numberTintSlider) numberTintSlider.value = 1;
} else {
setTopperColor(selectedColor);
}
} else if (isManual()) {
manualActiveColorGlobal = window.shared?.setActiveColor?.(selectedColor) || selectedColor;
} else {
const index = parseInt(activeTarget, 10) - 1;
if (index >= 0 && index < MAX_SLOTS) { classicColors[index] = selectedColor; setClassicColors(classicColors); }
}
updateUI(); onColorChange();
if (window.updateExportButtonVisibility) window.updateExportButtonVisibility();
});
row.appendChild(sw);
});
swatchGrid.appendChild(row);
});
topperSwatch.addEventListener('click', () => { activeTarget = 'T'; updateUI(); });
const openPalettePicker = () => {
if (typeof window.openColorPicker !== 'function') return;
const items = allPaletteColors.map(c => ({
label: c.name || c.hex,
hex: c.hex,
meta: c,
metaText: c.family || ''
}));
const currentType = document.querySelector('.topper-type-btn[aria-pressed="true"]')?.dataset.type || 'round';
const subtitle = isManual()
? 'Apply to active paint'
: (activeTarget === 'T' ? 'Set topper color' : `Set slot #${activeTarget}`);
window.openColorPicker({
title: 'Choose a color',
subtitle,
items,
onSelect: (item) => {
const meta = item.meta || {};
const selectedColor = { hex: meta.hex || item.hex, image: meta.image || null };
if (activeTarget === 'T') {
if (currentType.startsWith('num-')) {
setNumberTintColor(selectedColor.hex);
setNumberTintOpacity(1);
if (numberTintSlider) numberTintSlider.value = 1;
} else {
setTopperColor(selectedColor);
}
} else if (isManual()) {
manualActiveColorGlobal = window.shared?.setActiveColor?.(selectedColor) || selectedColor;
} else {
const index = parseInt(activeTarget, 10) - 1;
if (index >= 0 && index < MAX_SLOTS) { classicColors[index] = selectedColor; setClassicColors(classicColors); }
}
updateUI(); onColorChange();
if (window.updateExportButtonVisibility) window.updateExportButtonVisibility();
}
});
};
topperSwatch.addEventListener('click', () => { activeTarget = 'T'; updateUI(); openPalettePicker(); });
activeChip?.addEventListener('click', () => {
if (openManualPicker()) return;
try { swatchGrid?.scrollIntoView({ behavior: 'smooth', block: 'center' }); } catch {}
openPalettePicker();
});
floatingChip?.addEventListener('click', () => {
if (openManualPicker()) return;
try { swatchGrid?.scrollIntoView({ behavior: 'smooth', block: 'center' }); } catch {}
openPalettePicker();
});
randomizeBtn?.addEventListener('click', () => {
const pool = allPaletteColors.slice(); const picks = [];