42 lines
1.5 KiB
JavaScript
42 lines
1.5 KiB
JavaScript
// The concept's page heading (docs/concepts/workspace/app.js heading(), 303-305), shared by every workspace route.
|
|
|
|
function element(tag, className, text) {
|
|
const node = document.createElement(tag);
|
|
if (className) node.className = className;
|
|
if (text !== undefined) node.textContent = text;
|
|
return node;
|
|
}
|
|
|
|
function partsOf(heading) {
|
|
return {
|
|
heading,
|
|
h1: heading.querySelector(':scope > div > h1'),
|
|
description: heading.querySelector(':scope > div > p.muted'),
|
|
actions: heading.querySelector(':scope > .heading-actions'),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Replace `main`'s content with `.heading` > div (`h1#page-title[tabindex=-1]`, `p.muted`) + `.heading-actions`.
|
|
* The h1 is the focus target after a save or a route change, as the concept's page title is.
|
|
*/
|
|
export function renderHeading(main, { title = '', description = '', actions = [] } = {}) {
|
|
const heading = element('div', 'heading');
|
|
const copy = element('div');
|
|
const h1 = element('h1', undefined, title);
|
|
h1.id = 'page-title';
|
|
h1.tabIndex = -1;
|
|
copy.append(h1, element('p', 'muted', description));
|
|
const actionRow = element('div', 'heading-actions');
|
|
actionRow.append(...actions);
|
|
heading.append(copy, actionRow);
|
|
main.replaceChildren(heading);
|
|
return partsOf(heading);
|
|
}
|
|
|
|
/** The heading the shell rendered into `main`, or null when a view is mounted without one. */
|
|
export function pageHeading(main) {
|
|
const heading = main.querySelector(':scope > .heading');
|
|
return heading ? partsOf(heading) : null;
|
|
}
|