fix: load sections too

backup
flop 3 weeks ago
parent d1c042922b
commit 256fde9214
  1. 98
      ts/index.html

@ -406,7 +406,7 @@
flex-shrink: 0 flex-shrink: 0
} }
/* red × section & element */ /* red × - section & element */
.x-btn { .x-btn {
background: none; background: none;
border: none; border: none;
@ -681,11 +681,11 @@
<div id="sec-meta"> <div id="sec-meta">
<div class="meta-row"> <div class="meta-row">
<label>Selected section</label> <label>Selected section</label>
<span class="meta-val green" id="meta-name"></span> <span class="meta-val green" id="meta-name">-</span>
</div> </div>
<div class="meta-row"> <div class="meta-row">
<label>Elements</label> <label>Elements</label>
<span class="meta-val" id="meta-count"></span> <span class="meta-val" id="meta-count">-</span>
</div> </div>
<div class="meta-row"> <div class="meta-row">
<label>Section flags</label> <label>Section flags</label>
@ -728,7 +728,7 @@
let currentFilename = 'untitled'; let currentFilename = 'untitled';
let isDirty = false; let isDirty = false;
// ─── Element type definitions ──────────────────────────────────────────────── // --- Element type definitions ------------------------------------------------
const EL_TYPES = ['Image2D', 'Animation', 'ClippedText', 'HScrollText', 'CurrentTime']; const EL_TYPES = ['Image2D', 'Animation', 'ClippedText', 'HScrollText', 'CurrentTime'];
const EL_FIELDS = { const EL_FIELDS = {
Image2D: [ Image2D: [
@ -746,7 +746,7 @@
{ k: 'width', l: 'Width', t: 'number', d: W }, { k: 'height', l: 'Height', t: 'number', d: 16 }, { k: 'width', l: 'Width', t: 'number', d: W }, { k: 'height', l: 'Height', t: 'number', d: 16 },
], ],
HScrollText: [ HScrollText: [
{ k: 'text', l: 'Text', t: 'text', d: 'Scrolling text ', full: true }, { k: 'text', l: 'Text', t: 'text', d: 'Scrolling text - ', full: true },
{ k: 'xOffset', l: 'X offset', t: 'number', d: 0 }, { k: 'yOffset', l: 'Y offset', t: 'number', d: 32 }, { k: 'xOffset', l: 'X offset', t: 'number', d: 0 }, { k: 'yOffset', l: 'Y offset', t: 'number', d: 32 },
{ k: 'width', l: 'Width', t: 'number', d: W }, { k: 'height', l: 'Height', t: 'number', d: 16 }, { k: 'width', l: 'Width', t: 'number', d: W }, { k: 'height', l: 'Height', t: 'number', d: 16 },
{ k: 'scrollSpeed', l: 'Scroll speed', t: 'number', d: 50 }, { k: 'scrollSpeed', l: 'Scroll speed', t: 'number', d: 50 },
@ -763,7 +763,7 @@
CurrentTime: [{ k: 'clock12h', l: '12h mode' }, { k: 'showHours', l: 'Show hours' }, { k: 'showSeconds', l: 'Show seconds' }], CurrentTime: [{ k: 'clock12h', l: '12h mode' }, { k: 'showHours', l: 'Show hours' }, { k: 'showSeconds', l: 'Show seconds' }],
}; };
// ─── Confirm dialog ─────────────────────────────────────────────────────────── // --- Confirm dialog -----------------------------------------------------------
function confirm(msg, buttons) { function confirm(msg, buttons) {
// buttons: [{label,primary,action}] // buttons: [{label,primary,action}]
return new Promise(resolve => { return new Promise(resolve => {
@ -782,7 +782,7 @@
}); });
} }
// ─── Dirty tracking ─────────────────────────────────────────────────────────── // --- Dirty tracking -----------------------------------------------------------
function markDirty() { function markDirty() {
isDirty = true; isDirty = true;
document.getElementById('filename').classList.add('dirty'); document.getElementById('filename').classList.add('dirty');
@ -800,7 +800,7 @@
return action; return action;
} }
// ─── Helpers ───────────────────────────────────────────────────────────────── // --- Helpers -----------------------------------------------------------------
function newSec() { function newSec() {
secCounter++; secCounter++;
return { return {
@ -819,7 +819,7 @@
function getSec(id) { return sections.find(s => s.id === id) } function getSec(id) { return sections.find(s => s.id === id) }
function getEl(secId, elId) { const s = getSec(secId); return s && s.elements.find(e => e.id === elId) } function getEl(secId, elId) { const s = getSec(secId); return s && s.elements.find(e => e.id === elId) }
// ─── Mutations ──────────────────────────────────────────────────────────────── // --- Mutations ----------------------------------------------------------------
function addSection() { function addSection() {
const s = newSec(); sections.push(s); const s = newSec(); sections.push(s);
activeSec = s.id; activeEl = null; activeSec = s.id; activeEl = null;
@ -871,7 +871,7 @@
el.flags[key] = val; markDirty(); triggerPreview(); el.flags[key] = val; markDirty(); triggerPreview();
} }
// ─── Load demo into editor state ───────────────────────────────────────────── // --- Load demo into editor state ---------------------------------------------
const DEMO_DEFS = [ const DEMO_DEFS = [
{ {
label: 'Checkerboard', build() { label: 'Checkerboard', build() {
@ -900,7 +900,7 @@
label: 'Scrolltext', build() { label: 'Scrolltext', build() {
const s = newSec(); s.name = 'Scrolltext'; s.flags = { drawFront: true, clearBuffer: true }; const s = newSec(); s.name = 'Scrolltext'; s.flags = { drawFront: true, clearBuffer: true };
const el = newEl('HScrollText'); const el = newEl('HScrollText');
el.fields.text = 'MONO DISPLAY — scrolling ticker — 🚀 '; el.fields.text = 'MONO DISPLAY - scrolling ticker - 🚀 ';
el.fields.yOffset = 32; el.fields.scrollSpeed = 50; el.fields.yOffset = 32; el.fields.scrollSpeed = 50;
el.flags.endless = true; el.flags.invertDirection = false; el.flags.endless = true; el.flags.invertDirection = false;
s.elements.push(el); return [s]; s.elements.push(el); return [s];
@ -925,7 +925,7 @@
}, },
]; ];
// ─── Preview via MonoDisplayFile (same as original demos) ──────────────────── // --- Preview via MonoDisplayFile (same as original demos) --------------------
const DEMO_PREVIEWS = { const DEMO_PREVIEWS = {
Checkerboard() { Checkerboard() {
const { MonoDisplayFile, ElementType } = window.MonoDisplay; const { MonoDisplayFile, ElementType } = window.MonoDisplay;
@ -963,7 +963,7 @@
elements_always: { elements_always: {
flags: { drawFront: true, clearBuffer: true }, flags: { drawFront: true, clearBuffer: true },
elements: [{ elements: [{
type: ElementType.HScrollText, text: 'MONO DISPLAY — scrolling ticker — 🚀 ', type: ElementType.HScrollText, text: 'MONO DISPLAY - scrolling ticker - 🚀 ',
xOffset: 0, yOffset: 32, width: W, height: 16, scrollSpeed: 50, flags: { endless: true, invertDirection: false } xOffset: 0, yOffset: 32, width: W, height: 16, scrollSpeed: 50, flags: { endless: true, invertDirection: false }
}] }]
} }
@ -1011,7 +1011,7 @@
}); });
} }
// ─── Render ─────────────────────────────────────────────────────────────────── // --- Render -------------------------------------------------------------------
function render() { function render() {
updateMeta(); updateMeta();
const wrap = document.getElementById('sections-wrap'); const wrap = document.getElementById('sections-wrap');
@ -1085,20 +1085,20 @@
} }
function elSummary(el) { function elSummary(el) {
if (el.fields.text) return esc(el.fields.text.slice(0, 24) + (el.fields.text.length > 24 ? '' : '')); if (el.fields.text) return esc(el.fields.text.slice(0, 24) + (el.fields.text.length > 24 ? '...' : ''));
return `${el.fields.xOffset ?? 0}, ${el.fields.yOffset ?? 0}`; return `${el.fields.xOffset ?? 0}, ${el.fields.yOffset ?? 0}`;
} }
function esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') } function esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') }
function updateMeta() { function updateMeta() {
const s = activeSec ? getSec(activeSec) : null; const s = activeSec ? getSec(activeSec) : null;
document.getElementById('meta-name').textContent = s ? s.name : ''; document.getElementById('meta-name').textContent = s ? s.name : '-';
document.getElementById('meta-count').textContent = s ? s.elements.length + ' element(s)' : ''; document.getElementById('meta-count').textContent = s ? s.elements.length + ' element(s)' : '-';
document.getElementById('flag-drawFront').checked = s ? !!s.flags.drawFront : false; document.getElementById('flag-drawFront').checked = s ? !!s.flags.drawFront : false;
document.getElementById('flag-clearBuffer').checked = s ? !!s.flags.clearBuffer : false; document.getElementById('flag-clearBuffer').checked = s ? !!s.flags.clearBuffer : false;
} }
// ─── Preview ────────────────────────────────────────────────────────────────── // --- Preview ------------------------------------------------------------------
let previewTimer = null; let previewTimer = null;
function triggerPreview() { function triggerPreview() {
clearTimeout(previewTimer); clearTimeout(previewTimer);
@ -1120,17 +1120,69 @@
)); ));
} }
// ─── Load / Export ──────────────────────────────────────────────────────────── // --- Load / Export ------------------------------------------------------------
function parsedToSections(parsedSecs) {
const TYPE_MAP = { 1: 'Image2D', 2: 'Animation', 16: 'ClippedText', 17: 'HScrollText', 32: 'CurrentTime' };
return parsedSecs
.filter(s => s.sectionType === 1 || s.sectionType === 2)
.map(s => {
secCounter++;
const elements = (s.elements || []).map(el => {
const typeName = TYPE_MAP[el.type];
if (!typeName) return null;
elCounter++;
let fields = {}, flags = {};
switch (typeName) {
case 'Image2D':
fields = { xOffset: el.xOffset, yOffset: el.yOffset, width: el.image?.width ?? W, height: el.image?.height ?? H };
break;
case 'Animation':
fields = { xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height, updateInterval: el.updateInterval };
break;
case 'ClippedText':
fields = { text: el.text, xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height };
break;
case 'HScrollText':
fields = { text: el.text, xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height, scrollSpeed: el.scrollSpeed };
flags = { endless: !!el.flags?.endless, invertDirection: !!el.flags?.invertDirection };
break;
case 'CurrentTime':
fields = { xOffset: el.xOffset, yOffset: el.yOffset, width: el.width, height: el.height, utcOffsetMinutes: el.utcOffsetMinutes };
flags = { clock12h: !!el.flags?.clock12h, showHours: !!el.flags?.showHours, showSeconds: !!el.flags?.showSeconds };
break;
}
return { id: 'e' + elCounter, type: typeName, fields, flags };
}).filter(Boolean);
return {
id: 's' + secCounter,
name: 'Section ' + secCounter,
open: true,
flags: { drawFront: !!s.flags?.drawFront, clearBuffer: !!s.flags?.clearBuffer },
elements
};
});
}
function loadBin(input) { function loadBin(input) {
const file = input.files[0]; if (!file) return; const file = input.files[0]; if (!file) return;
currentFilename = file.name; currentFilename = file.name;
document.getElementById('filename').textContent = file.name; document.getElementById('filename').textContent = file.name;
const reader = new FileReader(); const reader = new FileReader();
reader.onload = e => { reader.onload = e => {
const buf = new Uint8Array(e.target.result); const arrayBuf = e.target.result;
const buf = new Uint8Array(arrayBuf);
if (!window._mdDriver && window.MonoDisplay) if (!window._mdDriver && window.MonoDisplay)
window._mdDriver = new window.MonoDisplay.MonoDisplayDriver('canvas_root', { onColor: '#EC0', offColor: '#000', fps: 25 }); window._mdDriver = new window.MonoDisplay.MonoDisplayDriver('canvas_root', { onColor: '#EC0', offColor: '#000', fps: 25 });
if (window._mdDriver) window._mdDriver.load(() => Promise.resolve(buf)); if (window._mdDriver) window._mdDriver.load(() => Promise.resolve(buf));
try {
const parsed = new window.MonoDisplay.MonoDisplayParser().parse(arrayBuf);
sections = parsedToSections(parsed.sections);
activeSec = sections.length ? sections[0].id : null;
activeEl = null;
render();
} catch (err) {
console.warn('Could not parse sections from bin:', err);
}
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
input.value = ''; markClean(); input.value = ''; markClean();
@ -1149,7 +1201,7 @@
a.click(); markClean(); a.click(); markClean();
} }
// ─── Theme ──────────────────────────────────────────────────────────────────── // --- Theme --------------------------------------------------------------------
var _THEMES = ['dark', 'light', 'auto']; var _THEMES = ['dark', 'light', 'auto'];
function _getTheme() { return document.documentElement.getAttribute('data-theme') || 'auto'; } function _getTheme() { return document.documentElement.getAttribute('data-theme') || 'auto'; }
function _applyTheme(t) { function _applyTheme(t) {
@ -1172,11 +1224,11 @@
var t = _getTheme(), dr = _detectDR(); var t = _getTheme(), dr = _detectDR();
var lbl = { dark: '☾ dark', light: '☀ light', auto: '⊙ auto' }; var lbl = { dark: '☾ dark', light: '☀ light', auto: '⊙ auto' };
btn.textContent = (dr ? 'DR · ' : '') + (lbl[t] || lbl.auto); btn.textContent = (dr ? 'DR · ' : '') + (lbl[t] || lbl.auto);
btn.title = dr ? 'DarkReader active controlling theme' : ('Theme: ' + t + ' (click to cycle)'); btn.title = dr ? 'DarkReader active - controlling theme' : ('Theme: ' + t + ' (click to cycle)');
} }
window.addEventListener('DOMContentLoaded', _updateThemeBtn); window.addEventListener('DOMContentLoaded', _updateThemeBtn);
// ─── Init ───────────────────────────────────────────────────────────────────── // --- Init ---------------------------------------------------------------------
render(); render();
if (window.MonoDisplay) { initDemos(); } if (window.MonoDisplay) { initDemos(); }
else { const iv = setInterval(() => { if (window.MonoDisplay) { clearInterval(iv); initDemos(); } }, 100); } else { const iv = setInterval(() => { if (window.MonoDisplay) { clearInterval(iv); initDemos(); } }, 100); }

Loading…
Cancel
Save