Skip to content

Commit 5b0a8d7

Browse files
committed
Update matrix UI
1 parent 0e3422e commit 5b0a8d7

File tree

2 files changed

+58
-75
lines changed

2 files changed

+58
-75
lines changed

examples/led-matrix-painter/assets/app.js

Lines changed: 50 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ let selectedIds = new Set(); // persistent selection of frame ids (survives refr
3838
let persistTimeout = null;
3939
const 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
192125
function schedulePersist(){
@@ -981,13 +914,15 @@ if (invertNotNullBtn) {
981914
console.warn('[ui] invert-not-null button not found');
982915
}
983916

984-
/* Custom Select Dropdown */
985917
document.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
});

examples/led-matrix-painter/assets/style.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ input:checked + .slider:before {
374374
display: flex;
375375
align-items: center;
376376
justify-content: center;
377-
cursor: pointer;
378377
}
379378
/* brightness visual using background color intensity */
380379
.cell[data-b="0"] { background: #3CE2FF33; }
@@ -658,3 +657,11 @@ input {
658657
background: #008184 !important; /* Green background */
659658
border-radius: 30px;
660659
}
660+
661+
.grid[data-tool='brush'] {
662+
cursor: url('img/mouse-brush.svg') 8 8, auto;
663+
}
664+
665+
.grid[data-tool='eraser'] {
666+
cursor: url('img/mouse-eraser.svg') 8 8, auto;
667+
}

0 commit comments

Comments
 (0)