Improve number topper outlines and allow textured colors
This commit is contained in:
parent
8bb46389f3
commit
0f325ca1d8
194
classic.js
194
classic.js
@ -73,6 +73,11 @@
|
||||
}
|
||||
return { color: '#0f172a', shadow: 'none' };
|
||||
}
|
||||
function outlineColorFor(colorInfo) {
|
||||
// Mirrors the topper chip text color choice for consistent contrast.
|
||||
const chipStyle = textStyleForColor(colorInfo || { hex: '#ffffff' });
|
||||
return chipStyle.color || '#0f172a';
|
||||
}
|
||||
|
||||
// -------- persistent color selection (now supports image textures) ----------
|
||||
const PALETTE_KEY = 'classic:colors:v2';
|
||||
@ -82,16 +87,16 @@
|
||||
const MANUAL_OVERRIDES_KEY = 'classic:manualOverrides:v1';
|
||||
const MANUAL_EXPANDED_KEY = 'classic:manualExpanded:v1';
|
||||
const NUMBER_IMAGE_MAP = {
|
||||
'0': 'output_webp/0.svg',
|
||||
'1': 'output_webp/1.svg',
|
||||
'2': 'output_webp/2.svg',
|
||||
'3': 'output_webp/3.svg',
|
||||
'4': 'output_webp/4.svg',
|
||||
'5': 'output_webp/5.svg',
|
||||
'6': 'output_webp/6.svg',
|
||||
'7': 'output_webp/7.svg',
|
||||
'8': 'output_webp/8.svg',
|
||||
'9': 'output_webp/9.svg'
|
||||
'0': 'output_webp/0.webp',
|
||||
'1': 'output_webp/1.webp',
|
||||
'2': 'output_webp/2.webp',
|
||||
'3': 'output_webp/3.webp',
|
||||
'4': 'output_webp/4.webp',
|
||||
'5': 'output_webp/5.webp',
|
||||
'6': 'output_webp/6.webp',
|
||||
'7': 'output_webp/7.webp',
|
||||
'8': 'output_webp/8.webp',
|
||||
'9': 'output_webp/9.webp'
|
||||
};
|
||||
|
||||
const MAX_SLOTS = 20;
|
||||
@ -102,6 +107,14 @@
|
||||
{ hex: '#fcd34d', image: null }
|
||||
];
|
||||
const defaultTopper = () => ({ hex: '#E32636', image: 'images/chrome-gold.webp' }); // Classic gold
|
||||
const numberSpriteSet = new Set(Object.values(NUMBER_IMAGE_MAP));
|
||||
const sanitizeTopperColor = (colorObj = {}) => {
|
||||
const base = defaultTopper();
|
||||
const hex = normHex(colorObj.hex || base.hex);
|
||||
const img = colorObj.image || null;
|
||||
const image = (img && !numberSpriteSet.has(img)) ? img : null;
|
||||
return { hex, image };
|
||||
};
|
||||
|
||||
function getClassicColors() {
|
||||
let arr = defaultColors();
|
||||
@ -134,12 +147,13 @@
|
||||
function getTopperColor() {
|
||||
try {
|
||||
const saved = JSON.parse(localStorage.getItem(TOPPER_COLOR_KEY));
|
||||
return (saved && saved.hex) ? saved : defaultTopper();
|
||||
} catch { return defaultTopper(); }
|
||||
if (saved && saved.hex) return sanitizeTopperColor(saved);
|
||||
} catch {}
|
||||
return sanitizeTopperColor(defaultTopper());
|
||||
}
|
||||
|
||||
function setTopperColor(colorObj) {
|
||||
const clean = { hex: normHex(colorObj.hex), image: colorObj.image || null };
|
||||
const clean = sanitizeTopperColor(colorObj);
|
||||
try { localStorage.setItem(TOPPER_COLOR_KEY, JSON.stringify(clean)); } catch {}
|
||||
}
|
||||
function loadManualMode() {
|
||||
@ -373,19 +387,12 @@
|
||||
if (base.image) {
|
||||
const w = base.width || 1, h = base.height || 1;
|
||||
if (isNumTopper) {
|
||||
// Use the SVG alpha as a mask and fill with the selected topper color.
|
||||
const maskId = `mask-${id}`;
|
||||
kids.push(svg('mask', { id: maskId, maskUnits: 'userSpaceOnUse', maskContentUnits: 'userSpaceOnUse', 'mask-type': 'alpha' }, [
|
||||
svg('image', { href: base.image, x: -w/2, y: -h/2, width: w, height: h, preserveAspectRatio: base.preserveAspectRatio || 'xMidYMid meet', style: 'pointer-events:none' })
|
||||
]));
|
||||
kids.push(svg('rect', {
|
||||
x: -w/2, y: -h/2, width: w, height: h,
|
||||
fill: model.topperColor?.hex || '#ffffff',
|
||||
opacity: 1,
|
||||
mask: `url(#${maskId})`,
|
||||
style: 'pointer-events:none'
|
||||
}));
|
||||
// Overlay the original SVG lightly to keep stroke/detail without overpowering the fill.
|
||||
const maskId = base.maskId || 'classic-num-mask';
|
||||
const fillVal = (colorInfo && colorInfo.image)
|
||||
? 'url(#classic-pattern-topper)'
|
||||
: (colorInfo?.hex || '#ffffff');
|
||||
const lum = luminance(colorInfo?.hex || colorInfo?.colour || '#ffffff');
|
||||
const outlineFilterId = lum >= 0.55 ? 'classic-num-outline-dark' : 'classic-num-outline-light';
|
||||
kids.push(svg('image', {
|
||||
href: base.image,
|
||||
x: -w/2,
|
||||
@ -393,7 +400,18 @@
|
||||
width: w,
|
||||
height: h,
|
||||
preserveAspectRatio: base.preserveAspectRatio || 'xMidYMid meet',
|
||||
style: 'pointer-events:none;mix-blend-mode:multiply;opacity:0.4'
|
||||
style: 'pointer-events:none',
|
||||
filter: `url(#${outlineFilterId})`,
|
||||
mask: `url(#${maskId})`
|
||||
}));
|
||||
kids.push(svg('rect', {
|
||||
x: -w/2,
|
||||
y: -h/2,
|
||||
width: w,
|
||||
height: h,
|
||||
fill: fillVal,
|
||||
mask: `url(#${maskId})`,
|
||||
style: 'pointer-events:none'
|
||||
}));
|
||||
} else {
|
||||
kids.push(svg('image', { href: base.image, x: -w/2, y: -h/2, width: w, height: h, preserveAspectRatio: base.preserveAspectRatio || 'xMidYMid meet', style: 'pointer-events:none' }));
|
||||
@ -409,7 +427,7 @@
|
||||
}
|
||||
|
||||
const allowShine = base.allowShine !== false;
|
||||
const applyShine = !wireframe && model.shineEnabled && (!cell.isTopper || allowShine);
|
||||
const applyShine = !wireframe && model.shineEnabled && (!cell.isTopper || (allowShine && !isNumTopper));
|
||||
if (applyShine) {
|
||||
const shine = classicShineStyle(colorInfo);
|
||||
const shineAttrs = {
|
||||
@ -738,8 +756,11 @@ function distinctPaletteSlots(palette) {
|
||||
const vb = [ minX, minY, vbW, vbH ].join(' ');
|
||||
|
||||
const patternsDefs = [];
|
||||
const maskDefs = [];
|
||||
const SVG_PATTERN_ZOOM = 2.5;
|
||||
const offset = (1 - SVG_PATTERN_ZOOM) / 2;
|
||||
const OUTLINE_DARK = '#0f172a'; // matches chip text for light colors
|
||||
const OUTLINE_LIGHT = '#f8fafc'; // matches chip text for dark colors
|
||||
|
||||
Object.entries(model.palette).forEach(([slot, colorInfo]) => {
|
||||
if (colorInfo.image) {
|
||||
@ -758,7 +779,50 @@ function distinctPaletteSlots(palette) {
|
||||
[ svg('image', { href: model.topperColor.image, x: offset, y: offset, width: SVG_PATTERN_ZOOM, height: SVG_PATTERN_ZOOM, preserveAspectRatio: 'xMidYMid slice' }) ]
|
||||
));
|
||||
}
|
||||
const svgDefs = svg('defs', {}, patternsDefs);
|
||||
Object.entries(numberTopperShapes).forEach(([key, shape]) => {
|
||||
const base = shape.base || {};
|
||||
if (!base.image) return;
|
||||
const w = base.width || 1, h = base.height || 1;
|
||||
const maskId = base.maskId || `classic-num-mask-${key.replace('topper-num-', '')}`;
|
||||
maskDefs.push(svg('mask', { id: maskId, maskUnits: 'userSpaceOnUse', x: -w/2, y: -h/2, width: w, height: h }, [
|
||||
svg('image', { href: base.image, x: -w/2, y: -h/2, width: w, height: h, preserveAspectRatio: base.preserveAspectRatio || 'xMidYMid meet' })
|
||||
]));
|
||||
});
|
||||
const svgDefs = svg('defs', {}, [
|
||||
// Tint: use source alpha to clip topper color, then reapply ink.
|
||||
svg('filter', { id: 'classic-num-tint', 'color-interpolation-filters': 'sRGB', x: '-10%', y: '-10%', width: '120%', height: '120%' }, [
|
||||
svg('feColorMatrix', { in: 'SourceGraphic', type: 'matrix', values: '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0', result: 'alpha' }),
|
||||
svg('feFlood', { 'flood-color': model.topperColor?.hex || '#ffffff', result: 'tint' }),
|
||||
svg('feComposite', { in: 'tint', in2: 'alpha', operator: 'in', result: 'fill' }),
|
||||
svg('feComposite', { in: 'SourceGraphic', in2: 'alpha', operator: 'in', result: 'ink' }),
|
||||
svg('feMerge', {}, [
|
||||
svg('feMergeNode', { in: 'fill' }),
|
||||
svg('feMergeNode', { in: 'ink' })
|
||||
])
|
||||
]),
|
||||
svg('filter', { id: 'classic-num-outline-dark', 'color-interpolation-filters': 'sRGB', x: '-22%', y: '-22%', width: '144%', height: '144%' }, [
|
||||
svg('feMorphology', { in: 'SourceAlpha', operator: 'dilate', radius: 3.1, result: 'spread' }),
|
||||
svg('feComposite', { in: 'spread', in2: 'SourceAlpha', operator: 'out', result: 'stroke' }),
|
||||
svg('feFlood', { 'flood-color': OUTLINE_DARK, 'flood-opacity': 1, result: 'strokeColor' }),
|
||||
svg('feComposite', { in: 'strokeColor', in2: 'stroke', operator: 'in', result: 'coloredStroke' }),
|
||||
svg('feMerge', {}, [
|
||||
svg('feMergeNode', { in: 'coloredStroke' }),
|
||||
svg('feMergeNode', { in: 'SourceGraphic' })
|
||||
])
|
||||
]),
|
||||
svg('filter', { id: 'classic-num-outline-light', 'color-interpolation-filters': 'sRGB', x: '-22%', y: '-22%', width: '144%', height: '144%' }, [
|
||||
svg('feMorphology', { in: 'SourceAlpha', operator: 'dilate', radius: 3.1, result: 'spread' }),
|
||||
svg('feComposite', { in: 'spread', in2: 'SourceAlpha', operator: 'out', result: 'stroke' }),
|
||||
svg('feFlood', { 'flood-color': OUTLINE_LIGHT, 'flood-opacity': 1, result: 'strokeColor' }),
|
||||
svg('feComposite', { in: 'strokeColor', in2: 'stroke', operator: 'in', result: 'coloredStroke' }),
|
||||
svg('feMerge', {}, [
|
||||
svg('feMergeNode', { in: 'coloredStroke' }),
|
||||
svg('feMergeNode', { in: 'SourceGraphic' })
|
||||
])
|
||||
]),
|
||||
...maskDefs,
|
||||
...patternsDefs
|
||||
]);
|
||||
|
||||
const mainGroup = svg('g', null, kids);
|
||||
const zoomPercent = classicZoom * 100;
|
||||
@ -855,34 +919,47 @@ function distinctPaletteSlots(palette) {
|
||||
}
|
||||
|
||||
function buildNumberTopperShapes() {
|
||||
const r = 1.0;
|
||||
const baseTransform = 'scale(0.58)';
|
||||
const fallbackPaths = {
|
||||
'0': { d: 'M 0 -0.7 C 0.38 -0.7 0.62 -0.42 0.62 0 C 0.62 0.42 0.38 0.7 0 0.7 C -0.38 0.7 -0.62 0.42 -0.62 0 C -0.62 -0.42 -0.38 -0.7 0 -0.7 Z M 0 -0.4 C -0.2 -0.4 -0.34 -0.22 -0.34 0 C -0.34 0.24 -0.2 0.42 0 0.42 C 0.2 0.42 0.34 0.24 0.34 0 C 0.34 -0.22 0.2 -0.4 0 -0.4 Z', fillRule: 'evenodd' },
|
||||
'1': { d: 'M -0.12 -0.55 Q 0.1 -0.72 0.28 -0.6 Q 0.36 -0.52 0.34 -0.42 L 0.34 0.65 Q 0.34 0.82 0 0.82 Q -0.34 0.82 -0.34 0.65 L -0.34 -0.18 Q -0.34 -0.32 -0.46 -0.32 Q -0.6 -0.32 -0.62 -0.45 Q -0.64 -0.58 -0.52 -0.65 Z' },
|
||||
'2': { d: 'M -0.55 -0.25 Q -0.55 -0.7 -0.18 -0.9 Q 0.1 -1.05 0.48 -0.98 Q 0.86 -0.9 1 -0.55 Q 1.12 -0.25 0.92 0.06 Q 0.78 0.28 0.36 0.5 Q 0.02 0.68 -0.2 0.88 Q -0.36 1.04 -0.32 1.12 Q -0.28 1.2 -0.12 1.2 L 0.78 1.2 Q 0.98 1.2 0.98 0.94 Q 0.98 0.7 0.78 0.7 L 0.14 0.7 Q 0.02 0.7 0.02 0.6 Q 0.02 0.52 0.24 0.38 Q 0.76 0.08 0.96 -0.22 Q 1.2 -0.58 1 -0.98 Q 0.82 -1.36 0.38 -1.48 Q -0.2 -1.64 -0.7 -1.34 Q -1.1 -1.1 -1.12 -0.6 Q -1.14 -0.38 -0.96 -0.3 Q -0.8 -0.24 -0.68 -0.32 Q -0.55 -0.42 -0.55 -0.25 Z', fillRule: 'nonzero' },
|
||||
'3': { d: 'M -0.42 -0.88 Q -0.1 -1.08 0.26 -1.02 Q 0.7 -0.94 0.94 -0.62 Q 1.16 -0.32 1 -0.02 Q 0.86 0.24 0.58 0.36 Q 0.88 0.5 1 0.76 Q 1.16 1.12 0.88 1.38 Q 0.6 1.64 0.08 1.64 Q -0.3 1.64 -0.62 1.44 Q -0.88 1.26 -0.78 0.98 Q -0.7 0.72 -0.44 0.82 Q -0.06 0.96 0.26 0.88 Q 0.42 0.82 0.42 0.62 Q 0.42 0.38 0.1 0.36 L -0.24 0.34 Q -0.44 0.32 -0.44 0.12 Q -0.44 -0.08 -0.24 -0.12 L 0.08 -0.2 Q 0.32 -0.24 0.4 -0.42 Q 0.48 -0.62 0.26 -0.76 Q -0.02 -0.94 -0.4 -0.78 Q -0.62 -0.7 -0.74 -0.9 Q -0.86 -1.1 -0.68 -1.26 Q -0.58 -1.36 -0.42 -0.88 Z' },
|
||||
'4': { d: 'M 0.42 -0.94 Q 0.64 -0.94 0.7 -0.74 L 0.7 -0.1 L 0.92 -0.1 Q 1.12 -0.08 1.14 0.16 Q 1.16 0.38 0.92 0.46 L 0.7 0.54 L 0.7 0.98 Q 0.7 1.14 0.5 1.18 Q 0.3 1.22 0.18 1.08 L -0.34 0.48 L -0.6 0.48 Q -0.82 0.48 -0.86 0.28 Q -0.88 0.08 -0.7 -0.02 L -0.36 -0.18 L -0.36 -0.76 Q -0.36 -0.96 -0.14 -0.96 Q 0.08 -0.96 0.12 -0.76 L 0.12 -0.36 L 0.08 -0.36 Q 0.28 -0.62 0.42 -0.94 Z' },
|
||||
'5': { d: 'M 0.92 -0.94 Q 0.92 -1.16 0.72 -1.16 L -0.58 -1.16 Q -0.86 -1.16 -0.86 -0.86 Q -0.86 -0.56 -0.58 -0.56 L -0.2 -0.56 Q -0.02 -0.56 0.14 -0.5 Q 0.44 -0.38 0.44 -0.06 Q 0.44 0.18 0.22 0.36 Q 0.06 0.5 -0.16 0.5 L -0.52 0.5 Q -0.8 0.5 -0.8 0.8 Q -0.8 1.12 -0.52 1.12 L 0.24 1.12 Q 0.7 1.12 0.96 0.84 Q 1.2 0.58 1.12 0.24 Q 1.04 -0.02 0.82 -0.16 Q 0.96 -0.38 0.98 -0.62 Q 0.98 -0.86 0.92 -0.94 Z' },
|
||||
'6': { d: 'M 0.94 -0.6 Q 0.88 -0.98 0.52 -1.16 Q 0.06 -1.4 -0.44 -1.1 Q -0.94 -0.82 -1.02 -0.22 Q -1.12 0.4 -0.8 0.96 Q -0.48 1.48 0.14 1.48 Q 0.52 1.48 0.82 1.24 Q 1.12 1.02 1.12 0.66 Q 1.12 0.32 0.86 0.1 Q 0.66 -0.08 0.42 -0.08 Q 0.08 -0.08 -0.12 0.18 Q -0.26 0.36 -0.28 0.6 Q -0.5 0.26 -0.48 -0.18 Q -0.46 -0.66 -0.12 -0.86 Q 0.08 -0.98 0.32 -0.9 Q 0.56 -0.82 0.62 -0.58 Q 0.68 -0.34 0.92 -0.32 Q 1.02 -0.32 0.94 -0.6 Z M -0.06 0.6 C 0.12 0.6 0.26 0.44 0.26 0.26 C 0.26 0.08 0.12 -0.08 -0.06 -0.08 C -0.24 -0.08 -0.38 0.08 -0.38 0.26 C -0.38 0.44 -0.24 0.6 -0.06 0.6 Z', fillRule: 'evenodd' },
|
||||
'7': { d: 'M -0.74 -0.96 Q -0.94 -0.96 -0.94 -0.72 Q -0.94 -0.5 -0.74 -0.5 L 0.2 -0.5 Q 0.46 -0.5 0.52 -0.3 Q 0.58 -0.1 0.42 0.1 L -0.28 1.02 Q -0.42 1.2 -0.22 1.32 Q 0 1.44 0.18 1.28 L 0.98 0.2 Q 1.22 -0.12 1.1 -0.46 Q 0.98 -0.84 0.58 -0.96 Q 0.32 -1.04 0 -1.04 Z' },
|
||||
'8': { d: 'M 0 -1 C 0.44 -1 0.78 -0.72 0.78 -0.34 C 0.78 0.02 0.46 0.28 0.18 0.36 C 0.46 0.44 0.8 0.66 0.8 1.02 C 0.8 1.44 0.44 1.72 0 1.72 C -0.44 1.72 -0.8 1.44 -0.8 1.02 C -0.8 0.66 -0.48 0.44 -0.2 0.36 C -0.48 0.28 -0.8 0.02 -0.8 -0.34 C -0.8 -0.72 -0.44 -1 -0.02 -1 Z M 0 0.48 C 0.2 0.48 0.34 0.64 0.34 0.84 C 0.34 1.04 0.2 1.18 0 1.18 C -0.2 1.18 -0.34 1.04 -0.34 0.84 C -0.34 0.64 -0.2 0.48 0 0.48 Z M 0 -0.46 C 0.18 -0.46 0.3 -0.64 0.3 -0.8 C 0.3 -0.98 0.18 -1.12 0 -1.12 C -0.18 -1.12 -0.3 -0.98 -0.3 -0.8 C -0.3 -0.64 -0.18 -0.46 0 -0.46 Z', fillRule: 'evenodd' },
|
||||
'9': { d: 'M 0 -0.72 C 0.42 -0.72 0.7 -0.44 0.7 -0.08 C 0.7 0.2 0.56 0.46 0.32 0.6 C 0.12 0.72 0.1 0.84 0.1 1.06 C 0.1 1.24 -0.16 1.32 -0.28 1.18 L -0.64 0.72 C -0.92 0.38 -1.08 -0.1 -0.96 -0.54 C -0.82 -1.02 -0.46 -1.26 -0.08 -1.26 C 0.14 -1.26 0.32 -1.18 0.48 -1.04 C 0.62 -0.9 0.62 -0.74 0.5 -0.66 C 0.38 -0.58 0.26 -0.66 0.08 -0.74 C -0.14 -0.84 -0.34 -0.68 -0.42 -0.44 C -0.5 -0.24 -0.46 0.04 -0.32 0.26 C -0.16 0.5 0.14 0.46 0.26 0.26 C 0.38 0.06 0.3 -0.1 0.14 -0.18 C 0.02 -0.24 0 -0.42 0.12 -0.52 C 0.2 -0.58 0.46 -0.62 0.64 -0.42 C 0.82 -0.22 0.86 0.02 0.76 0.24 C 0.6 0.58 0.18 0.76 -0.16 0.7 C -0.36 0.66 -0.54 0.56 -0.68 0.42 C -0.64 0.82 -0.44 1.22 -0.14 1.46 C 0.16 1.7 0.54 1.72 0.86 1.52 C 1.26 1.26 1.42 0.84 1.36 0.38 C 1.26 -0.3 0.72 -0.72 0 -0.72 Z', fillRule: 'evenodd' }
|
||||
// Reuse the exported SVG glyphs for numbers and recolor them via an alpha mask.
|
||||
// ViewBox sizes vary a lot, so we normalize the aspect ratio with a shared base height.
|
||||
const viewBoxes = {
|
||||
'0': { w: 28.874041, h: 38.883382 },
|
||||
'1': { w: 20.387968, h: 39.577327 },
|
||||
'2': { w: 27.866452, h: 39.567209 },
|
||||
'3': { w: 27.528916, h: 39.153201 },
|
||||
'4': { w: 39.999867, h: 39.999867 },
|
||||
'5': { w: 39.999867, h: 39.999867 },
|
||||
'6': { w: 27.952782, h: 39.269062 },
|
||||
'7': { w: 39.999867, h: 39.999867 },
|
||||
'8': { w: 39.999867, h: 39.999867 },
|
||||
'9': { w: 39.999867, h: 39.999867 }
|
||||
};
|
||||
|
||||
const shapes = {};
|
||||
const topperSize = 9.5; // ≈34" foil height when base balloons are ~11"
|
||||
Object.keys({ ...fallbackPaths, ...NUMBER_IMAGE_MAP }).forEach(num => {
|
||||
const fallback = fallbackPaths[num];
|
||||
const img = NUMBER_IMAGE_MAP[num];
|
||||
const topperSize = 8.2; // closer to round topper scale
|
||||
const baseHeight = 1.05;
|
||||
|
||||
Object.entries(NUMBER_IMAGE_MAP).forEach(([num, href]) => {
|
||||
const vb = viewBoxes[num] || { w: 40, h: 40 };
|
||||
const aspect = vb.w / Math.max(1, vb.h);
|
||||
const height = baseHeight;
|
||||
const width = height * aspect;
|
||||
const radius = Math.max(width, height) / 2;
|
||||
const maskId = `classic-num-mask-${num}`;
|
||||
|
||||
shapes[`topper-num-${num}`] = {
|
||||
// Prefer provided SVG image for numbers so we keep the photo look.
|
||||
base: img
|
||||
? { type: 'image', image: img, width: 1, height: 1, radius: 0.9, allowShine: false, preserveAspectRatio: 'xMidYMid meet', transform: 'scale(0.9)' }
|
||||
: { type: 'path', paths: [{ d: fallback.d, fillRule: fallback.fillRule || 'nonzero' }], radius: r, allowShine: true, transform: baseTransform },
|
||||
base: {
|
||||
image: href,
|
||||
width,
|
||||
height,
|
||||
preserveAspectRatio: 'xMidYMid meet',
|
||||
maskId,
|
||||
radius,
|
||||
allowShine: false // keep number toppers matte; shine causes halo
|
||||
},
|
||||
size: topperSize
|
||||
};
|
||||
});
|
||||
|
||||
return shapes;
|
||||
}
|
||||
|
||||
@ -1373,14 +1450,7 @@ function distinctPaletteSlots(palette) {
|
||||
const meta = item.meta || {};
|
||||
const selectedColor = { hex: meta.hex || item.hex, image: meta.image || null };
|
||||
if (activeTarget === 'T') {
|
||||
const currentTypeLocal = document.querySelector('.topper-type-btn[aria-pressed="true"]')?.dataset.type || 'round';
|
||||
if (currentTypeLocal.startsWith('num-')) {
|
||||
const num = currentTypeLocal.split('-')[1];
|
||||
const imgPath = num ? NUMBER_IMAGE_MAP[num] : null;
|
||||
setTopperColor({ hex: selectedColor.hex, image: imgPath || selectedColor.image || null });
|
||||
} else {
|
||||
setTopperColor(selectedColor);
|
||||
}
|
||||
} else if (isManual()) {
|
||||
manualActiveColorGlobal = window.shared?.setActiveColor?.(selectedColor) || selectedColor;
|
||||
} else {
|
||||
@ -1593,18 +1663,16 @@ function distinctPaletteSlots(palette) {
|
||||
};
|
||||
function ensureNumberTopperImage(type) {
|
||||
if (!type || !type.startsWith('num-')) return;
|
||||
const num = type.split('-')[1];
|
||||
const imgPath = num ? NUMBER_IMAGE_MAP[num] : null;
|
||||
if (!imgPath) return;
|
||||
const cur = getTopperColor();
|
||||
if (cur?.image === imgPath) return;
|
||||
setTopperColor({ hex: cur?.hex || '#ffffff', image: imgPath });
|
||||
if (cur?.image && numberSpriteSet.has(cur.image)) {
|
||||
setTopperColor({ hex: cur?.hex || '#ffffff', image: null });
|
||||
refreshClassicPaletteUi?.();
|
||||
}
|
||||
}
|
||||
function resetNonNumberTopperColor(type) {
|
||||
if (type && type.startsWith('num-')) return;
|
||||
const fallback = getTopperColor();
|
||||
if (fallback?.image && Object.values(NUMBER_IMAGE_MAP).includes(fallback.image)) {
|
||||
if (fallback?.image && numberSpriteSet.has(fallback.image)) {
|
||||
setTopperColor({ hex: fallback.hex || '#ffffff', image: null });
|
||||
refreshClassicPaletteUi?.();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user