diff --git a/public/app.mjs b/public/app.mjs index 08b8365..5c87099 100644 --- a/public/app.mjs +++ b/public/app.mjs @@ -2359,6 +2359,8 @@ function open_bin_editor(bin) { if (!dlg) return; bin_editor_bin_id = bin.id; + bin_editor_instance = null; // canvas not loaded until needed + document.getElementById('bin-editor-name').value = bin.name; // Populate type selector @@ -2385,28 +2387,68 @@ function open_bin_editor(bin) { type_sel.addEventListener('change', sync_dims_row); sync_dims_row(); - // Tabs - let active_tab = 'corners'; + // Image preview (default view) + const view_image = document.getElementById('bin-editor-view-image'); + const view_corners = document.getElementById('bin-editor-view-corners'); + const preview_img = document.getElementById('bin-editor-preview'); + const no_image_el = document.getElementById('bin-editor-no-image'); + + function show_image_view() { + view_image.hidden = false; + view_corners.hidden = true; + } + + function show_corners_view() { + view_image.hidden = true; + view_corners.hidden = false; + // Lazy-load canvas the first time + if (!bin_editor_instance) { + const canvas = document.getElementById('bin-editor-canvas'); + bin_editor_instance = new Grid_Setup(canvas); + bin_editor_instance.set_rows(1); + bin_editor_instance.set_cols(1); + bin_editor_instance.load_image(`/img/${bin.source_id}`).then(() => { + if (bin.corners) { + bin_editor_instance.set_corners(bin.corners); + } + }); + } + } + + if (bin.image_filename) { + preview_img.src = `/img/${bin.image_filename}`; + preview_img.hidden = false; + no_image_el.hidden = true; + } else { + preview_img.hidden = true; + no_image_el.hidden = false; + } + + document.getElementById('bin-editor-go-corners').onclick = () => { + dlg.showModal(); // already open; ensures layout is stable before canvas sizes + show_corners_view(); + }; + document.getElementById('bin-editor-go-back').onclick = show_image_view; + + show_image_view(); + + // Tabs: Fields | Contents const tab_panels = { - corners: document.getElementById('bin-editor-tab-corners'), fields: document.getElementById('bin-editor-tab-fields'), contents: document.getElementById('bin-editor-tab-contents'), }; qs(dlg, '#bin-editor-tabs').onclick = (e) => { const tab = e.target.dataset.tab; if (!tab) return; - active_tab = tab; qs(dlg, '#bin-editor-tabs').querySelectorAll('.tab-btn').forEach(btn => { btn.classList.toggle('active', btn.dataset.tab === tab); }); for (const [name, el] of Object.entries(tab_panels)) { el.hidden = name !== tab; } - const save_btn = document.getElementById('bin-editor-save'); - save_btn.textContent = active_tab === 'corners' ? 'Save & process' : 'Save'; }; - // Fields tab + // Fields bin_editor_get_fields = build_field_editor( document.getElementById('bin-field-rows'), document.getElementById('bin-add-field-select'), @@ -2414,22 +2456,11 @@ function open_bin_editor(bin) { bin.fields ?? {} ).get_fields; - // Contents tab + // Contents render_bin_contents(bin.id, document.getElementById('bin-contents-list')); document.getElementById('bin-add-content').onclick = () => open_bin_content_dialog(bin.id); - // Show dialog first so the canvas has correct layout dimensions dlg.showModal(); - - const canvas = document.getElementById('bin-editor-canvas'); - bin_editor_instance = new Grid_Setup(canvas); - bin_editor_instance.set_rows(1); - bin_editor_instance.set_cols(1); - bin_editor_instance.load_image(`/img/${bin.source_id}`).then(() => { - if (bin.corners) { - bin_editor_instance.set_corners(bin.corners); - } - }); } // --------------------------------------------------------------------------- @@ -2678,10 +2709,9 @@ async function init() { const type_id = document.getElementById('bin-editor-type').value || null; const fields = bin_editor_get_fields?.() ?? {}; try { - // Always save name, type, and fields const corners = bin_editor_instance?.get_corners(); if (corners) { - // Corners tab active (or image loaded) — also re-process + // Canvas was opened — re-process corners too const phys_w = parseFloat(document.getElementById('bin-editor-width').value) || null; const phys_h = parseFloat(document.getElementById('bin-editor-height').value) || null; await api.update_bin(id, { name, type_id, fields }); diff --git a/public/style.css b/public/style.css index 1c1e279..d4c0d3f 100644 --- a/public/style.css +++ b/public/style.css @@ -1988,6 +1988,46 @@ nav { margin-left: 0.25rem; } +.bin-editor-preview-wrap { + width: 100%; + background: #0e0e0e; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + min-height: 120px; + margin-bottom: 0.5rem; + overflow: hidden; +} + +.bin-editor-preview-img { + max-width: 100%; + max-height: 55vh; + display: block; + object-fit: contain; +} + +.bin-editor-no-image { + color: var(--text-faint); + font-size: 0.85rem; + padding: 2rem; + text-align: center; +} + +.btn-link { + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 0.8rem; + padding: 0.25rem 0; + text-decoration: underline; +} + +.btn-link:hover { + color: var(--text); +} + .bin-editor-canvas { display: block; border-radius: 4px; diff --git a/public/templates.html b/public/templates.html index aa74caf..a35252d 100644 --- a/public/templates.html +++ b/public/templates.html @@ -671,24 +671,29 @@