@relatude/site
v1.0.0-alpha.2
Published
Marks a site's pages for the Relatude CMS interface's preview, so Locate finds every field exactly: any framework, no dependencies.
Readme
@relatude/site
Marks a site's pages for the Relatude CMS interface's preview. Locate in the preview outlines a field where the page shows it, and a click opens that field in the editor. It finds most fields by their values; a page that marks them is found exactly, whatever it shows: a date formatted, a price with its unit, a picture as a background, a heading the same as the menu's link. A page that moves to another without loading, as client-routed apps do, also says which page it shows now.
npm install @relatude/siteIt has no dependencies and works with any way of rendering, as the marks are attributes on elements, which the CMS's script in the page reads and reads again as the page changes:
| Attribute | On | Says |
|---|---|---|
| data-relatude-field="{node}/{Property}" | the element showing a field | a node's property, by the node's Guid and the property's code name |
| data-relatude-field="{node}/{Embedded}/{inner}/{Property}" | the same | an inner node's property, by its holder, the embedded property and the inner node's Guid |
| data-relatude-page="{node}" | any one element, the app's root say | the node the page shows now; "" for a page of no node |
| data-relatude-culture="{code}" | beside data-relatude-page | the culture it is shown in |
The functions write them only on pages the preview shows (the CMS adds its script to those and to no other), so a visitor's page is as it was.
React, Preact, Solid
import { fieldAttributes, pageAttributes } from '@relatude/site';
export function Article({ article }: { article: Article }) {
return (
<main {...pageAttributes(article.id, article.culture)}>
<h1 {...fieldAttributes(article.id, 'Name')}>{article.name}</h1>
<time {...fieldAttributes(article.id, 'Published')}>{format(article.published)}</time>
<div {...fieldAttributes(article.id, 'Body')} dangerouslySetInnerHTML={{ __html: article.body }} />
{article.specifications.map(s => (
<dd key={s.id} {...fieldAttributes(article.id, 'Value', { embedded: 'Specifications', id: s.id })}>{s.value}</dd>
))}
</main>
);
}Vue
<h1 v-bind="fieldAttributes(article.id, 'Name')">{{ article.name }}</h1>Svelte
<h1 {...fieldAttributes(article.id, 'Name')}>{article.name}</h1>Angular, Lit and templates that bind one attribute
fieldMark is the attribute's value, or null where fields are not marked, which leaves the attribute out:
<h1 [attr.data-relatude-field]="fieldMark(article.id, 'Name')">{{ article.name }}</h1>Code that works on elements
import { setFieldMark, setPageMark } from '@relatude/site';
setPageMark(document.querySelector('main'), article.id);
setFieldMark(heading, article.id, 'Name');What it needs
- Node ids. A node is its Guid, or an object holding it as
id,$id(the CMS API's) orId. Whatever the site's pages are made from must carry the ids of the nodes it shows. - The page's node, when the page changes without loading. The CMS tells the script which node a page is when it
sends the page, which holds only for that address. Name the node the app shows now on one element with
pageAttributes, or leave it to the preview, which takes the address apart with the site's URL manager. - The script tag in the page.
inPreview()looks for the CMS's script,script[data-relatude-finder], which the CMS puts at the end of the body: it knows once the document is parsed, as a module script or a bundler's entry runs. The CMS adds it to pages it serves throughUseRelatudeCMS(), so an app'sindex.htmlmust be served after it (app.UseRelatudeCMS()beforeapp.UseStaticFiles(), or the app's own route). - Hydration. A page rendered on a server and hydrated in the browser must have the same markup in both: call
markAlways()before rendering, on the server and in the browser, and every page carries the marks.
