76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import type GameLoop from '../game-loop/game-loop';
|
|
import { activeVibe, settings } from '../settings';
|
|
import { ErrorCode, RuntimeError } from '../utils/error-handler';
|
|
import { rgbColorToCss } from '../utils/rgb-color';
|
|
|
|
interface PaletteControlOptions {
|
|
getGame: () => GameLoop | null;
|
|
onChange: () => void;
|
|
onModeChange?: (isEraserActive: boolean) => void;
|
|
}
|
|
|
|
export class PaletteControl {
|
|
private readonly swatches = queryRequiredColorSwatches();
|
|
private isEraserActiveState = false;
|
|
|
|
public constructor(private readonly options: PaletteControlOptions) {
|
|
this.swatches.forEach((swatch, index) => {
|
|
swatch.addEventListener('click', () => {
|
|
settings.selectedColorIndex = index;
|
|
this.isEraserActiveState = false;
|
|
this.render();
|
|
this.options.onModeChange?.(false);
|
|
this.options.onChange();
|
|
});
|
|
});
|
|
}
|
|
|
|
public get isEraserActive(): boolean {
|
|
return this.isEraserActiveState;
|
|
}
|
|
|
|
public setEraserActive(active: boolean): void {
|
|
this.isEraserActiveState = active;
|
|
this.render();
|
|
this.options.onModeChange?.(active);
|
|
}
|
|
|
|
public render(): void {
|
|
this.swatches.forEach((swatch, index) => {
|
|
swatch.style.backgroundColor = rgbColorToCss(activeVibe.colors[index]);
|
|
const isActive = settings.selectedColorIndex === index && !this.isEraserActiveState;
|
|
swatch.classList.toggle('active', isActive);
|
|
swatch.setAttribute('aria-pressed', String(isActive));
|
|
});
|
|
this.options.getGame()?.setEraseMode(this.isEraserActiveState);
|
|
document.documentElement.style.setProperty(
|
|
'--garden-background',
|
|
rgbColorToCss(activeVibe.backgroundColor)
|
|
);
|
|
}
|
|
}
|
|
|
|
const queryRequiredColorSwatches = (): Array<HTMLButtonElement> => {
|
|
const selector = '.color-swatch';
|
|
const swatches = Array.from(document.querySelectorAll(selector));
|
|
const expectedCount = activeVibe.colors.length;
|
|
const hasExpectedSwatches =
|
|
swatches.length === expectedCount &&
|
|
swatches.every((swatch) => swatch instanceof HTMLButtonElement);
|
|
|
|
if (!hasExpectedSwatches) {
|
|
throw new RuntimeError(
|
|
ErrorCode.DOM_ELEMENT_MISSING,
|
|
`Expected ${expectedCount} color swatches.`,
|
|
{
|
|
details: {
|
|
actualCount: swatches.length,
|
|
expectedCount,
|
|
selector,
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
return swatches as Array<HTMLButtonElement>;
|
|
};
|