@@ -38,7 +38,7 @@ let selectedIds = new Set(); // persistent selection of frame ids (survives refr
3838let persistTimeout = null ;
3939const AUTO_PERSIST_DELAY_MS = 150 ; // 150ms unified delay
4040
41- async function loadConfig ( ) {
41+ async function loadConfig ( brightnessSlider , brightnessValue ) {
4242 try {
4343 const resp = await fetch ( '/config' ) ;
4444 if ( ! resp . ok ) return ;
@@ -113,80 +113,13 @@ function makeGrid(){
113113 const el = document . createElement ( 'div' ) ;
114114 el . className = 'cell' ;
115115 el . dataset . r = r ; el . dataset . c = c ;
116- // click opens a brightness slider for that cell
117- el . addEventListener ( 'click' , ( ev ) => { ev . stopPropagation ( ) ; cellClicked ( ev , el ) ; } ) ;
118116 gridEl . appendChild ( el ) ;
119117 cells . push ( el ) ;
120118 }
121119 }
122120}
123121
124- const sliderWrap = document . getElementById ( 'cell-slider' ) ;
125- const brightnessSlider = document . getElementById ( 'brightness-slider' ) ;
126- const brightnessValue = document . getElementById ( 'brightness-value' ) ;
127- let activeCell = null ;
128122
129- function cellClicked ( ev , el ) {
130- activeCell = el ;
131- // position slider near cursor if present; otherwise just keep selection
132- if ( sliderWrap && brightnessSlider ) {
133- try {
134- sliderWrap . style . left = ( ev . clientX + 8 ) + 'px' ;
135- sliderWrap . style . top = ( ev . clientY + 8 ) + 'px' ;
136- const current = clampBrightness ( el . dataset . b ? parseInt ( el . dataset . b ) : 0 ) ;
137- brightnessSlider . value = String ( current ) ;
138- if ( brightnessValue ) brightnessValue . textContent = String ( current ) ;
139- if ( sliderWrap ) { sliderWrap . style . display = 'flex' ; }
140- } catch ( err ) {
141- console . warn ( '[ui] failed to position slider' , err ) ;
142- }
143- } else {
144- // fallback: ensure visual state reflects dataset.b
145- const current = clampBrightness ( el . dataset . b ? parseInt ( el . dataset . b ) : 0 ) ;
146- if ( current > 0 ) el . classList . add ( 'on' ) ; else el . classList . remove ( 'on' ) ;
147- // user has toggled a cell visually without using the slider -> this counts as an edit
148- clearLoaded ( ) ;
149- }
150- }
151-
152- if ( brightnessSlider ) {
153- brightnessSlider . addEventListener ( 'input' , ( ) => {
154- if ( ! activeCell ) return ;
155- const v = clampBrightness ( parseInt ( brightnessSlider . value ) ) ;
156- brightnessSlider . value = String ( v ) ;
157- activeCell . dataset . b = String ( v ) ;
158- // visually mark as 'on' if v>0
159- if ( v > 0 ) activeCell . classList . add ( 'on' ) ; else activeCell . classList . remove ( 'on' ) ;
160- // update numeric display next to slider
161- if ( brightnessValue ) brightnessValue . textContent = String ( v ) ;
162- } ) ;
163-
164- brightnessSlider . addEventListener ( 'change' , ( ) => {
165- // commit change: send full 2D array rows of ints to backend
166- const committed = clampBrightness ( parseInt ( brightnessSlider . value ) ) ;
167- brightnessSlider . value = String ( committed ) ;
168- console . debug ( '[ui] brightness change commit for active cell, value=' , committed ) ;
169-
170- // Trigger unified persist (board + DB)
171- schedulePersist ( ) ;
172-
173- // hide slider
174- if ( sliderWrap ) sliderWrap . style . display = 'none' ;
175- activeCell = null ;
176- } ) ;
177- } else {
178- console . warn ( '[ui] brightness-slider element not found; per-cell slider disabled' ) ;
179- }
180-
181- loadConfig ( ) ;
182-
183- // Hide the slider when clicking anywhere outside the slider or the grid
184- document . addEventListener ( 'click' , ( e ) => {
185- if ( ! sliderWrap ) return ;
186- if ( sliderWrap . contains ( e . target ) ) return ;
187- if ( gridEl && gridEl . contains ( e . target ) ) return ;
188- sliderWrap . style . display = 'none' ;
189- } ) ;
190123
191124// Unified persist: save to DB and update board together
192125function schedulePersist ( ) {
@@ -981,13 +914,15 @@ if (invertNotNullBtn) {
981914 console . warn ( '[ui] invert-not-null button not found' ) ;
982915}
983916
984- /* Custom Select Dropdown */
985917document . addEventListener ( 'DOMContentLoaded' , ( ) => {
918+ let selectedTool = 'brush' ;
919+ gridEl . dataset . tool = selectedTool ;
920+
986921 const customSelect = document . querySelector ( '.custom-select' ) ;
987922 if ( customSelect ) {
988923 const trigger = customSelect . querySelector ( '.custom-select__trigger' ) ;
989924 const options = customSelect . querySelectorAll ( '.custom-option' ) ;
990- const triggerImage = trigger . querySelector ( 'img ' ) ;
925+ const triggerSvg = trigger . querySelector ( 'svg.tool-icon ' ) ;
991926
992927 trigger . addEventListener ( 'click' , ( ) => {
993928 customSelect . classList . toggle ( 'open' ) ;
@@ -996,13 +931,13 @@ document.addEventListener('DOMContentLoaded', () => {
996931 options . forEach ( option => {
997932 option . addEventListener ( 'click' , ( ) => {
998933 const value = option . getAttribute ( 'data-value' ) ;
999- const img = option . querySelector ( 'img ' ) ;
934+ const svg = option . querySelector ( 'svg.tool-icon ' ) ;
1000935
1001- triggerImage . src = img . src ;
1002- triggerImage . alt = img . alt ;
936+ triggerSvg . innerHTML = svg . innerHTML ;
1003937 customSelect . classList . remove ( 'open' ) ;
1004938
1005- // You can use the 'value' variable to handle tool changes
939+ selectedTool = value ;
940+ gridEl . dataset . tool = selectedTool ;
1006941 console . log ( 'Selected tool:' , value ) ;
1007942 } ) ;
1008943 } ) ;
@@ -1023,4 +958,45 @@ document.addEventListener('DOMContentLoaded', () => {
1023958 brightnessAlphaValue . textContent = brightnessAlphaSlider . value ;
1024959 } ) ;
1025960 }
961+
962+ loadConfig ( brightnessAlphaSlider , brightnessAlphaValue ) ;
963+
964+ let isDrawing = false ;
965+
966+ function draw ( e ) {
967+ if ( ! e . target . classList . contains ( 'cell' ) ) return ;
968+
969+ const cell = e . target ;
970+ if ( selectedTool === 'brush' ) {
971+ const brightness = brightnessAlphaSlider . value ;
972+ cell . dataset . b = brightness ;
973+ } else if ( selectedTool === 'eraser' ) {
974+ delete cell . dataset . b ;
975+ }
976+ }
977+
978+ gridEl . addEventListener ( 'mousedown' , ( e ) => {
979+ isDrawing = true ;
980+ draw ( e ) ;
981+ } ) ;
982+
983+ gridEl . addEventListener ( 'mousemove' , ( e ) => {
984+ if ( isDrawing ) {
985+ draw ( e ) ;
986+ }
987+ } ) ;
988+
989+ window . addEventListener ( 'mouseup' , ( ) => {
990+ if ( isDrawing ) {
991+ isDrawing = false ;
992+ schedulePersist ( ) ;
993+ }
994+ } ) ;
995+
996+ gridEl . addEventListener ( 'mouseleave' , ( ) => {
997+ if ( isDrawing ) {
998+ isDrawing = false ;
999+ schedulePersist ( ) ;
1000+ }
1001+ } ) ;
10261002} ) ;
0 commit comments