Use modal picker for organic and wall palettes
This commit is contained in:
parent
f546662143
commit
99d943643b
111
organic.js
111
organic.js
@ -143,6 +143,13 @@
|
||||
const garlandAccentChip = document.getElementById('garland-accent-chip');
|
||||
const garlandAccentClearBtn = document.getElementById('garland-accent-clear');
|
||||
const garlandControls = document.getElementById('garland-controls');
|
||||
// Optional dropdowns (may not be present in current layout)
|
||||
const garlandColorMain1Sel = document.getElementById('garland-color-main-1');
|
||||
const garlandColorMain2Sel = document.getElementById('garland-color-main-2');
|
||||
const garlandColorMain3Sel = document.getElementById('garland-color-main-3');
|
||||
const garlandColorMain4Sel = document.getElementById('garland-color-main-4');
|
||||
const garlandColorAccentSel = document.getElementById('garland-color-accent');
|
||||
const updateGarlandSwatches = () => {}; // stub for layouts without dropdown swatches
|
||||
|
||||
const sizePresetGroup = document.getElementById('size-preset-group');
|
||||
const toggleShineBtn = null;
|
||||
@ -1112,45 +1119,25 @@
|
||||
function renderAllowedPalette() {
|
||||
if (!paletteBox) return;
|
||||
paletteBox.innerHTML = '';
|
||||
(window.PALETTE || []).forEach(group => {
|
||||
const title = document.createElement('div');
|
||||
title.className = 'family-title';
|
||||
title.textContent = group.family;
|
||||
paletteBox.appendChild(title);
|
||||
|
||||
const row = document.createElement('div');
|
||||
row.className = 'swatch-row';
|
||||
(group.colors || []).forEach(c => {
|
||||
const idx =
|
||||
FLAT_COLORS.find(fc => fc.name === c.name && fc.hex === c.hex && fc.family === group.family)?._idx
|
||||
?? HEX_TO_FIRST_IDX.get(normalizeHex(c.hex));
|
||||
const sw = document.createElement('button');
|
||||
sw.type = 'button';
|
||||
sw.className = 'swatch';
|
||||
sw.setAttribute('aria-label', c.name);
|
||||
|
||||
if (c.image) {
|
||||
const meta = FLAT_COLORS[idx] || {};
|
||||
sw.style.backgroundImage = `url("${c.image}")`;
|
||||
sw.style.backgroundSize = `${100 * SWATCH_TEXTURE_ZOOM}%`;
|
||||
sw.style.backgroundPosition = `${(meta.imageFocus?.x ?? 0.5) * 100}% ${(meta.imageFocus?.y ?? 0.5) * 100}%`;
|
||||
} else {
|
||||
sw.style.backgroundColor = c.hex;
|
||||
}
|
||||
|
||||
if (idx === selectedColorIdx) sw.classList.add('active');
|
||||
sw.title = c.name;
|
||||
|
||||
sw.addEventListener('click', () => {
|
||||
selectedColorIdx = idx ?? 0;
|
||||
renderAllowedPalette();
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'btn-dark w-full';
|
||||
btn.textContent = 'Choose color';
|
||||
btn.addEventListener('click', () => {
|
||||
if (!window.openColorPicker) return;
|
||||
window.openColorPicker({
|
||||
title: 'Choose active color',
|
||||
subtitle: 'Applies to drawing and path tools',
|
||||
items: (FLAT_COLORS || []).map((c, idx) => ({ label: c.name || c.hex, metaText: c.family || '', idx })),
|
||||
onSelect: (item) => {
|
||||
if (!Number.isInteger(item.idx)) return;
|
||||
selectedColorIdx = item.idx;
|
||||
updateCurrentColorChip();
|
||||
persist();
|
||||
}
|
||||
});
|
||||
row.appendChild(sw);
|
||||
});
|
||||
paletteBox.appendChild(row);
|
||||
});
|
||||
paletteBox.appendChild(btn);
|
||||
}
|
||||
|
||||
function getUsedColors() {
|
||||
@ -1212,8 +1199,6 @@
|
||||
onSelect: (item) => {
|
||||
if (!Number.isInteger(item.idx)) return;
|
||||
selectedColorIdx = item.idx;
|
||||
renderAllowedPalette();
|
||||
renderUsedPalette();
|
||||
updateCurrentColorChip();
|
||||
persist();
|
||||
}
|
||||
@ -1238,58 +1223,8 @@
|
||||
|
||||
function renderUsedPalette() {
|
||||
if (!usedPaletteBox) return;
|
||||
usedPaletteBox.innerHTML = '';
|
||||
const used = getUsedColors();
|
||||
if (used.length === 0) {
|
||||
usedPaletteBox.innerHTML = '<div class="hint">No colors yet.</div>';
|
||||
usedPaletteBox.innerHTML = '<div class="hint">Palette opens in modal.</div>';
|
||||
if (replaceFromSel) replaceFromSel.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
const row = document.createElement('div');
|
||||
row.className = 'swatch-row';
|
||||
used.forEach(item => {
|
||||
const sw = document.createElement('button');
|
||||
sw.type = 'button';
|
||||
sw.className = 'swatch';
|
||||
const name = item.name || NAME_BY_HEX.get(item.hex) || item.hex;
|
||||
sw.setAttribute('aria-label', `${name} - Count: ${item.count}`);
|
||||
|
||||
if (item.image) {
|
||||
const meta = FLAT_COLORS[HEX_TO_FIRST_IDX.get(item.hex)] || {};
|
||||
sw.style.backgroundImage = `url("${item.image}")`;
|
||||
sw.style.backgroundSize = `${100 * SWATCH_TEXTURE_ZOOM}%`;
|
||||
sw.style.backgroundPosition = `${(meta.imageFocus?.x ?? 0.5) * 100}% ${(meta.imageFocus?.y ?? 0.5) * 100}%`;
|
||||
} else {
|
||||
sw.style.backgroundColor = item.hex;
|
||||
}
|
||||
if (normalizeHex(FLAT_COLORS[selectedColorIdx]?.hex) === item.hex) sw.classList.add('active');
|
||||
sw.title = `${name} — ${item.count}`;
|
||||
sw.addEventListener('click', () => {
|
||||
selectedColorIdx = HEX_TO_FIRST_IDX.get(item.hex) ?? 0;
|
||||
renderAllowedPalette();
|
||||
renderUsedPalette();
|
||||
});
|
||||
|
||||
const badge = document.createElement('div');
|
||||
badge.className = 'badge';
|
||||
badge.textContent = String(item.count);
|
||||
sw.appendChild(badge);
|
||||
row.appendChild(sw);
|
||||
});
|
||||
usedPaletteBox.appendChild(row);
|
||||
|
||||
// fill "replace from"
|
||||
if (replaceFromSel) {
|
||||
replaceFromSel.innerHTML = '';
|
||||
used.forEach(item => {
|
||||
const opt = document.createElement('option');
|
||||
const name = item.name || NAME_BY_HEX.get(item.hex) || item.hex;
|
||||
opt.value = item.hex;
|
||||
opt.textContent = `${name} (${item.count})`;
|
||||
replaceFromSel.appendChild(opt);
|
||||
});
|
||||
updateReplaceChips();
|
||||
}
|
||||
}
|
||||
|
||||
// ====== Balloon Ops & Data/Export ======
|
||||
|
||||
85
wall.js
85
wall.js
@ -623,36 +623,7 @@
|
||||
|
||||
function renderWallUsedPalette() {
|
||||
if (!wallUsedPaletteEl) return;
|
||||
const used = wallUsedColors();
|
||||
wallUsedPaletteEl.innerHTML = '';
|
||||
if (!used.length) {
|
||||
wallUsedPaletteEl.innerHTML = '<div class="text-xs text-gray-500">No colors yet.</div>';
|
||||
populateWallReplaceSelects();
|
||||
updateWallReplacePreview();
|
||||
return;
|
||||
}
|
||||
const row = document.createElement('div');
|
||||
row.className = 'swatch-row';
|
||||
used.forEach(item => {
|
||||
const sw = document.createElement('button');
|
||||
sw.type = 'button';
|
||||
sw.className = 'swatch';
|
||||
if (item.image) {
|
||||
sw.style.backgroundImage = `url("${item.image}")`;
|
||||
sw.style.backgroundSize = `${100 * 2.5}%`;
|
||||
} else {
|
||||
sw.style.backgroundColor = item.hex;
|
||||
}
|
||||
sw.title = `${item.name || item.hex} (${item.count})`;
|
||||
sw.addEventListener('click', () => {
|
||||
if (!Number.isInteger(item.idx)) return;
|
||||
setActiveColor(normalizeColorIdx(item.idx));
|
||||
renderWallPalette();
|
||||
renderWallUsedPalette();
|
||||
});
|
||||
row.appendChild(sw);
|
||||
});
|
||||
wallUsedPaletteEl.appendChild(row);
|
||||
wallUsedPaletteEl.innerHTML = '<div class="text-xs text-gray-500">Palette opens in modal.</div>';
|
||||
populateWallReplaceSelects();
|
||||
updateWallReplacePreview();
|
||||
}
|
||||
@ -1003,47 +974,25 @@
|
||||
if (!wallPaletteEl) return;
|
||||
wallPaletteEl.innerHTML = '';
|
||||
populateWallReplaceSelects();
|
||||
(window.PALETTE || []).forEach(group => {
|
||||
const title = document.createElement('div');
|
||||
title.className = 'family-title';
|
||||
title.textContent = group.family;
|
||||
wallPaletteEl.appendChild(title);
|
||||
|
||||
const row = document.createElement('div');
|
||||
row.className = 'swatch-row';
|
||||
(group.colors || []).forEach(c => {
|
||||
const normHex = (c.hex || '').toLowerCase();
|
||||
let idx = FLAT_COLORS.findIndex(fc => fc.name === c.name && fc.hex === c.hex && fc.family === group.family);
|
||||
if (idx < 0 && window.shared?.HEX_TO_FIRST_IDX?.has(normHex)) {
|
||||
idx = window.shared.HEX_TO_FIRST_IDX.get(normHex);
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'btn-dark w-full';
|
||||
btn.textContent = 'Choose color';
|
||||
btn.addEventListener('click', () => {
|
||||
if (!window.openColorPicker) return;
|
||||
window.openColorPicker({
|
||||
title: 'Choose active wall color',
|
||||
subtitle: 'Applies to wall fill tools',
|
||||
items: (FLAT_COLORS || []).map((c, idx) => ({ label: c.name || c.hex, metaText: c.family || '', idx })),
|
||||
onSelect: (item) => {
|
||||
if (!Number.isInteger(item.idx)) return;
|
||||
setActiveColor(item.idx);
|
||||
updateWallActiveChip(getActiveWallColorIdx());
|
||||
updateWallReplacePreview();
|
||||
}
|
||||
idx = normalizeColorIdx(idx);
|
||||
const sw = document.createElement('button');
|
||||
sw.type = 'button';
|
||||
sw.className = 'swatch';
|
||||
if (c.image) {
|
||||
const meta = FLAT_COLORS[idx] || {};
|
||||
sw.style.backgroundImage = `url("${c.image}")`;
|
||||
sw.style.backgroundSize = `${100 * 2.5}%`;
|
||||
sw.style.backgroundPosition = `${(meta.imageFocus?.x ?? 0.5) * 100}% ${(meta.imageFocus?.y ?? 0.5) * 100}%`;
|
||||
} else {
|
||||
sw.style.backgroundColor = c.hex;
|
||||
}
|
||||
if (idx === selectedColorIdx) sw.classList.add('active');
|
||||
sw.title = c.name;
|
||||
sw.addEventListener('click', () => {
|
||||
setActiveColor(idx);
|
||||
window.organic?.updateCurrentColorChip?.(selectedColorIdx);
|
||||
// Also update the global chip explicitly
|
||||
if (window.organic?.updateCurrentColorChip) {
|
||||
window.organic.updateCurrentColorChip(selectedColorIdx);
|
||||
}
|
||||
renderWallPalette();
|
||||
});
|
||||
row.appendChild(sw);
|
||||
});
|
||||
wallPaletteEl.appendChild(row);
|
||||
});
|
||||
wallPaletteEl.appendChild(btn);
|
||||
renderWallUsedPalette();
|
||||
updateWallActiveChip(getActiveWallColorIdx());
|
||||
updateWallReplacePreview();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user