Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | import { BladeApi, BladeController, View } from '@tweakpane/core'; import { createBlade } from '@tweakpane/core'; import { ViewProps } from '@tweakpane/core'; import { colorToRgb, getBrightness } from '../core/utils/color-utils'; import { ColorValue } from '../types'; interface DrawStateBladeConfig { numStates: number; palette: Record<number, ColorValue>; drawState: number; onStateChange: (state: number) => void; } class DrawStateBladeView implements View { public readonly element: HTMLElement; private buttons: HTMLElement[] = []; constructor(config: DrawStateBladeConfig) { this.element = document.createElement('div'); this.element.style.display = 'flex'; this.element.style.gap = '4px'; this.element.style.flexWrap = 'wrap'; this.element.style.padding = '4px 0'; this.buildButtons(config); } private updateSelection(selectedState: number, numStates: number) { this.buttons.forEach((button, index) => { if (index < numStates) { if (index === selectedState) { button.style.border = '3px solid #ffff00'; button.style.boxShadow = '0 0 5px rgba(255, 255, 0, 0.8)'; } else { button.style.border = '2px solid #666'; button.style.boxShadow = 'none'; } } }); } public update(config: DrawStateBladeConfig) { this.buildButtons(config); } private buildButtons(config: DrawStateBladeConfig) { this.buttons.forEach(btn => btn.remove()); this.buttons = []; for (let i = 0; i < config.numStates; i++) { const button = document.createElement('button'); button.style.width = '24px'; button.style.height = '24px'; button.style.border = '2px solid #666'; button.style.borderRadius = '4px'; button.style.cursor = 'pointer'; button.style.padding = '0'; button.style.margin = '0'; button.title = `State ${i}`; const colorValue = config.palette[i] ?? '#000000'; const colorStr = this.colorToCss(colorValue); button.style.backgroundColor = colorStr; const brightness = getBrightness(colorValue); button.style.color = brightness > 128 ? '#000000' : '#ffffff'; button.addEventListener('click', () => { config.onStateChange(i); this.updateSelection(i, config.numStates); }); this.element.appendChild(button); this.buttons.push(button); } this.updateSelection(config.drawState, config.numStates); } private colorToCss(color: ColorValue): string { if (typeof color === 'string') return color; const rgb = colorToRgb(color); const r = rgb.r.toString(16).padStart(2, '0'); const g = rgb.g.toString(16).padStart(2, '0'); const b = rgb.b.toString(16).padStart(2, '0'); return `#${r}${g}${b}`; } } class DrawStateBladeController extends BladeController<DrawStateBladeView> { constructor(config: DrawStateBladeConfig) { super({ blade: createBlade(), view: new DrawStateBladeView(config), viewProps: ViewProps.create(), }); } } export class DrawStateBladeApi extends BladeApi<DrawStateBladeController> { constructor(controller: DrawStateBladeController) { super(controller); } public update(config: DrawStateBladeConfig) { this.controller.view.update(config); } } export function createDrawStateBlade(config: DrawStateBladeConfig): DrawStateBladeApi { const controller = new DrawStateBladeController(config); return new DrawStateBladeApi(controller); } |