feat(ui): 2.0.0-alpha.13 — finer per-card width scaling (12-col grid + -/+ stepper)
clock/weather etc. default to 1/6 width; sizes store an integer span 1-12 (legacy s/m/l still accepted by /api/dashboard/layout). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -29,18 +29,43 @@ async function saveLayout() {
|
||||
}
|
||||
|
||||
// ---- per-card edit controls (drag grip + size + hide), shown only in edit mode via CSS
|
||||
const STR_SPAN = { s: 2, m: 6, l: 12 }; // legacy size → 12-col span (s = 1/6, m = 1/2, l = full)
|
||||
function spanOf(def) {
|
||||
const v = layout.sizes?.[def.id];
|
||||
if (typeof v === 'number') return Math.max(1, Math.min(12, v));
|
||||
if (typeof v === 'string') return STR_SPAN[v] || 6;
|
||||
return STR_SPAN[def.size] || 6;
|
||||
}
|
||||
function curSpan(id) {
|
||||
const node = grid().querySelector(`.sv-card[data-card-id="${id}"]`);
|
||||
const m = node && (node.style.gridColumn || '').match(/span (\d+)/);
|
||||
return m ? +m[1] : spanOf(BY_ID.get(id) || {});
|
||||
}
|
||||
function setSpan(id, delta) {
|
||||
const span = Math.max(1, Math.min(12, curSpan(id) + delta));
|
||||
layout.sizes = { ...layout.sizes, [id]: span };
|
||||
const node = grid().querySelector(`.sv-card[data-card-id="${id}"]`);
|
||||
if (node) {
|
||||
node.style.gridColumn = 'span ' + span;
|
||||
const lbl = node.querySelector('.sv-span-val');
|
||||
if (lbl) lbl.textContent = span;
|
||||
}
|
||||
saveLayout();
|
||||
}
|
||||
|
||||
function editOverlay(def) {
|
||||
const grip = el('span', { class: 'sv-grip', draggable: true, title: 'Drag to reorder' }, '⠿');
|
||||
const sizes = el('span', { class: 'sv-ed-sizes' },
|
||||
...['s', 'm', 'l'].map(s =>
|
||||
el('button', { class: 'sv-ed-size', dataset: { s }, onclick: () => setSize(def.id, s) }, s.toUpperCase())));
|
||||
const stepper = el('span', { class: 'sv-ed-span' },
|
||||
el('button', { class: 'sv-ed-step', title: 'Narrower', onclick: () => setSpan(def.id, -1) }, '−'),
|
||||
el('span', { class: 'sv-span-val', title: 'Width (of 12)' }, String(spanOf(def))),
|
||||
el('button', { class: 'sv-ed-step', title: 'Wider', onclick: () => setSpan(def.id, +1) }, '+'));
|
||||
const hide = el('button', { class: 'sv-ed-hide', title: 'Hide card', onclick: () => hideCard(def.id) }, '✕');
|
||||
return el('div', { class: 'sv-card-edit' }, grip, sizes, hide);
|
||||
return el('div', { class: 'sv-card-edit' }, grip, stepper, hide);
|
||||
}
|
||||
|
||||
function mountOne(def) {
|
||||
const size = layout.sizes?.[def.id] || def.size;
|
||||
const { root, body } = svCard({ ...def, size });
|
||||
const span = spanOf(def);
|
||||
const { root, body } = svCard({ ...def, span });
|
||||
root.appendChild(editOverlay(def));
|
||||
grid().appendChild(root);
|
||||
try { def.mount(body); def.start && def.start(); active.push(def); }
|
||||
|
||||
Reference in New Issue
Block a user