From f54666214385603548014e09d96c5790509940cf Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 17 Dec 2025 17:40:28 -0500 Subject: [PATCH] Use modal color picker for classic palette --- classic.js | 109 +++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/classic.js b/classic.js index 992dd53..00949b6 100644 --- a/classic.js +++ b/classic.js @@ -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 = [];