@phis/ui 0.3.0 → 0.4.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/components/cms/phi-cms-layout-renderer.js +1 -1
- package/components/controls/phi-collection-header-control.js +1 -1
- package/components/controls/phi-collection-view-control.js +2 -1
- package/components/controls/phi-drawer-control-adapter.d.ts +1 -1
- package/components/controls/phi-drawer-control-adapter.js +2 -2
- package/components/controls/phi-image-control.d.ts +6 -1
- package/components/controls/phi-image-control.js +23 -4
- package/components/controls/phi-lightbox-image-control-adapter.d.ts +2 -0
- package/components/controls/phi-lightbox-image-control-adapter.js +11 -0
- package/components/controls/phi-lightbox-image-control.d.ts +3 -2
- package/components/controls/phi-lightbox-image-control.js +7 -3
- package/components/controls/phi-modal-control-adapter.d.ts +1 -1
- package/components/controls/phi-modal-control-adapter.js +5 -2
- package/components/controls/phi-overlay-control-contract.d.ts +5 -0
- package/components/controls/phi-pagination-control-adapter.d.ts +2 -0
- package/components/controls/phi-pagination-control-adapter.js +15 -0
- package/components/controls/phi-pagination-control.d.ts +2 -1
- package/components/controls/phi-pagination-control.js +11 -7
- package/components/controls/phi-table-control.js +1 -1
- package/components/controls/phi-timeline-control-adapter.d.ts +2 -0
- package/components/controls/phi-timeline-control-adapter.js +28 -0
- package/components/controls/phi-timeline-control.d.ts +3 -1
- package/components/controls/phi-timeline-control.js +8 -22
- package/components/controls/phi-tour-control.js +25 -7
- package/components/controls/phi-tour-viewport.d.ts +36 -0
- package/components/controls/phi-tour-viewport.js +86 -0
- package/components/controls/phi-zoom-image-overlay.d.ts +17 -0
- package/components/controls/phi-zoom-image-overlay.js +58 -0
- package/components/layouts/layout-definitions.d.ts +0 -18
- package/components/layouts/layout-definitions.js +7 -1
- package/components/layouts/plugins/carousel-layout-plugin.js +2 -1
- package/components/media/aspect-ratios.d.ts +14 -0
- package/components/media/aspect-ratios.js +13 -0
- package/components/motion/phi-sequence-run.d.ts +27 -0
- package/components/motion/phi-sequence-run.js +87 -0
- package/components/motion/phi-sequence-viewport.d.ts +16 -0
- package/components/motion/phi-sequence-viewport.js +97 -34
- package/components/overlays/phi-overlay-container-client.js +5 -2
- package/components/runtime/runtime-visual-anchors.d.ts +13 -2
- package/components/runtime/runtime-visual-anchors.js +49 -3
- package/components/widgets/config/image-variant-options.d.ts +3 -5
- package/components/widgets/config/image-variant-options.js +11 -11
- package/components/widgets/config/sequence-settings.d.ts +75 -0
- package/components/widgets/config/sequence-settings.js +173 -0
- package/components/widgets/label-sets/content-entries.d.ts +9 -0
- package/components/widgets/label-sets/content-entries.js +17 -0
- package/components/widgets/label-types/gallery.d.ts +2 -10
- package/components/widgets/label-types/sequence.d.ts +18 -0
- package/components/widgets/label-types/sequence.js +1 -0
- package/helpers/cms-layout-defaults.js +9 -2
- package/helpers/cms-region-keys.d.ts +1 -1
- package/helpers/motion.d.ts +7 -0
- package/helpers/motion.js +7 -0
- package/package.json +1 -1
- package/plugins/runtime-modules/asset/data-providers.d.ts +4 -0
- package/plugins/runtime-modules/asset/data-providers.js +1 -0
- package/plugins/runtime-modules/asset/definition.d.ts +4 -0
- package/plugins/runtime-modules/asset/presets.d.ts +53 -1
- package/plugins/runtime-modules/asset/presets.js +16 -12
- package/plugins/runtime-modules/asset/tour.d.ts +44 -0
- package/plugins/runtime-modules/asset/tour.js +53 -0
- package/plugins/runtime-modules/builder/clients/inspector-config-field.js +42 -18
- package/plugins/runtime-modules/builder/clients/inspector-image-field.js +2 -2
- package/plugins/runtime-modules/builder/clients/workspace-scope-boundary.js +10 -0
- package/plugins/runtime-modules/builder/controller/workspace-controller.js +18 -3
- package/plugins/runtime-modules/builder/plugin-meta-labels.js +8 -0
- package/plugins/runtime-modules/builder/presets.js +5 -3
- package/plugins/runtime-modules/builder/tour.d.ts +316 -0
- package/plugins/runtime-modules/builder/tour.js +337 -0
- package/plugins/runtime-modules/builder/trees/phi-builder-inspector-area-overlay-tree.server.js +8 -1
- package/plugins/runtime-modules/builder/widgets/structure-region/built-in.js +3 -2
- package/plugins/runtime-modules/core/widgets/collection-view/client.js +10 -0
- package/plugins/runtime-modules/core/widgets/description/config.d.ts +25 -1
- package/plugins/runtime-modules/core/widgets/entry-detail/config.d.ts +2 -0
- package/plugins/runtime-modules/core/widgets/entry-detail/config.js +8 -1
- package/plugins/runtime-modules/core/widgets/entry-header/config.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/entry-header/config.js +8 -1
- package/plugins/runtime-modules/core/widgets/entry-list/client.d.ts +4 -1
- package/plugins/runtime-modules/core/widgets/entry-list/client.js +3 -2
- package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +392 -93
- package/plugins/runtime-modules/core/widgets/entry-list/config.js +21 -3
- package/plugins/runtime-modules/core/widgets/entry-list/server.js +2 -0
- package/plugins/runtime-modules/core/widgets/gallery/authoring.js +62 -10
- package/plugins/runtime-modules/core/widgets/gallery/client.d.ts +6 -1
- package/plugins/runtime-modules/core/widgets/gallery/client.js +7 -79
- package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +337 -144
- package/plugins/runtime-modules/core/widgets/gallery/config.js +52 -113
- package/plugins/runtime-modules/core/widgets/gallery/defaults.d.ts +15 -0
- package/plugins/runtime-modules/core/widgets/gallery/defaults.js +20 -0
- package/plugins/runtime-modules/core/widgets/image/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/image/config.d.ts +29 -4
- package/plugins/runtime-modules/core/widgets/image/config.js +19 -2
- package/plugins/runtime-modules/core/widgets/image/editor.js +1 -1
- package/plugins/runtime-modules/core/widgets/result/config.d.ts +25 -1
- package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +25 -1
- package/plugins/runtime-modules/core/widgets/table/config.d.ts +79 -3
- package/plugins/runtime-modules/core/widgets/tour-button/client.js +1 -1
- package/plugins/runtime-modules/revisions/presets.d.ts +53 -2
- package/plugins/runtime-modules/revisions/presets.js +16 -12
- package/plugins/runtime-modules/revisions/tour.d.ts +43 -0
- package/plugins/runtime-modules/revisions/tour.js +51 -0
- package/plugins/runtime-modules/theme/presets.d.ts +36 -4
- package/plugins/runtime-modules/theme/tour.d.ts +45 -11
- package/plugins/runtime-modules/theme/tour.js +39 -8
- package/plugins/runtime-modules/tour/controller/address.js +2 -2
- package/plugins/runtime-modules/tour/controller/client.js +43 -2
- package/plugins/runtime-modules/tour/controller/definition.js +2 -1
- package/server-helpers/cms-request.js +1 -0
- package/server-helpers/page-tour.d.ts +10 -3
- package/server-helpers/page-tour.js +25 -12
- package/types/cms-config.d.ts +3 -1
- package/types/cms-config.js +3 -3
- package/types/cms-plugins.d.ts +31 -4
- package/types/tour-controller.d.ts +10 -0
- package/types/tour-controller.js +13 -0
- package/types/tours.d.ts +27 -25
- package/types/tours.js +9 -23
- package/types/visual-anchors.d.ts +15 -0
- package/types/visual-anchors.js +12 -0
- package/types.d.ts +2 -0
- package/types.js +4 -1
|
@@ -1,2 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const PHI_REVISIONS_RUNTIME_MODULE_ROUTES: {
|
|
2
|
+
tour: {
|
|
3
|
+
readonly id: "@phis/ui/modules/revisions/revisions";
|
|
4
|
+
readonly version: 1;
|
|
5
|
+
readonly steps: readonly [{
|
|
6
|
+
readonly key: "history";
|
|
7
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:filters`;
|
|
8
|
+
readonly title: "Whose history";
|
|
9
|
+
readonly description: "Every save is kept as a revision. Kind chooses what the list shows: an Area's Shell, a Page, a Navigation or the Theme. Scope chooses which Page or which Navigation.";
|
|
10
|
+
readonly placement: "bottom";
|
|
11
|
+
readonly ifMissing: "skip";
|
|
12
|
+
}, {
|
|
13
|
+
readonly key: "list";
|
|
14
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:header`;
|
|
15
|
+
readonly title: "One row per revision";
|
|
16
|
+
readonly description: "Newest first, with when it was saved, by whom and what changed. The tags say which revision is live and which is the draft being worked on; those two cannot be deleted.";
|
|
17
|
+
readonly placement: "bottom";
|
|
18
|
+
}, {
|
|
19
|
+
readonly key: "answer";
|
|
20
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:row-actions`;
|
|
21
|
+
readonly title: "Looking back and going back";
|
|
22
|
+
readonly description: "Review opens the revision as it was, in a new tab. Restore makes a new draft from it: nothing live changes until that draft is published. Delete removes a revision for good; selected rows can be deleted together.";
|
|
23
|
+
readonly placement: "left";
|
|
24
|
+
readonly ifMissing: "skip";
|
|
25
|
+
}, {
|
|
26
|
+
readonly key: "reset";
|
|
27
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:toolbar`;
|
|
28
|
+
readonly title: "Back to the preset";
|
|
29
|
+
readonly description: "A Page a Module brings can go back to that Module's version. Every revision the Site stored for it goes with it, so this is offered only while a Page's history is shown.";
|
|
30
|
+
readonly placement: "bottom";
|
|
31
|
+
readonly ifMissing: "skip";
|
|
32
|
+
}, {
|
|
33
|
+
readonly key: "delete-area";
|
|
34
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
35
|
+
readonly title: "Deleting an Area";
|
|
36
|
+
readonly description: "Clears everything the Site stored for an Area's Shell and Module selection, live included, and leaves no revision to restore. The Area keeps its Pages, its Navigation and its Theme. It asks for the Area's key before it does anything.";
|
|
37
|
+
readonly placement: "bottom";
|
|
38
|
+
}];
|
|
39
|
+
};
|
|
40
|
+
ownerModuleId: import("../contracts").PhiRuntimeModuleId;
|
|
41
|
+
presetKey: string;
|
|
42
|
+
presetVersion: number;
|
|
43
|
+
area: import("@phis/contracts/cms").PhiCmsAreaKey;
|
|
44
|
+
path: string;
|
|
45
|
+
landingPage?: true;
|
|
46
|
+
title: string;
|
|
47
|
+
defaultPageFlags?: number;
|
|
48
|
+
loadTree: (context: import("../../../types").PhiCmsDescriptorBuildContext & {
|
|
49
|
+
activeModuleIds: ReadonlySet<import("../contracts").PhiRuntimeModuleId>;
|
|
50
|
+
params: Readonly<Record<string, string>>;
|
|
51
|
+
}) => import("../../../types").PhiResolvedCmsPageTree | Promise<import("../../../types").PhiResolvedCmsPageTree>;
|
|
52
|
+
navigation?: readonly import("../../../types").PhiCmsNavigationInjectionDescriptor[];
|
|
53
|
+
}[];
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { buildPhiSidebarRoutePresetDescriptor } from "../sidebar-route";
|
|
2
2
|
import { PHI_REVISIONS_RUNTIME_MODULE_ID } from "./ids";
|
|
3
|
+
import { PHI_REVISIONS_TOUR } from "./tour";
|
|
3
4
|
export const PHI_REVISIONS_RUNTIME_MODULE_ROUTES = [
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
{
|
|
6
|
+
...buildPhiSidebarRoutePresetDescriptor({
|
|
7
|
+
area: "builder",
|
|
8
|
+
anchor: "main",
|
|
9
|
+
ownerModuleId: PHI_REVISIONS_RUNTIME_MODULE_ID,
|
|
10
|
+
presetKey: "builder-revisions-page",
|
|
11
|
+
title: "Revisions",
|
|
12
|
+
path: "/revisions",
|
|
13
|
+
itemKey: "@phis/ui/modules/revisions/nav/builder/revisions",
|
|
14
|
+
icon: "antd:history",
|
|
15
|
+
loadTree: ({ page, runtime }) => import("./trees/phi-default-builder-revisions-page-tree")
|
|
16
|
+
.then((module) => module.buildPhiDefaultBuilderRevisionsPageTree({ page, runtime })),
|
|
17
|
+
}),
|
|
18
|
+
tour: PHI_REVISIONS_TOUR,
|
|
19
|
+
},
|
|
16
20
|
];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Revisions Tour. What the Page does not say is that every save is kept, that going back never
|
|
3
|
+
* touches what is live -- a restored revision is a new draft -- and that the one act here that cannot be
|
|
4
|
+
* taken back stands apart from the rest.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PHI_REVISIONS_TOUR: {
|
|
7
|
+
readonly id: "@phis/ui/modules/revisions/revisions";
|
|
8
|
+
readonly version: 1;
|
|
9
|
+
readonly steps: readonly [{
|
|
10
|
+
readonly key: "history";
|
|
11
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:filters`;
|
|
12
|
+
readonly title: "Whose history";
|
|
13
|
+
readonly description: "Every save is kept as a revision. Kind chooses what the list shows: an Area's Shell, a Page, a Navigation or the Theme. Scope chooses which Page or which Navigation.";
|
|
14
|
+
readonly placement: "bottom";
|
|
15
|
+
readonly ifMissing: "skip";
|
|
16
|
+
}, {
|
|
17
|
+
readonly key: "list";
|
|
18
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:header`;
|
|
19
|
+
readonly title: "One row per revision";
|
|
20
|
+
readonly description: "Newest first, with when it was saved, by whom and what changed. The tags say which revision is live and which is the draft being worked on; those two cannot be deleted.";
|
|
21
|
+
readonly placement: "bottom";
|
|
22
|
+
}, {
|
|
23
|
+
readonly key: "answer";
|
|
24
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:row-actions`;
|
|
25
|
+
readonly title: "Looking back and going back";
|
|
26
|
+
readonly description: "Review opens the revision as it was, in a new tab. Restore makes a new draft from it: nothing live changes until that draft is published. Delete removes a revision for good; selected rows can be deleted together.";
|
|
27
|
+
readonly placement: "left";
|
|
28
|
+
readonly ifMissing: "skip";
|
|
29
|
+
}, {
|
|
30
|
+
readonly key: "reset";
|
|
31
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}:toolbar`;
|
|
32
|
+
readonly title: "Back to the preset";
|
|
33
|
+
readonly description: "A Page a Module brings can go back to that Module's version. Every revision the Site stored for it goes with it, so this is offered only while a Page's history is shown.";
|
|
34
|
+
readonly placement: "bottom";
|
|
35
|
+
readonly ifMissing: "skip";
|
|
36
|
+
}, {
|
|
37
|
+
readonly key: "delete-area";
|
|
38
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
39
|
+
readonly title: "Deleting an Area";
|
|
40
|
+
readonly description: "Clears everything the Site stored for an Area's Shell and Module selection, live included, and leaves no revision to restore. The Area keeps its Pages, its Navigation and its Theme. It asks for the Area's key before it does anything.";
|
|
41
|
+
readonly placement: "bottom";
|
|
42
|
+
}];
|
|
43
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PHI_REVISIONS_RUNTIME_MODULE_ID } from "./ids";
|
|
2
|
+
import { PHI_REVISIONS_PAGE_WIDGET_IDS, PHI_REVISIONS_TABLE_WIDGET_ID } from "./page-ids";
|
|
3
|
+
/**
|
|
4
|
+
* The Revisions Tour. What the Page does not say is that every save is kept, that going back never
|
|
5
|
+
* touches what is live -- a restored revision is a new draft -- and that the one act here that cannot be
|
|
6
|
+
* taken back stands apart from the rest.
|
|
7
|
+
*/
|
|
8
|
+
export const PHI_REVISIONS_TOUR = {
|
|
9
|
+
id: `${PHI_REVISIONS_RUNTIME_MODULE_ID}/revisions`,
|
|
10
|
+
version: 1,
|
|
11
|
+
steps: [
|
|
12
|
+
{
|
|
13
|
+
key: "history",
|
|
14
|
+
target: `cms:${PHI_REVISIONS_TABLE_WIDGET_ID}:filters`,
|
|
15
|
+
title: "Whose history",
|
|
16
|
+
description: "Every save is kept as a revision. Kind chooses what the list shows: an Area's Shell, a Page, a Navigation or the Theme. Scope chooses which Page or which Navigation.",
|
|
17
|
+
placement: "bottom",
|
|
18
|
+
ifMissing: "skip",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: "list",
|
|
22
|
+
target: `cms:${PHI_REVISIONS_TABLE_WIDGET_ID}:header`,
|
|
23
|
+
title: "One row per revision",
|
|
24
|
+
description: "Newest first, with when it was saved, by whom and what changed. The tags say which revision is live and which is the draft being worked on; those two cannot be deleted.",
|
|
25
|
+
placement: "bottom",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "answer",
|
|
29
|
+
target: `cms:${PHI_REVISIONS_TABLE_WIDGET_ID}:row-actions`,
|
|
30
|
+
title: "Looking back and going back",
|
|
31
|
+
description: "Review opens the revision as it was, in a new tab. Restore makes a new draft from it: nothing live changes until that draft is published. Delete removes a revision for good; selected rows can be deleted together.",
|
|
32
|
+
placement: "left",
|
|
33
|
+
ifMissing: "skip",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: "reset",
|
|
37
|
+
target: `cms:${PHI_REVISIONS_TABLE_WIDGET_ID}:toolbar`,
|
|
38
|
+
title: "Back to the preset",
|
|
39
|
+
description: "A Page a Module brings can go back to that Module's version. Every revision the Site stored for it goes with it, so this is offered only while a Page's history is shown.",
|
|
40
|
+
placement: "bottom",
|
|
41
|
+
ifMissing: "skip",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
key: "delete-area",
|
|
45
|
+
target: `cms:${PHI_REVISIONS_PAGE_WIDGET_IDS.widgetRevisionsAreaShellDelete}`,
|
|
46
|
+
title: "Deleting an Area",
|
|
47
|
+
description: "Clears everything the Site stored for an Area's Shell and Module selection, live included, and leaves no revision to restore. The Area keeps its Pages, its Navigation and its Theme. It asks for the Area's key before it does anything.",
|
|
48
|
+
placement: "bottom",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
@@ -5,15 +5,47 @@ export declare const PHI_THEME_RUNTIME_MODULE_ROUTES: {
|
|
|
5
5
|
readonly steps: readonly [{
|
|
6
6
|
readonly key: "theme-choice";
|
|
7
7
|
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
8
|
-
readonly title: "
|
|
9
|
-
readonly description: "The Site's published theme, its draft, or a theme a Module brings.
|
|
8
|
+
readonly title: "What your draft starts from";
|
|
9
|
+
readonly description: "The Site's published theme, its draft, or a theme a Module brings. Picking one makes it the base of your theme draft; the Module's theme itself stays as it is.";
|
|
10
10
|
readonly placement: "bottom";
|
|
11
11
|
}, {
|
|
12
12
|
readonly key: "theme-parts";
|
|
13
13
|
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
14
|
-
readonly title: "
|
|
15
|
-
readonly description: "
|
|
14
|
+
readonly title: "Four parts of the theme";
|
|
15
|
+
readonly description: "Colour, style, background and brand: each opens its own controls on the left, with the preview beside them.";
|
|
16
16
|
readonly placement: "bottom";
|
|
17
|
+
}, {
|
|
18
|
+
readonly key: string;
|
|
19
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
20
|
+
readonly title: string;
|
|
21
|
+
readonly description: string;
|
|
22
|
+
readonly placement: "right";
|
|
23
|
+
readonly prepare: readonly [import("../../../types").PhiTourStepSignal];
|
|
24
|
+
readonly release: readonly [import("../../../types").PhiTourStepSignal];
|
|
25
|
+
}, {
|
|
26
|
+
readonly key: string;
|
|
27
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
28
|
+
readonly title: string;
|
|
29
|
+
readonly description: string;
|
|
30
|
+
readonly placement: "right";
|
|
31
|
+
readonly prepare: readonly [import("../../../types").PhiTourStepSignal];
|
|
32
|
+
readonly release: readonly [import("../../../types").PhiTourStepSignal];
|
|
33
|
+
}, {
|
|
34
|
+
readonly key: string;
|
|
35
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
36
|
+
readonly title: string;
|
|
37
|
+
readonly description: string;
|
|
38
|
+
readonly placement: "right";
|
|
39
|
+
readonly prepare: readonly [import("../../../types").PhiTourStepSignal];
|
|
40
|
+
readonly release: readonly [import("../../../types").PhiTourStepSignal];
|
|
41
|
+
}, {
|
|
42
|
+
readonly key: string;
|
|
43
|
+
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
44
|
+
readonly title: string;
|
|
45
|
+
readonly description: string;
|
|
46
|
+
readonly placement: "right";
|
|
47
|
+
readonly prepare: readonly [import("../../../types").PhiTourStepSignal];
|
|
48
|
+
readonly release: readonly [import("../../../types").PhiTourStepSignal];
|
|
17
49
|
}, {
|
|
18
50
|
readonly key: "preview-mode";
|
|
19
51
|
readonly target: `cms:${import("@phis/contracts/cms").PhiCmsInstanceId}`;
|
|
@@ -1,34 +1,68 @@
|
|
|
1
|
+
import type { PhiCmsInstanceId } from "../../../types/cms-instance-id";
|
|
2
|
+
import type { PhiTourStepSignal } from "../../../types/tours";
|
|
1
3
|
/**
|
|
2
4
|
* The Theme workspace's Tour (TODOS.md, "A Tour for the Theme workspace").
|
|
3
5
|
*
|
|
4
|
-
* What the workspace does not say out loud is its first step:
|
|
5
|
-
*
|
|
6
|
-
* rest is the order a person meets the workspace in.
|
|
6
|
+
* What the workspace does not say out loud is its first step: the selector picks what a draft starts
|
|
7
|
+
* from. A Module's Theme is a base to start from, never edited through it, and installing a package
|
|
8
|
+
* that ships a look changes nothing for the Site. The rest is the order a person meets the workspace in.
|
|
7
9
|
*/
|
|
8
10
|
export declare const PHI_THEME_WORKSPACE_TOUR: {
|
|
9
11
|
readonly id: "@phis/ui/modules/theme/workspace";
|
|
10
12
|
readonly version: 1;
|
|
11
13
|
readonly steps: readonly [{
|
|
12
14
|
readonly key: "theme-choice";
|
|
13
|
-
readonly target: `cms:${
|
|
14
|
-
readonly title: "
|
|
15
|
-
readonly description: "The Site's published theme, its draft, or a theme a Module brings.
|
|
15
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
16
|
+
readonly title: "What your draft starts from";
|
|
17
|
+
readonly description: "The Site's published theme, its draft, or a theme a Module brings. Picking one makes it the base of your theme draft; the Module's theme itself stays as it is.";
|
|
16
18
|
readonly placement: "bottom";
|
|
17
19
|
}, {
|
|
18
20
|
readonly key: "theme-parts";
|
|
19
|
-
readonly target: `cms:${
|
|
20
|
-
readonly title: "
|
|
21
|
-
readonly description: "
|
|
21
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
22
|
+
readonly title: "Four parts of the theme";
|
|
23
|
+
readonly description: "Colour, style, background and brand: each opens its own controls on the left, with the preview beside them.";
|
|
22
24
|
readonly placement: "bottom";
|
|
25
|
+
}, {
|
|
26
|
+
readonly key: string;
|
|
27
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
28
|
+
readonly title: string;
|
|
29
|
+
readonly description: string;
|
|
30
|
+
readonly placement: "right";
|
|
31
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
32
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
33
|
+
}, {
|
|
34
|
+
readonly key: string;
|
|
35
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
36
|
+
readonly title: string;
|
|
37
|
+
readonly description: string;
|
|
38
|
+
readonly placement: "right";
|
|
39
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
40
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
41
|
+
}, {
|
|
42
|
+
readonly key: string;
|
|
43
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
44
|
+
readonly title: string;
|
|
45
|
+
readonly description: string;
|
|
46
|
+
readonly placement: "right";
|
|
47
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
48
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
49
|
+
}, {
|
|
50
|
+
readonly key: string;
|
|
51
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
52
|
+
readonly title: string;
|
|
53
|
+
readonly description: string;
|
|
54
|
+
readonly placement: "right";
|
|
55
|
+
readonly prepare: readonly [PhiTourStepSignal];
|
|
56
|
+
readonly release: readonly [PhiTourStepSignal];
|
|
23
57
|
}, {
|
|
24
58
|
readonly key: "preview-mode";
|
|
25
|
-
readonly target: `cms:${
|
|
59
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
26
60
|
readonly title: "Light and dark";
|
|
27
61
|
readonly description: "See the theme in either mode. This switches the preview, not the Site.";
|
|
28
62
|
readonly placement: "bottom";
|
|
29
63
|
}, {
|
|
30
64
|
readonly key: "draft-status";
|
|
31
|
-
readonly target: `cms:${
|
|
65
|
+
readonly target: `cms:${PhiCmsInstanceId}`;
|
|
32
66
|
readonly title: "Where your changes stand";
|
|
33
67
|
readonly description: "What you change here is a draft. The Site keeps its published theme until the draft is published.";
|
|
34
68
|
readonly placement: "bottom";
|
|
@@ -1,11 +1,38 @@
|
|
|
1
|
+
import { PHI_CMS_SEQUENTIAL_LAYOUT_SLOTS } from "../../../constants/cms-layout-types";
|
|
1
2
|
import { PHI_THEME_RUNTIME_MODULE_ID } from "./ids";
|
|
2
|
-
import { PHI_THEME_PAGE_WIDGET_IDS } from "./page-ids";
|
|
3
|
+
import { PHI_THEME_PAGE_LAYOUT_IDS, PHI_THEME_PAGE_WIDGET_IDS } from "./page-ids";
|
|
4
|
+
/** Turns the workspace's Stack to one of its four panels, as the Segmented above it does. */
|
|
5
|
+
function showPanel(slot) {
|
|
6
|
+
return {
|
|
7
|
+
receiver: `cms:${PHI_THEME_PAGE_LAYOUT_IDS.layoutBrandStack}`,
|
|
8
|
+
channel: "activeSlotKey",
|
|
9
|
+
action: "change",
|
|
10
|
+
valueType: "string",
|
|
11
|
+
value: PHI_CMS_SEQUENTIAL_LAYOUT_SLOTS[slot].key,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One panel of the workspace, pointed at by its controls. The step turns the Stack to the panel and back
|
|
16
|
+
* to Color when it is left, the panel the workspace opens with; from one panel step to the next both
|
|
17
|
+
* arrive together, so the Stack simply moves on.
|
|
18
|
+
*/
|
|
19
|
+
function panelStep(key, slot, controls, title, description) {
|
|
20
|
+
return {
|
|
21
|
+
key,
|
|
22
|
+
target: `cms:${controls}`,
|
|
23
|
+
title,
|
|
24
|
+
description,
|
|
25
|
+
placement: "right",
|
|
26
|
+
prepare: [showPanel(slot)],
|
|
27
|
+
release: [showPanel(0)],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
3
30
|
/**
|
|
4
31
|
* The Theme workspace's Tour (TODOS.md, "A Tour for the Theme workspace").
|
|
5
32
|
*
|
|
6
|
-
* What the workspace does not say out loud is its first step:
|
|
7
|
-
*
|
|
8
|
-
* rest is the order a person meets the workspace in.
|
|
33
|
+
* What the workspace does not say out loud is its first step: the selector picks what a draft starts
|
|
34
|
+
* from. A Module's Theme is a base to start from, never edited through it, and installing a package
|
|
35
|
+
* that ships a look changes nothing for the Site. The rest is the order a person meets the workspace in.
|
|
9
36
|
*/
|
|
10
37
|
export const PHI_THEME_WORKSPACE_TOUR = {
|
|
11
38
|
id: `${PHI_THEME_RUNTIME_MODULE_ID}/workspace`,
|
|
@@ -14,17 +41,21 @@ export const PHI_THEME_WORKSPACE_TOUR = {
|
|
|
14
41
|
{
|
|
15
42
|
key: "theme-choice",
|
|
16
43
|
target: `cms:${PHI_THEME_PAGE_WIDGET_IDS.widgetBrandContextSelect}`,
|
|
17
|
-
title: "
|
|
18
|
-
description: "The Site's published theme, its draft, or a theme a Module brings.
|
|
44
|
+
title: "What your draft starts from",
|
|
45
|
+
description: "The Site's published theme, its draft, or a theme a Module brings. Picking one makes it the base of your theme draft; the Module's theme itself stays as it is.",
|
|
19
46
|
placement: "bottom",
|
|
20
47
|
},
|
|
21
48
|
{
|
|
22
49
|
key: "theme-parts",
|
|
23
50
|
target: `cms:${PHI_THEME_PAGE_WIDGET_IDS.widgetThemeStackSegmented}`,
|
|
24
|
-
title: "
|
|
25
|
-
description: "
|
|
51
|
+
title: "Four parts of the theme",
|
|
52
|
+
description: "Colour, style, background and brand: each opens its own controls on the left, with the preview beside them.",
|
|
26
53
|
placement: "bottom",
|
|
27
54
|
},
|
|
55
|
+
panelStep("color", 0, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandThemeControls, "Colour from a few seeds", "A palette is picked whole, or each colour is set on its own. Every colour is a seed: Primary, Info, Success, Warning, Error, Link, the text and the background each grow into the shades for hover, borders and backgrounds, and Custom grows into ten steps of its own."),
|
|
56
|
+
panelStep("style", 1, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandStyleControls, "Buttons and corners", "A shape sets the corners at once -- square, subtle, rounded or pill -- for buttons and fields alike. Below it the details: the buttons' shadows, the corner radius in three sizes, how tall controls are, and the fonts and their size."),
|
|
57
|
+
panelStep("background", 2, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandBackgroundControls, "Behind everything", "The root background is one layer behind the whole Site: a colour, a gradient or an image, still or in parallax, with an overlay of colour, pattern or noise on top. The chrome overlay is a second ground the header, the sider and the footer share, and the chrome shadow sets how they cast onto the Page. Each is set for light and dark."),
|
|
58
|
+
panelStep("brand", 3, PHI_THEME_PAGE_WIDGET_IDS.widgetBrandIdentityControls, "The Site's own marks", "The logo, one per mode, and where a click on it leads; the wordmark, the Site's name in type; and the two short lines the Brand shows beside them."),
|
|
28
59
|
{
|
|
29
60
|
key: "preview-mode",
|
|
30
61
|
target: `cms:${PHI_THEME_PAGE_WIDGET_IDS.widgetBrandPreviewModeSwitch}`,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { PHI_TOUR_CONTROLLER_KEY, PHI_TOUR_CONTROLLER_PLUGIN_KEY } from "../../../../types/
|
|
2
|
-
// The Controller's address is the foundation's (`types/
|
|
1
|
+
import { PHI_TOUR_CONTROLLER_KEY, PHI_TOUR_CONTROLLER_PLUGIN_KEY } from "../../../../types/tour-controller";
|
|
2
|
+
// The Controller's address is the foundation's (`types/tour-controller.ts`): the Tour button, which is Core's, asks it.
|
|
3
3
|
export const PHI_TOUR_CONTROLLER_TYPE = `${PHI_TOUR_CONTROLLER_PLUGIN_KEY}/${PHI_TOUR_CONTROLLER_KEY}`;
|
|
@@ -3,16 +3,19 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { PHI_SIGNAL_VALUE_SCHEMAS } from "../../../../types/signals";
|
|
5
5
|
import { PhiTourControl } from "../../../../components/controls/phi-tour-control";
|
|
6
|
+
import { holdPhiTourViewport, releasePhiTourViewport } from "../../../../components/controls/phi-tour-viewport";
|
|
6
7
|
import { createPhiRuntimeControllerClient } from "../../../../components/runtime/runtime-controller-client-factory";
|
|
7
8
|
import { usePhiSignalDispatcher, usePhiSignalListener } from "../../../../components/runtime/runtime-signal-bus";
|
|
8
9
|
import { usePhiSignalRuntimePartition } from "../../../../components/runtime/runtime-signal-partition";
|
|
9
|
-
import { readPhiVisualAnchor, waitForPhiVisualAnchor } from "../../../../components/runtime/runtime-visual-anchors";
|
|
10
|
+
import { readPhiVisualAnchor, waitForPhiVisualAnchor, waitForPhiVisualAnchorToSettle, } from "../../../../components/runtime/runtime-visual-anchors";
|
|
10
11
|
import { fetchPhiUserState, writePhiUserState } from "../../../../components/runtime/user-state-client";
|
|
11
12
|
import { PHI_TOUR_PROGRESS_USER_STATE_KEY } from "../ids";
|
|
12
13
|
import { PHI_TOUR_RUNTIME_CONTROLLER_DEFINITION } from "./definition";
|
|
13
14
|
import { readPhiTourProgress, recordPhiTourProgress, shouldOfferPhiTour, } from "./progress";
|
|
14
15
|
/** How long a step waits for its target before its `ifMissing` decides. */
|
|
15
16
|
const TARGET_WAIT_MS = 4000;
|
|
17
|
+
/** How long a found target may keep moving before it is pointed at where it stands. */
|
|
18
|
+
const TARGET_SETTLE_MS = 1000;
|
|
16
19
|
const PROGRESS_DESCRIPTOR = {
|
|
17
20
|
key: PHI_TOUR_PROGRESS_USER_STATE_KEY,
|
|
18
21
|
shape: "value",
|
|
@@ -115,6 +118,31 @@ function PhiTourControllerView({ address, config }) {
|
|
|
115
118
|
* never pointed at anything but its own address in this partition.
|
|
116
119
|
*/
|
|
117
120
|
const step = run ? run.tour.steps[run.index] ?? null : null;
|
|
121
|
+
const send = useCallback((signals) => {
|
|
122
|
+
for (const signal of signals ?? []) {
|
|
123
|
+
dispatchSignal({
|
|
124
|
+
scope: "area",
|
|
125
|
+
channel: signal.channel,
|
|
126
|
+
action: signal.action,
|
|
127
|
+
value: signal.value ?? null,
|
|
128
|
+
valueType: signal.valueType,
|
|
129
|
+
...(signal.valueSchema ? { valueSchema: signal.valueSchema } : {}),
|
|
130
|
+
sender: address,
|
|
131
|
+
receiver: signal.receiver,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}, [address, dispatchSignal]);
|
|
135
|
+
/*
|
|
136
|
+
* The step asked for gets its `prepare` before its target is waited for, and its `release` the moment it
|
|
137
|
+
* is no longer the one asked for -- the next step, a step passed over, the Tour closed or finished, the
|
|
138
|
+
* Page left. One effect per step, so every prepare is answered by exactly one release.
|
|
139
|
+
*/
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!step)
|
|
142
|
+
return undefined;
|
|
143
|
+
send(step.prepare);
|
|
144
|
+
return () => send(step.release);
|
|
145
|
+
}, [send, step]);
|
|
118
146
|
// A step centered on purpose has nothing to wait for.
|
|
119
147
|
const presented = run && step?.target == null ? run.index : run?.presented ?? null;
|
|
120
148
|
useEffect(() => {
|
|
@@ -122,10 +150,16 @@ function PhiTourControllerView({ address, config }) {
|
|
|
122
150
|
return undefined;
|
|
123
151
|
const abort = new AbortController();
|
|
124
152
|
void waitForPhiVisualAnchor(partition, step.target, { timeoutMs: TARGET_WAIT_MS, signal: abort.signal })
|
|
125
|
-
.then((element) => {
|
|
153
|
+
.then(async (element) => {
|
|
126
154
|
if (abort.signal.aborted)
|
|
127
155
|
return;
|
|
128
156
|
if (element) {
|
|
157
|
+
// Pointed at once it stands still: a target a `prepare` just opened is often still moving in.
|
|
158
|
+
await waitForPhiVisualAnchorToSettle(element, { timeoutMs: TARGET_SETTLE_MS, signal: abort.signal });
|
|
159
|
+
if (abort.signal.aborted)
|
|
160
|
+
return;
|
|
161
|
+
// Scrolled to below the sticky bands, once the step is presented (`phi-tour-viewport.ts`).
|
|
162
|
+
holdPhiTourViewport(element);
|
|
129
163
|
setRun({ ...run, presented: run.index });
|
|
130
164
|
return;
|
|
131
165
|
}
|
|
@@ -136,6 +170,13 @@ function PhiTourControllerView({ address, config }) {
|
|
|
136
170
|
});
|
|
137
171
|
return () => abort.abort();
|
|
138
172
|
}, [partition, run, step]);
|
|
173
|
+
// The window's scroll padding is the Tour's only while a Tour runs.
|
|
174
|
+
const running = run != null;
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (!running)
|
|
177
|
+
return undefined;
|
|
178
|
+
return releasePhiTourViewport;
|
|
179
|
+
}, [running]);
|
|
139
180
|
const steps = useMemo(() => (run?.tour.steps ?? []).map((definition) => ({
|
|
140
181
|
key: definition.key,
|
|
141
182
|
title: definition.title,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PHI_SIGNAL_VALUE_SCHEMAS } from "../../../../types/signals";
|
|
2
|
-
import {
|
|
2
|
+
import { PHI_TOUR_CONTROLLER_KEY, PHI_TOUR_CONTROLLER_PLUGIN_KEY } from "../../../../types/tour-controller";
|
|
3
|
+
import { PHI_PAGE_TOUR_CONFIG_KEY, PHI_PAGE_TOUR_CONTROLLER_FLAG, readPhiResolvedPageTour, } from "../../../../types/tours";
|
|
3
4
|
/**
|
|
4
5
|
* Runs the Tour of whichever Page is shown (design/TOURS.md).
|
|
5
6
|
*
|
|
@@ -320,6 +320,7 @@ export async function resolvePhiCmsRequest({ siteKey, locale, area, path, cookie
|
|
|
320
320
|
pageTour: routeTour
|
|
321
321
|
? {
|
|
322
322
|
definition: routeTour,
|
|
323
|
+
ownerModuleId: routeBinding.descriptor.ownerModuleId,
|
|
323
324
|
sourceLocale: catalog.sourceLocaleByModuleId.get(routeBinding.descriptor.ownerModuleId),
|
|
324
325
|
}
|
|
325
326
|
: null,
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
+
import type { PhiRuntimeModuleId } from "../types/cms-module-descriptors";
|
|
2
3
|
import type { PhiResolvedPageTour, PhiTourDefinition } from "../types/tours";
|
|
3
4
|
/**
|
|
4
|
-
* A Page's Tour in the viewer's language: every step's words translated
|
|
5
|
-
*
|
|
5
|
+
* A Page's Tour in the viewer's language: every step's words translated, and the step buttons from Core's
|
|
6
|
+
* label set. Addresses, keys and step signals are not words and pass through.
|
|
7
|
+
*
|
|
8
|
+
* Where the words are kept depends on who wrote them. A built-in Tour's text is this package's, the same
|
|
9
|
+
* on every Site, so it is translated once in the global set. A third-party Module's Tour is translated per
|
|
10
|
+
* Site from the language that Module writes in, where the Site's own corrections apply. Either way the
|
|
11
|
+
* Tour's id is the context, so a translator sees which Tour a sentence belongs to.
|
|
6
12
|
*/
|
|
7
|
-
export declare function resolvePhiPageTour({ definition, sourceLocale, locale, }: {
|
|
13
|
+
export declare function resolvePhiPageTour({ definition, ownerModuleId, sourceLocale, locale, }: {
|
|
8
14
|
definition: PhiTourDefinition;
|
|
15
|
+
ownerModuleId: PhiRuntimeModuleId;
|
|
9
16
|
sourceLocale?: string;
|
|
10
17
|
locale: string;
|
|
11
18
|
}): Promise<PhiResolvedPageTour>;
|
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
import { getPhiTourWidgetLabels } from "../components/widgets/label-sets/tour";
|
|
3
|
+
import { PHI_SHARED_PACKAGE_NAME } from "../constants/package";
|
|
3
4
|
import { readPhiServerApiCredentials } from "../helpers/phis-server-credentials";
|
|
4
|
-
import {
|
|
5
|
+
import { trBulkForLocale, trGlobalBulkForLocale } from "./translate";
|
|
6
|
+
/** A Tour this package ships, whose words are the same on every Site. */
|
|
7
|
+
function isPhiBuiltInTour(ownerModuleId) {
|
|
8
|
+
return ownerModuleId.startsWith(`${PHI_SHARED_PACKAGE_NAME}/`);
|
|
9
|
+
}
|
|
5
10
|
/**
|
|
6
|
-
* A Page's Tour in the viewer's language: every step's words translated
|
|
7
|
-
*
|
|
11
|
+
* A Page's Tour in the viewer's language: every step's words translated, and the step buttons from Core's
|
|
12
|
+
* label set. Addresses, keys and step signals are not words and pass through.
|
|
13
|
+
*
|
|
14
|
+
* Where the words are kept depends on who wrote them. A built-in Tour's text is this package's, the same
|
|
15
|
+
* on every Site, so it is translated once in the global set. A third-party Module's Tour is translated per
|
|
16
|
+
* Site from the language that Module writes in, where the Site's own corrections apply. Either way the
|
|
17
|
+
* Tour's id is the context, so a translator sees which Tour a sentence belongs to.
|
|
8
18
|
*/
|
|
9
|
-
export async function resolvePhiPageTour({ definition, sourceLocale, locale, }) {
|
|
10
|
-
const
|
|
19
|
+
export async function resolvePhiPageTour({ definition, ownerModuleId, sourceLocale, locale, }) {
|
|
20
|
+
const texts = definition.steps.flatMap((step) => [step.title, step.description ?? ""]);
|
|
21
|
+
const translate = isPhiBuiltInTour(ownerModuleId)
|
|
22
|
+
? trGlobalBulkForLocale(locale, texts, definition.id)
|
|
23
|
+
: trBulkForLocale(locale, texts, definition.id, "text", sourceLocale);
|
|
11
24
|
const credentials = readPhiServerApiCredentials();
|
|
12
|
-
const [labels,
|
|
25
|
+
const [labels, translated] = await Promise.all([
|
|
13
26
|
getPhiTourWidgetLabels({ apiBaseUrl: credentials.apiBaseUrl, internalToken: credentials.internalToken, locale }),
|
|
14
|
-
|
|
15
|
-
...step,
|
|
16
|
-
title: await translate(step.title),
|
|
17
|
-
...(step.description ? { description: await translate(step.description) } : {}),
|
|
18
|
-
}))),
|
|
27
|
+
translate,
|
|
19
28
|
]);
|
|
20
29
|
return {
|
|
21
30
|
id: definition.id,
|
|
22
31
|
version: definition.version,
|
|
23
|
-
steps,
|
|
32
|
+
steps: definition.steps.map((step, index) => ({
|
|
33
|
+
...step,
|
|
34
|
+
title: translated[index * 2] ?? step.title,
|
|
35
|
+
...(step.description ? { description: translated[index * 2 + 1] ?? step.description } : {}),
|
|
36
|
+
})),
|
|
24
37
|
labels: { next: labels.next, previous: labels.previous, finish: labels.finish },
|
|
25
38
|
};
|
|
26
39
|
}
|
package/types/cms-config.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type PhiCssLength } from "./length";
|
|
|
6
6
|
import type { PhiResponsiveValue } from "./responsive";
|
|
7
7
|
import type { PhiRenderableBlockBase, PhiRenderableBlockAnchor, PhiRenderableBlockResponsiveSize } from "./renderable-block";
|
|
8
8
|
import type { PhiBaseLayoutSlotStates } from "../components/layouts/phi-layout-contract";
|
|
9
|
+
import { type PhiSpacingScaleKey } from "../components/widgets/config/spacing-options";
|
|
9
10
|
export type PhiCmsPluginConfigBase = Record<string, unknown>;
|
|
10
11
|
export type PhiCmsRenderableBlockConfigBase = PhiCmsPluginConfigBase & PhiRenderableBlockBase;
|
|
11
12
|
export type PhiCmsLayerBase = PhiCmsRenderableBlockConfigBase & {
|
|
@@ -120,7 +121,8 @@ export type PhiCmsCarouselLayoutConfig = PhiCmsLayerBase & {
|
|
|
120
121
|
transition?: PhiSequenceTransition;
|
|
121
122
|
transitionDurationMs?: number;
|
|
122
123
|
transitionEasing?: PhiMotionEasing;
|
|
123
|
-
|
|
124
|
+
/** A step of the spacing scale between the slots of a window. */
|
|
125
|
+
slotGap?: PhiSpacingScaleKey;
|
|
124
126
|
/** Which of its own controls the Carousel draws. Pager Widgets work regardless of this. */
|
|
125
127
|
controls?: "none" | "arrows" | "dots" | "both";
|
|
126
128
|
loop?: boolean;
|
package/types/cms-config.js
CHANGED
|
@@ -9,6 +9,7 @@ import { applyPhiLayoutDefaults } from "../helpers/cms-layout-defaults";
|
|
|
9
9
|
import { resolvePhiLayoutDefaults } from "../helpers/cms-layout-defaults";
|
|
10
10
|
import { normalizeRenderableBlockAnchor } from "../helpers/renderable-block-anchor";
|
|
11
11
|
import { isPhiRecord } from "../helpers/is-record";
|
|
12
|
+
import { PHI_SPACING_SCALE_KEYS } from "../components/widgets/config/spacing-options";
|
|
12
13
|
import { PHI_GRID_COLUMN_COUNTS, isPhiGridColumnCount } from "../constants/grid-columns";
|
|
13
14
|
function readInitialSlotStates(value) {
|
|
14
15
|
if (Array.isArray(value)) {
|
|
@@ -334,6 +335,7 @@ export function parsePhiCmsCarouselLayoutConfig(config) {
|
|
|
334
335
|
const loop = readCarouselFlag(config.loop, "loop");
|
|
335
336
|
const autoplayMs = readCarouselCount(config.autoplayMs, "autoplayMs", 0);
|
|
336
337
|
const lookahead = readCarouselCount(config.lookahead, "lookahead", 0);
|
|
338
|
+
const slotGap = readCarouselMember(config.slotGap, PHI_SPACING_SCALE_KEYS, "slotGap");
|
|
337
339
|
return applyPhiLayoutDefaults({
|
|
338
340
|
...readRenderableBlockConfig(config),
|
|
339
341
|
labelEnd: readPhiLayoutLabelEnd(config.labelEnd),
|
|
@@ -342,15 +344,13 @@ export function parsePhiCmsCarouselLayoutConfig(config) {
|
|
|
342
344
|
...(visibleSlots === undefined ? {} : { visibleSlots }),
|
|
343
345
|
...(windowAnchor === undefined ? {} : { windowAnchor }),
|
|
344
346
|
...(transition === undefined ? {} : { transition }),
|
|
345
|
-
// Absent means "whatever the theme does", which is why nothing is written here rather than a
|
|
346
|
-
// number this parser invented.
|
|
347
347
|
...(config.transitionDurationMs === undefined || config.transitionDurationMs === null ? {} : {
|
|
348
348
|
transitionDurationMs: clampPhiSequenceTransitionMs(config.transitionDurationMs),
|
|
349
349
|
}),
|
|
350
350
|
...(config.transitionEasing === undefined ? {} : {
|
|
351
351
|
transitionEasing: readPhiMotionEasing(config.transitionEasing, undefined),
|
|
352
352
|
}),
|
|
353
|
-
slotGap:
|
|
353
|
+
...(slotGap === undefined ? {} : { slotGap }),
|
|
354
354
|
...(controls === undefined ? {} : { controls }),
|
|
355
355
|
...(loop === undefined ? {} : { loop }),
|
|
356
356
|
// Zero is how "does not move on its own" is written, so it is the one number below the floor
|