@datocms/product-scenes 0.1.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -3
- package/dist/index.d.ts +3306 -247
- package/dist/index.js +33221 -10131
- package/dist/product-scenes.css +14025 -3455
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The pictures of the DatoCMS interface on www.datocms.com, made with the real com
|
|
|
4
4
|
|
|
5
5
|
This package is for the DatoCMS website only. It has no support and no semver promise: any version can change the API. The licence does not let you use it in other projects.
|
|
6
6
|
|
|
7
|
-
The package is a kit of parts: the frame (`Stage`), the parts of the screens of the cms (`NavigationBar
|
|
7
|
+
The package is a kit of parts: the frame (`Stage`), the parts of the screens of the cms (`NavigationBar` (with the tabs that plugins add, `pluginTabs`), `ContentSidebar`, `RecordEditorLayout`, `VisualEditorLayout` (the tab Visual, with the records of the page), `WebPreview` (the plugin Web Previews, with the page of the site and the outlines of content link), `RecordForm` (with the locale tabs of a localized record, the SEO field, the error of a field after a save, the external video field with its video (`RecordForm.VideoInput`, with the actions on the thumbnail if you give `hovered`), the file field with an image or with a media that the host plays (`RecordForm.FileInput` `media`, for example a video), the avatar and the lock of another user that edits the record, and the parts of a plugin: an outlet above the fields (`RecordForm.Outlet`) and the editor of a field (`RecordForm.PluginInput`), with the content from the website), `ConfigurationMenu` and `PluginList` (the menu of the environment configuration, and the plugins of the project in the `list` column, with the presets and the help of the title, and the pill of a private plugin), `SeoPreviewStack` (the SEO field in a stack of cards, one preview on each), `StructuredTextInput`, `ModularContentField`, `InfoAside` (with the stage of a record in a workflow and the revision history), `RecordList` (the collection of a model: its toolbar and the table of its records), `RecordTree` (the compact view of a model with hierarchical sorting: the tree of its records, in the `list` column of `RecordEditorLayout`), `RolePermissions`, the record permissions of a role (with the conditions on the creator and on the stage of a record), `SelectivePublishing`, `ModelSettings` and `SeoDialog` (the dialog of the SEO field, alone or over the record editor), three dialogs, `WorkflowStages`, the stages of a workflow in its settings, `AddFieldMenu`, the page of a model in the schema with the menu Add new field open, and the tab Schema: `SchemaSidebar` (the models and their API keys), `ModelPage` (the fields of a model) and `FieldSettings` (the dialog of an asset field, with its validations and the help text of its tab Presentation, or on its tab Settings with the switch of the localization, or the dialog of a text field with the toolbar buttons of its Markdown editor and the menu of its editors open), `MediaArea` (the media library: the tree of the collections, the grid of the assets, the menus of the saved filters and of the upload button) and `AssetDetail` (the details of an asset, alone or over the media library: the focal point and its crop previews, the asset info, the default metadata in each locale, the categorization; for a video, the player with the marker of the thumbnail (`AssetDetail.Player`, also alone), the panel of the audio tracks and the subtitles (`AssetDetail.Tracks`, with the tooltip of the download), and the dialogs Generate subtitles from audio (`AssetDetail.GenerateSubtitles`) and Add new track (`AssetDetail.AddTrack`, with the upload of the file), over the page or alone with `over={false}`)) and a few components of the DatoCMS design system (`Button`, `InfoList`, `Pill`, from the package ui-public). The website composes the scenes from the parts and gives the fake data.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ The package is a kit of parts: the frame (`Stage`), the parts of the screens of
|
|
|
12
12
|
npm install @datocms/product-scenes react@19 react-dom@19
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
The package has no dependencies: the build contains the components of the cms. React 19 is a peer dependency.
|
|
15
|
+
The package has no dependencies: the build contains the components of the cms (the packages ui-public and ui-static of the DatoCMS monorepo). React 19 is a peer dependency.
|
|
16
16
|
|
|
17
17
|
## The CSS and the Fonts
|
|
18
18
|
|
|
@@ -24,6 +24,8 @@ import '@datocms/product-scenes/product-scenes.css';
|
|
|
24
24
|
|
|
25
25
|
Every rule of the file applies only inside a scene, thus the CSS of the page does not change. The file has no `@font-face` rule: the page gives the fonts that it already loads, with two custom properties on an element above the scenes.
|
|
26
26
|
|
|
27
|
+
The selects of the scenes also write rules when they render (react-select writes them with Emotion, in `<style data-emotion>` tags in the HTML). These rules are in the cascade layer `vendor`. When the website puts `product-scenes.css` in a layer, give the name of that layer to the `cssLayer` prop of `Stage`, thus the CSS of the kit beats these rules. A website without layers keeps the default: the CSS of the kit has no layer, thus it beats the layer.
|
|
28
|
+
|
|
27
29
|
```css
|
|
28
30
|
:root {
|
|
29
31
|
--product-scenes-font-sans: 'ABC Oracle', sans-serif;
|
|
@@ -31,6 +33,12 @@ Every rule of the file applies only inside a scene, thus the CSS of the page doe
|
|
|
31
33
|
}
|
|
32
34
|
```
|
|
33
35
|
|
|
36
|
+
A dialog alone (`SelectivePublishing`, `ModelSettings`) has no page behind it: the screen is transparent, and the panel is at its top left, with a margin around it for its shadow. The margin is `--spacing-xxl` of the cms (about 56px); `--product-scenes-dialog-margin`, on an element above the scene, changes it. The panel takes the width of the screen less the margins, up to its width in the cms (600px or 700px): on a wider screen the space is on the right. The panel has the corners of the cms; `--product-scenes-dialog-radius` (in px of the page), on an element above the scene, changes them: a page that puts the panel at the corner of the frame (a margin of 0) gives it the radius of the frame.
|
|
37
|
+
|
|
38
|
+
`SeoDialog` with `over` is the dialog over the page: put it after the `RecordEditorLayout`, in the same `Stage`. It covers the screen with the backdrop of the cms, and the panel is near the top, in the center. `--product-scenes-dialog-margin` does not change it. A page that clips the right part of the screen gives that width, in px of the page, to `--product-scenes-dialog-clip-end`, on an element above the scene: the panel is then in the center of the part that shows, and narrower if that part is narrower than the panel.
|
|
39
|
+
|
|
40
|
+
The stack of `SeoPreviewStack` has no page behind it either: the screen is transparent, and the cards fill its width, 32px below its top edge, where the cards behind peek out.
|
|
41
|
+
|
|
34
42
|
## A Scene
|
|
35
43
|
|
|
36
44
|
```tsx
|
|
@@ -84,10 +92,89 @@ In an Astro page, render the scene as a component, without a `client:` directive
|
|
|
84
92
|
|
|
85
93
|
A model or a folder of `ContentSidebar` and the `icon` of `RecordForm` use the emoji of the model as the icon, as in the cms. A part that shows another icon takes it as a `ReactNode`.
|
|
86
94
|
|
|
95
|
+
## The Stage
|
|
96
|
+
|
|
97
|
+
`Stage` is the frame of a scene. Its props:
|
|
98
|
+
|
|
99
|
+
- `description`: what the scene shows, for a screen reader.
|
|
100
|
+
- `scheme`: `'light'` (default), `'dark'`, or `'page'`: the screen follows the scheme of the page (see "The scheme of the page").
|
|
101
|
+
- `hue`: the hue of the brand color, from 0 to 360 (default 290).
|
|
102
|
+
- `tint`: the strength of the hue on the surfaces and the borders (default 1). It multiplies the chroma of the neutral colors of the cms. In the dark scheme the hue barely shows: use 2 to 4 to make it show more. The text does not get it (the tint fades out on the stops of the text), thus the light text of the dark scheme stays almost white.
|
|
103
|
+
- `chroma`: the most chroma of the brand color, in OKLCH (0 to about 0.3). It caps the signal colors of the cms: the primary buttons, the focus rings, the selected rows. Without it they are as vivid as the gamut allows, as in the cms (from 0.11 for a blue to 0.24 for a purple). Cap it where the accent of the cms must not win over the page around the scene: 0.08 is a quiet accent.
|
|
104
|
+
- `height`: the height of the screen in px, before the zoom (default 900).
|
|
105
|
+
- `width`: the width of the screen in px (see below).
|
|
106
|
+
- `minWidth`: the smallest width of the screen of the cms in px (default 1025).
|
|
107
|
+
- `fit`: the zoom makes the screen smaller on a stage narrower than the screen (default: true without `width`, false with `width`).
|
|
108
|
+
- `inspectable`: for the development of the website only: the screen is not inert and not hidden, so the browser devtools can inspect it. Never in production: a screen reader would read the fake interface.
|
|
109
|
+
|
|
110
|
+
Without `width`, the screen takes the width of the stage, down to `minWidth`, as the cms takes the width of the window. On a narrower stage, the screen stays `minWidth` wide and CSS makes it smaller with `zoom`, thus it is exactly as wide as the stage. Give a larger `minWidth` to a scene that needs more space, for example a toolbar that must stay on one line.
|
|
111
|
+
|
|
112
|
+
With `width`, the screen is exactly that wide, and the stage is as wide as the screen at its zoom: the page can put the stage in a box with `width: fit-content`. Use it for a scene without `RecordEditorLayout`, for example a `RecordForm` alone in a narrow window. The screen does not get smaller: the page clips it. With `fit`, it gets smaller on a stage narrower than the screen.
|
|
113
|
+
|
|
114
|
+
### The CSS contract of the stage
|
|
115
|
+
|
|
116
|
+
The page styles the stage with custom properties, on the stage or on an element above it. It does not style the classes of the stage.
|
|
117
|
+
|
|
118
|
+
| Property | Meaning |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `--product-scenes-zoom` | The zoom of the screen (a number, default 1). The stage makes it smaller where the screen does not fit (`fit`). |
|
|
121
|
+
| `--product-scenes-radius` | The corners of the frame of the screen (default 0). |
|
|
122
|
+
| `--product-scenes-shadow` | The shadow of the frame, for example a ring (default none). |
|
|
123
|
+
| `--product-scenes-border` | A border above the screen, inside the frame, for example `1px solid white` (default none). It does not make the frame wider. |
|
|
124
|
+
| `--product-scenes-pointer-scale` | The size of the pointer of the system on the page, in times its real size (a number, default 1.4). The zoom of the screen does not change it. |
|
|
125
|
+
|
|
126
|
+
The frame has the size of the screen at its zoom, thus the corners, the shadow and the border are at the size of the page.
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
.hero {
|
|
130
|
+
--product-scenes-zoom: 0.9;
|
|
131
|
+
--product-scenes-radius: 12px;
|
|
132
|
+
--product-scenes-shadow: 0 0 0 1px rgb(0 0 0 / 60%);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### The scheme of the page
|
|
137
|
+
|
|
138
|
+
A stage with `scheme="page"` is dark when the root element of the page has `data-product-scenes-scheme="dark"`, and light without it. Thus a page with a switch of the scheme changes the attribute on `<html>`, and its scenes follow without a script and without a second render. Set the attribute before the first paint (an inline script in the head), else the scenes show light first.
|
|
139
|
+
|
|
140
|
+
```html
|
|
141
|
+
<html data-product-scenes-scheme="dark">
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The stage gets the light and the dark ramp of its hue and tint, and CSS selects one. The page must not set `data-color-scheme` on an element above the stages: the rules of the cms for a scheme also match an ancestor.
|
|
145
|
+
|
|
146
|
+
The page sets `data-paused` on the screen (`.ProductScenesScreen`) when the screen is not in view: the animations that loop, for example the caret of `StructuredTextInput.SlashMenu`, stop.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<Stage description="The editor of a page." width={360} height={480} hue={45} scheme="dark" tint={3}>
|
|
150
|
+
<RecordForm title="Spring sale" icon="🏠">
|
|
151
|
+
<RecordForm.Field label="Title" required>
|
|
152
|
+
<RecordForm.StringInput value="Spring sale" large />
|
|
153
|
+
</RecordForm.Field>
|
|
154
|
+
</RecordForm>
|
|
155
|
+
</Stage>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Sequences
|
|
159
|
+
|
|
160
|
+
A scene can play an interaction in a loop: the open gap of a modular content field (`ADD_BLOCK_SEQUENCE`), a block of a modular content field that the editor drags one place down and drops, with the highlight of the cms after the drop, then the block that went up, which the editor drags one place down too, thus the loop comes back to the first order (`DRAG_BLOCK_SEQUENCE`, with `ModularContentField.Block` `dragged`, `dragBack` on the next block, and `dropLine` "top" on the block after it), the slash menu of a structured text field (`SLASH_SEQUENCE`), a block of a structured text field that the editor selects (`BLOCK_SELECT_SEQUENCE`, with `StructuredTextInput.Block` `selected`), the pointer that comes on a record in the text and shows its tooltip (`RECORD_TOOLTIP_SEQUENCE`, with `StructuredTextInput.InlineRecord` `hovered`), the stage of a record and the tooltip of a stage in its menu (`STAGE_MENU_SEQUENCE`), the menu of a field that opens, then the submenu of a plugin in it (`FIELD_MENU_SEQUENCE`, with `RecordForm.Field` `menu` and a group with `open`), the cards of `SeoPreviewStack`, each in turn at the front (`PREVIEW_STACK_SEQUENCE`), a click on the Edit button of the SEO field that opens its dialog (`SEO_EDIT_SEQUENCE`, with `RecordForm.SeoInput` `edit` and `SeoDialog` `over`), another user that saves a record, leaves, comes back and edits it again, while the pointer of the user that looks cannot click the read-only field until the save (`COLLABORATION_SEQUENCE`, with `RecordForm` `collaborator`, `RecordForm.Field` `saved` and `pointer`, and `InfoAside.RevisionHistory` `saved`), the tab Visual, where the edit mode flashes the targets of the page, then a click opens a record and a second click opens a linked record (`VISUAL_EDITING_SEQUENCE`, with `VisualEditorLayout`, `WebPreview` `mode="visual"`, `WebPreview.Target`, `RecordForm.Field` `highlighted` and `RecordForm.Above`, the fields that the form scrolls past), and a click on Save that reloads the page in the plugin Web Previews (`PREVIEW_RELOAD_SEQUENCE`, with `WebPreview` `reloaded` and `RecordForm` `dirty="until-saved"`), the menu Add new field of a model that opens, then the card of a field type under the pointer (`ADD_FIELD_SEQUENCE`, with `AddFieldMenu` `hovered`), the pointer that goes on three field types of that menu in turn, each with its card (`HOVER_FIELD_TYPES_SEQUENCE`, with a list of three types in `AddFieldMenu` `hovered`), and a click on a field of a model that opens its dialog on the tab Settings, then a click on the tab Presentation and a click on the tab Validations (`FIELD_SETTINGS_SEQUENCE`, with `ModelPage` `clicked` and `FieldSettings` `over`; `RecordEditorLayout` `sidebarWidth={400}` gives the sidebar of the schema its width), the same click on a text field, then a click on the tab Presentation and a click on the button Change of its editor, that opens the menu of the editors (`FIELD_EDITOR_SEQUENCE`, with `FieldSettings` `type="text"`), and the subtitles that the cms generates from the audio of a video: the buttons of the panel, the dialog, then the new track (`GENERATE_SUBTITLES_SEQUENCE`, with `AssetDetail.Tracks` `sequence`, a track with `added`, and `AssetDetail.GenerateSubtitles` `sequence` in `AssetDetail` `dialog`), a click on an asset of the media area that opens its dialog (`OPEN_ASSET_SEQUENCE`, with a `MediaArea` asset with `clicked` and `AssetDetail` `over`), the same click, then a click on the image of the asset that sets its focal point, with the previews of the crops around the center, then around the point (`OPEN_ASSET_FOCAL_POINT_SEQUENCE`, with the same props and `AssetDetail` `sequence` and `focalPoint`), and a run of the plugin AI Translations in the aside: the click on Translate all fields, four batches of jobs with a progress bar and a line for the job in progress, the unsaved changes in the toolbar, and the message at the end (`AI_TRANSLATIONS_SEQUENCE`, with `InfoAside.AiTranslations` `sequence` and `RecordForm` `dirty="after-translations"`). Give the sequence to the stage:
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
<Stage description="…" sequence={ADD_BLOCK_SEQUENCE}>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The screen gets `data-scene-steps="rest:1600 gap:900 …"`: the name of each step and its time in ms. The page plays it with a script: it sets `data-step` on the screen (`.ProductScenesScreen`) to each name in turn, and loops. The CSS of the part shows the step, with the transitions and the animations of the cms. The screen also gets the time of each step in a custom property (`--scene-step-gap: 900ms`): an animation that lasts for all its step reads it. Without `data-step`, the screen shows the last step: the picture at rest. Thus the page shows the picture without JS and with reduced motion, and the script stops the loop when the scene is off screen.
|
|
167
|
+
|
|
168
|
+
The kit sends no JS: the script is of the page.
|
|
169
|
+
|
|
170
|
+
### Marks over the parts
|
|
171
|
+
|
|
172
|
+
A scene can put a layer of the website over a part of the cms, for example a ring and a tag that tell the name of a hook of the plugin SDK. The layer covers the box of the part, gets no pointer events, and can go out of the box: give its look in the CSS of the website. The plugin tab of `NavigationBar` (`pluginTabs[].mark`) and the publish button of `RecordForm` (`publishMark`) take a layer, because the website cannot put content in them. `RecordForm.Outlet` and `RecordForm.PluginInput` take content from the website, thus the website puts its layer in that content.
|
|
173
|
+
|
|
87
174
|
## The Rules of a Scene
|
|
88
175
|
|
|
89
176
|
- **No `client:` directive.** A scene is static HTML. The package sends no JS to the browser, and the parts do not work in the browser.
|
|
90
177
|
- **Controlled inputs with constant values.** Give each input its value as a prop. Do not keep a state, and do not wait for a user action.
|
|
91
|
-
- **No overlays and no portals.** Do not open a dropdown, a tooltip, a modal or a popover: there is no JS to place it. Show the closed state.
|
|
178
|
+
- **No overlays and no portals.** Do not open a dropdown, a tooltip, a modal or a popover: there is no JS to place it. Show the closed state. The exceptions are in the parts: `StructuredTextInput.SlashMenu` and the `addAbove` prop of `ModularContentField.Block` (open, at rest, with one option under the pointer and its card if you give `hovered`), the `hovered` prop of `StructuredTextInput.InlineRecord`, the `menu` of the `stage` of `InfoAside.RecordInfo` (open, with the tooltip of the stage under the pointer if you give `hovered`), the `menu` of `RecordForm.Field` (the dropdown of the actions of the field, open; the group with `open` shows its submenu, for example the actions of a plugin), the `hovered` prop of `RecordForm.VideoInput` (the actions of the card on the thumbnail, as under the pointer), `AddFieldMenu` (the menu Add new field, open, with the card of a field type under the pointer if you give `hovered`), and the `dragged` prop of `ModularContentField.Block` (the picture of a drag, still).
|
|
92
179
|
- **Fixed dates and fixed data.** Write the dates as text. Do not read the clock and do not fetch, thus two renders give the same picture.
|
|
93
180
|
- **One `Stage` for each scene, with a `description`.** The screen is hidden from assistive technology, thus the description is the only text that a screen reader hears. Write what the picture shows. A page can show many stages.
|