board-livecards-localstorage + server-runtime.
Source fetches are done by a demo task executor in this HTML using source_def url/url-list and
reporting results via reportSourceFetched.
Copy this pattern to register a card renderer, a board theme, a board renderer, or lightweight board skin classes.
LiveCard.registerCardRenderer('portfolio-card', {
createShell: function (model) {
var wrap = document.createElement('div');
wrap.className = 'card shadow-sm h-100 border-success-subtle';
var body = document.createElement('div');
body.className = 'card-body p-3';
wrap.appendChild(body);
return body;
},
renderBody: function (model, body, ctx) {
body.innerHTML = '';
var title = document.createElement('h6');
title.textContent = (model.card.meta && model.card.meta.title) || model.id;
body.appendChild(title);
var metrics = document.createElement('div');
ctx.renderBuiltin(model, 'metric', model.computed_values.total_value, metrics, { label: 'Total value' });
body.appendChild(metrics);
},
// Back-compat board skin fields also work when this renderer is present.
boardClass: 'demo-board-shell',
listClass: 'demo-board-list',
styles: '.demo-board-list { row-gap: 1rem; }'
});
LiveCard.registerBoardTheme('soft-grid', {
boardClass: 'px-2 py-1',
listClass: 'align-items-stretch',
styles: '.lc-board-grid { --bs-gutter-x: 1rem; --bs-gutter-y: 1rem; }'
});
LiveCard.registerBoardRenderer('framed-board', {
createBoardHost: function (ctx) {
var host = document.createElement('section');
host.className = 'border rounded-3 p-3 bg-white';
host.appendChild(ctx.defaultListEl);
return { mountEl: host, listEl: ctx.defaultListEl };
}
});
board = LiveCard.Board(engine, document.getElementById('boardRoot'), {
initialState: stateRef.current,
getNodeIds: function (s) { return s.cardIds; },
selectNode: function (s, id) { return s.modelsById[id]; },
boardTheme: 'soft-grid',
boardRenderer: 'framed-board',
boardSkin: {
boardClass: 'my-board-shell',
listClass: 'my-board-list',
styles: '.my-board-shell { background: #f8fafc; }'
}
});
Initializing board...