Replace row/col number inputs with graphical grid cell picker

Click a cell in the visual grid to select it. Cell images shown where
available. Selected cell highlighted with accent border.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 01:16:40 +00:00
parent 488fa7ff53
commit 64af0862f2
3 changed files with 74 additions and 19 deletions

View File

@@ -1625,8 +1625,9 @@ function open_inventory_dialog(entry = null, default_component_id = null, defaul
const new_comp_btn = qs(dlg, '#i-new-component');
const grid_row_div = qs(dlg, '#i-grid-row');
const grid_sel = qs(dlg, '#i-grid-select');
const row_num_input = qs(dlg, '#i-grid-row-num');
const col_num_input = qs(dlg, '#i-grid-col-num');
const grid_visual = qs(dlg, '#i-grid-visual');
let picker_row = null;
let picker_col = null;
title.textContent = entry ? 'Edit inventory entry' : 'Add inventory entry';
@@ -1659,8 +1660,44 @@ function open_inventory_dialog(entry = null, default_component_id = null, defaul
}))
);
if (effective_grid_cell?.grid_id) { grid_sel.value = effective_grid_cell.grid_id; }
row_num_input.value = effective_grid_cell?.grid_row != null ? effective_grid_cell.grid_row + 1 : 1;
col_num_input.value = effective_grid_cell?.grid_col != null ? effective_grid_cell.grid_col + 1 : 1;
picker_row = effective_grid_cell?.grid_row ?? null;
picker_col = effective_grid_cell?.grid_col ?? null;
function rebuild_grid_visual() {
const grid = all_grids.find(g => g.id === grid_sel.value);
if (!grid) { grid_visual.replaceChildren(); return; }
grid_visual.style.gridTemplateColumns = `repeat(${grid.cols}, 1fr)`;
const cells = [];
for (let r = 0; r < grid.rows; r++) {
for (let c = 0; c < grid.cols; c++) {
const cell = document.createElement('div');
cell.className = 'igv-cell';
if (r === picker_row && c === picker_col) cell.classList.add('igv-selected');
const filename = grid.cells?.[r]?.[c];
if (filename) {
const img = document.createElement('img');
img.src = `/img/${filename}`;
img.className = 'igv-img';
cell.appendChild(img);
}
cell.addEventListener('click', () => {
picker_row = r;
picker_col = c;
grid_visual.querySelectorAll('.igv-cell').forEach(el => el.classList.remove('igv-selected'));
cell.classList.add('igv-selected');
});
cells.push(cell);
}
}
grid_visual.replaceChildren(...cells);
}
rebuild_grid_visual();
const old_grid_handler = grid_sel._change_handler;
if (old_grid_handler) grid_sel.removeEventListener('change', old_grid_handler);
grid_sel._change_handler = () => { picker_row = null; picker_col = null; rebuild_grid_visual(); };
grid_sel.addEventListener('change', grid_sel._change_handler);
function update_ref_label() {
ref_label.textContent = ref_label_for_type(type_sel.value);
@@ -1700,8 +1737,8 @@ function open_inventory_dialog(entry = null, default_component_id = null, defaul
quantity: qty_input.value.trim(),
notes: notes_input.value.trim(),
grid_id: is_grid ? (grid_sel.value || null) : null,
grid_row: is_grid ? parseInt(row_num_input.value) - 1 : null,
grid_col: is_grid ? parseInt(col_num_input.value) - 1 : null,
grid_row: is_grid ? picker_row : null,
grid_col: is_grid ? picker_col : null,
};
if (entry) {
const result = await api.update_inventory(entry.id, body);