@cratis/scene.blueprint.default 4.12.0 → 4.14.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 +2 -2
- package/dist/cjs/gallery/GalleryScreenPreview.js +6 -3
- package/dist/cjs/gallery/GalleryScreenPreview.js.map +1 -1
- package/dist/cjs/gallery/TemplatePreviewState.js +17 -0
- package/dist/cjs/gallery/TemplatePreviewState.js.map +1 -0
- package/dist/cjs/gallery/applyTemplatePreviewState.js +91 -0
- package/dist/cjs/gallery/applyTemplatePreviewState.js.map +1 -0
- package/dist/cjs/gallery/authTemplates.js +25 -6
- package/dist/cjs/gallery/authTemplates.js.map +1 -1
- package/dist/cjs/gallery/dialogTemplates.js +13 -3
- package/dist/cjs/gallery/dialogTemplates.js.map +1 -1
- package/dist/cjs/gallery/navigation.js +7 -0
- package/dist/cjs/gallery/navigation.js.map +1 -1
- package/dist/cjs/gallery/nesting.js +13 -3
- package/dist/cjs/gallery/nesting.js.map +1 -1
- package/dist/cjs/gallery/screens.js +10 -1
- package/dist/cjs/gallery/screens.js.map +1 -1
- package/dist/cjs/gallery/statusTemplates.js +19 -5
- package/dist/cjs/gallery/statusTemplates.js.map +1 -1
- package/dist/cjs/gallery/supportTemplates.js +23 -6
- package/dist/cjs/gallery/supportTemplates.js.map +1 -1
- package/dist/cjs/gallery/widgets.js +20 -6
- package/dist/cjs/gallery/widgets.js.map +1 -1
- package/dist/cjs/gallery/workspaceTemplates.js +137 -8
- package/dist/cjs/gallery/workspaceTemplates.js.map +1 -1
- package/dist/cjs/index.js +10 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/layouts/appShell.js +5 -1
- package/dist/cjs/layouts/appShell.js.map +1 -1
- package/dist/cjs/layouts/fullPage.js +5 -1
- package/dist/cjs/layouts/fullPage.js.map +1 -1
- package/dist/cjs/templateProvenance.js +46 -0
- package/dist/cjs/templateProvenance.js.map +1 -0
- package/dist/esm/gallery/ApplicationScreens.stories.d.ts +1 -0
- package/dist/esm/gallery/ApplicationScreens.stories.d.ts.map +1 -1
- package/dist/esm/gallery/ApplicationScreens.stories.js +2 -1
- package/dist/esm/gallery/ApplicationScreens.stories.js.map +1 -1
- package/dist/esm/gallery/GalleryScreenPreview.d.ts +3 -1
- package/dist/esm/gallery/GalleryScreenPreview.d.ts.map +1 -1
- package/dist/esm/gallery/GalleryScreenPreview.js +6 -3
- package/dist/esm/gallery/GalleryScreenPreview.js.map +1 -1
- package/dist/esm/gallery/PreviewStates.stories.d.ts +36 -0
- package/dist/esm/gallery/PreviewStates.stories.d.ts.map +1 -0
- package/dist/esm/gallery/PreviewStates.stories.js +27 -0
- package/dist/esm/gallery/PreviewStates.stories.js.map +1 -0
- package/dist/esm/gallery/TemplatePreviewState.d.ts +7 -0
- package/dist/esm/gallery/TemplatePreviewState.d.ts.map +1 -0
- package/dist/esm/gallery/TemplatePreviewState.js +15 -0
- package/dist/esm/gallery/TemplatePreviewState.js.map +1 -0
- package/dist/esm/gallery/applyTemplatePreviewState.d.ts +6 -0
- package/dist/esm/gallery/applyTemplatePreviewState.d.ts.map +1 -0
- package/dist/esm/gallery/applyTemplatePreviewState.js +87 -0
- package/dist/esm/gallery/applyTemplatePreviewState.js.map +1 -0
- package/dist/esm/gallery/authTemplates.d.ts.map +1 -1
- package/dist/esm/gallery/authTemplates.js +25 -6
- package/dist/esm/gallery/authTemplates.js.map +1 -1
- package/dist/esm/gallery/dialogTemplates.d.ts.map +1 -1
- package/dist/esm/gallery/dialogTemplates.js +13 -3
- package/dist/esm/gallery/dialogTemplates.js.map +1 -1
- package/dist/esm/gallery/index.d.ts +2 -0
- package/dist/esm/gallery/index.d.ts.map +1 -1
- package/dist/esm/gallery/index.js +2 -0
- package/dist/esm/gallery/index.js.map +1 -1
- package/dist/esm/gallery/navigation.d.ts.map +1 -1
- package/dist/esm/gallery/navigation.js +7 -0
- package/dist/esm/gallery/navigation.js.map +1 -1
- package/dist/esm/gallery/nesting.d.ts.map +1 -1
- package/dist/esm/gallery/nesting.js +13 -3
- package/dist/esm/gallery/nesting.js.map +1 -1
- package/dist/esm/gallery/screens.d.ts.map +1 -1
- package/dist/esm/gallery/screens.js +10 -1
- package/dist/esm/gallery/screens.js.map +1 -1
- package/dist/esm/gallery/statusTemplates.d.ts.map +1 -1
- package/dist/esm/gallery/statusTemplates.js +19 -5
- package/dist/esm/gallery/statusTemplates.js.map +1 -1
- package/dist/esm/gallery/supportTemplates.d.ts.map +1 -1
- package/dist/esm/gallery/supportTemplates.js +23 -6
- package/dist/esm/gallery/supportTemplates.js.map +1 -1
- package/dist/esm/gallery/widgets.d.ts +1 -1
- package/dist/esm/gallery/widgets.d.ts.map +1 -1
- package/dist/esm/gallery/widgets.js +20 -6
- package/dist/esm/gallery/widgets.js.map +1 -1
- package/dist/esm/gallery/workspaceTemplates.d.ts +1 -0
- package/dist/esm/gallery/workspaceTemplates.d.ts.map +1 -1
- package/dist/esm/gallery/workspaceTemplates.js +139 -11
- package/dist/esm/gallery/workspaceTemplates.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/layouts/appShell.d.ts.map +1 -1
- package/dist/esm/layouts/appShell.js +5 -1
- package/dist/esm/layouts/appShell.js.map +1 -1
- package/dist/esm/layouts/fullPage.d.ts.map +1 -1
- package/dist/esm/layouts/fullPage.js +5 -1
- package/dist/esm/layouts/fullPage.js.map +1 -1
- package/dist/esm/templateProvenance.d.ts +4 -0
- package/dist/esm/templateProvenance.d.ts.map +1 -0
- package/dist/esm/templateProvenance.js +43 -0
- package/dist/esm/templateProvenance.js.map +1 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/gallery/ApplicationScreens.stories.tsx +4 -1
- package/gallery/GalleryScreenPreview.tsx +8 -3
- package/gallery/PreviewStates.stories.tsx +56 -0
- package/gallery/TemplatePreviewState.ts +20 -0
- package/gallery/applyTemplatePreviewState.ts +69 -0
- package/gallery/authTemplates.ts +7 -0
- package/gallery/dialogTemplates.ts +4 -0
- package/gallery/index.ts +2 -0
- package/gallery/navigation.ts +1 -0
- package/gallery/nesting.ts +4 -0
- package/gallery/screens.ts +2 -1
- package/gallery/statusTemplates.ts +6 -1
- package/gallery/supportTemplates.ts +7 -1
- package/gallery/widgets.ts +14 -5
- package/gallery/workspaceTemplates.ts +64 -4
- package/index.ts +1 -0
- package/layouts/appShell.ts +2 -0
- package/layouts/fullPage.ts +2 -0
- package/package.json +8 -7
- package/templateProvenance.ts +37 -0
|
@@ -19,7 +19,7 @@ const meta = {
|
|
|
19
19
|
layout: 'fullscreen',
|
|
20
20
|
docs: {
|
|
21
21
|
description: {
|
|
22
|
-
component: 'The
|
|
22
|
+
component: 'The eleven in-application screen templates plus the three-level nesting chain, each booted through the real engine as a screen.',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
25
|
},
|
|
@@ -36,6 +36,9 @@ export const Dashboard: Story = { args: { screenName: 'Dashboard' } };
|
|
|
36
36
|
/** A searchable product table with a header and a primary action. */
|
|
37
37
|
export const List: Story = { args: { screenName: 'CrudList' } };
|
|
38
38
|
|
|
39
|
+
/** A list beside the selected record, stacking on narrow screens. */
|
|
40
|
+
export const MasterDetail: Story = { args: { screenName: 'MasterDetail' } };
|
|
41
|
+
|
|
39
42
|
/** One record: header, sections and a summary panel. */
|
|
40
43
|
export const Detail: Story = { args: { screenName: 'DetailView' } };
|
|
41
44
|
|
|
@@ -11,6 +11,8 @@ import { composeScreenElement } from './composeScreen';
|
|
|
11
11
|
import { galleryComponentCatalog, galleryPreviewProfile } from './previewProfile';
|
|
12
12
|
import { resolveElementComponentNames } from './resolveElementNames';
|
|
13
13
|
import { galleryScreen } from './screens';
|
|
14
|
+
import { TemplatePreviewState } from './TemplatePreviewState';
|
|
15
|
+
import { applyTemplatePreviewState } from './applyTemplatePreviewState';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* The registry a preview resolves against when a host does not supply one: `core` plus this blueprint.
|
|
@@ -33,6 +35,9 @@ export interface GalleryScreenPreviewProps {
|
|
|
33
35
|
|
|
34
36
|
/** The component registry to render against. Defaults to `core` plus this blueprint's own components. */
|
|
35
37
|
registry?: ComponentRegistry;
|
|
38
|
+
|
|
39
|
+
/** The data state to show. Defaults to the seeded, populated records. */
|
|
40
|
+
state?: TemplatePreviewState;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
/**
|
|
@@ -48,15 +53,15 @@ export interface GalleryScreenPreviewProps {
|
|
|
48
53
|
* a preview of a blueprint against half a profile should look visibly incomplete rather than quietly
|
|
49
54
|
* wrong.
|
|
50
55
|
*/
|
|
51
|
-
export function GalleryScreenPreview({ screenName, initialConfig, themes = defaultBlueprintThemes, registry = galleryPreviewRegistry }: GalleryScreenPreviewProps) {
|
|
56
|
+
export function GalleryScreenPreview({ screenName, initialConfig, themes = defaultBlueprintThemes, registry = galleryPreviewRegistry, state = TemplatePreviewState.Populated }: GalleryScreenPreviewProps) {
|
|
52
57
|
const element = useMemo(() => {
|
|
53
58
|
const screen = galleryScreen(screenName);
|
|
54
59
|
if (!screen) {
|
|
55
60
|
throw new Error(`The gallery has no screen named '${screenName}'.`);
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
return resolveElementComponentNames(composeScreenElement(screen), galleryPreviewProfile, galleryComponentCatalog);
|
|
59
|
-
}, [screenName]);
|
|
63
|
+
return applyTemplatePreviewState(resolveElementComponentNames(composeScreenElement(screen), galleryPreviewProfile, galleryComponentCatalog), state);
|
|
64
|
+
}, [screenName, state]);
|
|
60
65
|
|
|
61
66
|
return (
|
|
62
67
|
<LayoutConfigProvider initialConfig={initialConfig} storage={null}>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
5
|
+
import { corePackage, mergePackageRegistries } from '@cratis/scene.react';
|
|
6
|
+
import { primeReactPackage } from '@cratis/scene.primereact';
|
|
7
|
+
import { defaultBlueprint } from '../defaultBlueprint';
|
|
8
|
+
import { GalleryScreenPreview } from './GalleryScreenPreview';
|
|
9
|
+
import { TemplatePreviewState } from './TemplatePreviewState';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The data templates in each data state, rendered against the packages the blueprint depends on - `core`,
|
|
13
|
+
* PrimeReact and the blueprint itself - so the tables are PrimeReact's own and each state is the table's own
|
|
14
|
+
* empty message, loading status or error alert rather than a placeholder.
|
|
15
|
+
*/
|
|
16
|
+
const registry = mergePackageRegistries([corePackage, primeReactPackage, defaultBlueprint]);
|
|
17
|
+
|
|
18
|
+
const meta = {
|
|
19
|
+
title: 'Blueprint/Preview states',
|
|
20
|
+
component: GalleryScreenPreview,
|
|
21
|
+
parameters: {
|
|
22
|
+
layout: 'fullscreen',
|
|
23
|
+
docs: { description: { component: 'Populated, empty, loading and error states of the data templates, through the real packages.' } },
|
|
24
|
+
},
|
|
25
|
+
args: { registry },
|
|
26
|
+
argTypes: { state: { control: 'select', options: Object.values(TemplatePreviewState) } },
|
|
27
|
+
tags: ['autodocs'],
|
|
28
|
+
} satisfies Meta<typeof GalleryScreenPreview>;
|
|
29
|
+
|
|
30
|
+
export default meta;
|
|
31
|
+
|
|
32
|
+
type Story = StoryObj<typeof meta>;
|
|
33
|
+
|
|
34
|
+
/** The list with its seeded products. */
|
|
35
|
+
export const ListPopulated: Story = { args: { screenName: 'CrudList', state: TemplatePreviewState.Populated } };
|
|
36
|
+
|
|
37
|
+
/** The list once the query returns nothing. */
|
|
38
|
+
export const ListEmpty: Story = { args: { screenName: 'CrudList', state: TemplatePreviewState.Empty } };
|
|
39
|
+
|
|
40
|
+
/** The list while the query has not answered. */
|
|
41
|
+
export const ListLoading: Story = { args: { screenName: 'CrudList', state: TemplatePreviewState.Loading } };
|
|
42
|
+
|
|
43
|
+
/** The list when the query failed. */
|
|
44
|
+
export const ListError: Story = { args: { screenName: 'CrudList', state: TemplatePreviewState.Error } };
|
|
45
|
+
|
|
46
|
+
/** Master/detail with its customers. */
|
|
47
|
+
export const MasterDetailPopulated: Story = { args: { screenName: 'MasterDetail', state: TemplatePreviewState.Populated } };
|
|
48
|
+
|
|
49
|
+
/** Master/detail while loading. */
|
|
50
|
+
export const MasterDetailLoading: Story = { args: { screenName: 'MasterDetail', state: TemplatePreviewState.Loading } };
|
|
51
|
+
|
|
52
|
+
/** The dashboard when its widgets' data failed to load. */
|
|
53
|
+
export const DashboardError: Story = { args: { screenName: 'Dashboard', state: TemplatePreviewState.Error } };
|
|
54
|
+
|
|
55
|
+
/** User administration with no users yet. */
|
|
56
|
+
export const UsersEmpty: Story = { args: { screenName: 'UserManagement', state: TemplatePreviewState.Empty } };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The data states a template preview can show. A template is only worth choosing if it looks right in all
|
|
6
|
+
* four, because an application spends real time in each of them.
|
|
7
|
+
*/
|
|
8
|
+
export enum TemplatePreviewState {
|
|
9
|
+
/** The seeded, realistic records. */
|
|
10
|
+
Populated = 'populated',
|
|
11
|
+
|
|
12
|
+
/** The query returned nothing; each table shows its empty message. */
|
|
13
|
+
Empty = 'empty',
|
|
14
|
+
|
|
15
|
+
/** The query has not answered yet; each table announces that it is loading. */
|
|
16
|
+
Loading = 'loading',
|
|
17
|
+
|
|
18
|
+
/** The query failed; each table announces the error in place of its rows. */
|
|
19
|
+
Error = 'error',
|
|
20
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { ExternalComponent, Panel, SceneElement } from '@cratis/scene.model';
|
|
5
|
+
import { TemplatePreviewState } from './TemplatePreviewState';
|
|
6
|
+
|
|
7
|
+
/** What a table in a preview says when its data could not be loaded. */
|
|
8
|
+
export const previewErrorMessage = 'The data could not be loaded. Try again in a moment.';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Puts every data-bearing element of a composed screen into one data state, leaving everything else - the
|
|
12
|
+
* shell, headers, actions and static content - exactly as authored.
|
|
13
|
+
*
|
|
14
|
+
* A data-bearing element is one whose `rows` are records: the seeded rows are what a query would return,
|
|
15
|
+
* so the states are expressed as a query's outcomes in the table's own vocabulary - no rows, `loading`, or
|
|
16
|
+
* an `error` message - rather than by swapping in a different component. The authored tree is not changed.
|
|
17
|
+
*/
|
|
18
|
+
export function applyTemplatePreviewState<T extends SceneElement>(element: T, state: TemplatePreviewState): T {
|
|
19
|
+
if (state === TemplatePreviewState.Populated) return element;
|
|
20
|
+
return transform(element, state) as T;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Whether a composed screen contains anything a data state changes. */
|
|
24
|
+
export function hasPreviewData(element: SceneElement): boolean {
|
|
25
|
+
const properties = (element as Partial<ExternalComponent>).properties;
|
|
26
|
+
if (isDataBearing(properties)) return true;
|
|
27
|
+
return childrenOf(element).some(hasPreviewData);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function transform(element: SceneElement, state: TemplatePreviewState): SceneElement {
|
|
31
|
+
const external = element as Partial<ExternalComponent>;
|
|
32
|
+
const panel = element as Partial<Panel>;
|
|
33
|
+
let result: SceneElement = element;
|
|
34
|
+
|
|
35
|
+
if (isDataBearing(external.properties)) {
|
|
36
|
+
result = { ...result, properties: { ...external.properties, ...stateProperties(state) } } as SceneElement;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (external.slots) {
|
|
40
|
+
const slots = Object.fromEntries(Object.entries(external.slots).map(([name, children]) => [name, children.map(child => transform(child, state))]));
|
|
41
|
+
result = { ...result, slots } as SceneElement;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(panel.children)) {
|
|
45
|
+
result = { ...result, children: panel.children.map(child => transform(child, state)) } as SceneElement;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function stateProperties(state: TemplatePreviewState): Record<string, unknown> {
|
|
52
|
+
switch (state) {
|
|
53
|
+
case TemplatePreviewState.Empty: return { rows: [] };
|
|
54
|
+
case TemplatePreviewState.Loading: return { rows: [], loading: true };
|
|
55
|
+
case TemplatePreviewState.Error: return { rows: [], error: previewErrorMessage };
|
|
56
|
+
default: return {};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isDataBearing(properties: Record<string, unknown> | undefined): boolean {
|
|
61
|
+
const rows = properties?.rows;
|
|
62
|
+
return Array.isArray(rows) && rows.every(row => typeof row === 'object' && row !== null && !Array.isArray(row));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function childrenOf(element: SceneElement): SceneElement[] {
|
|
66
|
+
const external = element as Partial<ExternalComponent>;
|
|
67
|
+
const panel = element as Partial<Panel>;
|
|
68
|
+
return [...Object.values(external.slots ?? {}).flat(), ...(Array.isArray(panel.children) ? panel.children : [])];
|
|
69
|
+
}
|
package/gallery/authTemplates.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { SlotName } from '../layouts';
|
|
|
7
7
|
import { TemplateSlotName } from './TemplateSlotName';
|
|
8
8
|
import { button, card, externalComponent, text } from './elements';
|
|
9
9
|
import { field, formActions } from './widgets';
|
|
10
|
+
import { defaultBlueprintTemplateProvenance } from '../templateProvenance';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* The six screens that stand between someone and the application: sign in, register, forgotten password,
|
|
@@ -47,6 +48,7 @@ export const loginTemplate: ScreenTemplate = {
|
|
|
47
48
|
},
|
|
48
49
|
displayName: 'Sign in',
|
|
49
50
|
description: 'Email and password beside the branding panel.',
|
|
51
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
/** Register. */
|
|
@@ -69,6 +71,7 @@ export const registerTemplate: ScreenTemplate = {
|
|
|
69
71
|
},
|
|
70
72
|
displayName: 'Register',
|
|
71
73
|
description: 'Account creation with a password strength meter and the terms checkbox.',
|
|
74
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
72
75
|
};
|
|
73
76
|
|
|
74
77
|
/** Forgotten password: ask for the address. */
|
|
@@ -88,6 +91,7 @@ export const forgotPasswordTemplate: ScreenTemplate = {
|
|
|
88
91
|
},
|
|
89
92
|
displayName: 'Forgotten password',
|
|
90
93
|
description: 'One field and one button - the whole point is that it asks for nothing else.',
|
|
94
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
91
95
|
};
|
|
92
96
|
|
|
93
97
|
/** New password: the other end of the link. */
|
|
@@ -108,6 +112,7 @@ export const newPasswordTemplate: ScreenTemplate = {
|
|
|
108
112
|
},
|
|
109
113
|
displayName: 'New password',
|
|
110
114
|
description: 'Where a reset link lands: choose it, confirm it, done.',
|
|
115
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
111
116
|
};
|
|
112
117
|
|
|
113
118
|
/** Verification: the code from the email. */
|
|
@@ -128,6 +133,7 @@ export const verificationTemplate: ScreenTemplate = {
|
|
|
128
133
|
},
|
|
129
134
|
displayName: 'Verification',
|
|
130
135
|
description: 'The code step, with the progress indicator that tells you how much is left.',
|
|
136
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
131
137
|
};
|
|
132
138
|
|
|
133
139
|
/** Lock screen: the session is still there, the person has to prove they are. */
|
|
@@ -148,6 +154,7 @@ export const lockScreenTemplate: ScreenTemplate = {
|
|
|
148
154
|
},
|
|
149
155
|
displayName: 'Lock screen',
|
|
150
156
|
description: 'One person, one password, and no way to lose what was open.',
|
|
157
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
151
158
|
};
|
|
152
159
|
|
|
153
160
|
/** The six authentication templates. */
|
|
@@ -5,6 +5,7 @@ import { DialogTemplate } from '@cratis/scene.model';
|
|
|
5
5
|
import { TemplateSlotName } from './TemplateSlotName';
|
|
6
6
|
import { button, card, externalComponent, panel, text } from './elements';
|
|
7
7
|
import { field } from './widgets';
|
|
8
|
+
import { defaultBlueprintTemplateProvenance } from '../templateProvenance';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* The three dialog shapes an application repeats: confirm something destructive, capture a short form, and
|
|
@@ -32,6 +33,7 @@ export const confirmDialogTemplate: DialogTemplate = {
|
|
|
32
33
|
},
|
|
33
34
|
displayName: 'Confirmation dialog',
|
|
34
35
|
description: 'One question with the consequence spelled out, and a way back.',
|
|
36
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
/** Form: a short capture that does not deserve a page of its own. */
|
|
@@ -51,6 +53,7 @@ export const formDialogTemplate: DialogTemplate = {
|
|
|
51
53
|
},
|
|
52
54
|
displayName: 'Form dialog',
|
|
53
55
|
description: 'A handful of fields captured without leaving the page underneath.',
|
|
56
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
54
57
|
};
|
|
55
58
|
|
|
56
59
|
/** Detail: a record shown over the list it came from. */
|
|
@@ -73,6 +76,7 @@ export const detailDialogTemplate: DialogTemplate = {
|
|
|
73
76
|
},
|
|
74
77
|
displayName: 'Detail dialog',
|
|
75
78
|
description: 'A record over the list it came from, with a route to the full page.',
|
|
79
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
76
80
|
};
|
|
77
81
|
|
|
78
82
|
/** The dialog templates this blueprint provides. */
|
package/gallery/index.ts
CHANGED
package/gallery/navigation.ts
CHANGED
|
@@ -21,6 +21,7 @@ export const navigationEntries: NavigationEntry[] = [
|
|
|
21
21
|
{ label: 'Dashboard', targetScreen: 'Dashboard', icon: 'pi pi-home', group: 'Workspace', order: 10 },
|
|
22
22
|
{ label: 'Products', targetScreen: 'CrudList', icon: 'pi pi-box', group: 'Workspace', order: 20 },
|
|
23
23
|
{ label: 'Product detail', targetScreen: 'DetailView', icon: 'pi pi-file', group: 'Workspace', order: 30 },
|
|
24
|
+
{ label: 'Customers', targetScreen: 'MasterDetail', icon: 'pi pi-users', group: 'Workspace', order: 35 },
|
|
24
25
|
{ label: 'New product', targetScreen: 'FormPage', icon: 'pi pi-plus-circle', group: 'Workspace', order: 40 },
|
|
25
26
|
{ label: 'Invoices', targetScreen: 'Invoice', icon: 'pi pi-receipt', group: 'Workspace', order: 50 },
|
|
26
27
|
{ label: 'Nothing yet', targetScreen: 'Empty', icon: 'pi pi-inbox', group: 'Workspace', order: 60 },
|
package/gallery/nesting.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { SlotName, column, slotLeaf } from '../layouts';
|
|
|
7
7
|
import { TemplateSlotName } from './TemplateSlotName';
|
|
8
8
|
import { button, externalComponent } from './elements';
|
|
9
9
|
import { pageHeader } from './widgets';
|
|
10
|
+
import { defaultBlueprintTemplateProvenance } from '../templateProvenance';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* A worked three-level chain, from the application layout down to a slice.
|
|
@@ -36,6 +37,7 @@ export const moduleWorkspaceTemplate: ScreenTemplate = {
|
|
|
36
37
|
},
|
|
37
38
|
displayName: 'Module workspace',
|
|
38
39
|
description: 'Module level: fits the application layout content slot and offers a body for one feature.',
|
|
40
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -56,6 +58,7 @@ export const featureSectionTemplate: ScreenTemplate = {
|
|
|
56
58
|
},
|
|
57
59
|
displayName: 'Feature section',
|
|
58
60
|
description: 'Feature level: fits a module workspace body slot and brings the action toolbar.',
|
|
61
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
59
62
|
};
|
|
60
63
|
|
|
61
64
|
/**
|
|
@@ -76,6 +79,7 @@ export const sliceSectionTemplate: ScreenTemplate = {
|
|
|
76
79
|
},
|
|
77
80
|
displayName: 'Slice section',
|
|
78
81
|
description: 'Slice level: fits a feature section body slot and hosts one behavior.',
|
|
82
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
/** The chain, outermost first - what a spec walks to prove `fitsSlot` resolves at every level. */
|
package/gallery/screens.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { workspaceTemplates } from './workspaceTemplates';
|
|
|
15
15
|
/**
|
|
16
16
|
* The screen templates this blueprint provides.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* Eleven shapes for inside the application shell, ten for the full-page shell, and the three-level nesting
|
|
19
19
|
* chain that demonstrates how `fitsSlot` composes. The list is what the manifest's `screenTemplates` names
|
|
20
20
|
* and what the bundle provides; `validatePackageBundle` proves the two agree.
|
|
21
21
|
*/
|
|
@@ -34,6 +34,7 @@ const fullPageTemplateNames = new Set([...authTemplates, ...statusTemplates].map
|
|
|
34
34
|
const breadcrumbs: Record<string, BreadcrumbEntry[]> = {
|
|
35
35
|
Dashboard: [{ label: 'Dashboard' }],
|
|
36
36
|
CrudList: [{ label: 'Catalog', targetScreen: 'Dashboard' }, { label: 'Products' }],
|
|
37
|
+
MasterDetail: [{ label: 'Sales', targetScreen: 'Dashboard' }, { label: 'Customers' }],
|
|
37
38
|
DetailView: [{ label: 'Catalog', targetScreen: 'Dashboard' }, { label: 'Products', targetScreen: 'CrudList' }, { label: 'Bamboo Watch' }],
|
|
38
39
|
FormPage: [{ label: 'Catalog', targetScreen: 'Dashboard' }, { label: 'Products', targetScreen: 'CrudList' }, { label: 'New product' }],
|
|
39
40
|
Empty: [{ label: 'Catalog', targetScreen: 'Dashboard' }, { label: 'Products' }],
|
|
@@ -7,6 +7,7 @@ import { SlotName } from '../layouts';
|
|
|
7
7
|
import { TemplateSlotName } from './TemplateSlotName';
|
|
8
8
|
import { button, card, externalComponent, panel, text } from './elements';
|
|
9
9
|
import { widget } from './widgets';
|
|
10
|
+
import { defaultBlueprintTemplateProvenance } from '../templateProvenance';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* The four screens that are not part of anyone's plan: a server error, a refusal, a wrong address, and the
|
|
@@ -37,6 +38,7 @@ export const errorTemplate: ScreenTemplate = {
|
|
|
37
38
|
},
|
|
38
39
|
displayName: 'Error',
|
|
39
40
|
description: 'A server-side failure, said plainly, with a way onward.',
|
|
41
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
/** Signed in, and still not allowed. */
|
|
@@ -59,6 +61,7 @@ export const accessDeniedTemplate: ScreenTemplate = {
|
|
|
59
61
|
},
|
|
60
62
|
displayName: 'Access denied',
|
|
61
63
|
description: 'A refusal that distinguishes "not signed in" from "not allowed".',
|
|
64
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
62
65
|
};
|
|
63
66
|
|
|
64
67
|
/** No such address. */
|
|
@@ -72,13 +75,14 @@ export const notFoundTemplate: ScreenTemplate = {
|
|
|
72
75
|
externalComponent('not-found-tag', 'tag', { value: '404', severity: 'info' }),
|
|
73
76
|
text('not-found-title', 'That page is not here'),
|
|
74
77
|
text('not-found-message', 'The link may be old, or the thing it pointed at may have been removed.'),
|
|
75
|
-
externalComponent('not-found-search', 'inputText', { placeholder: 'Search instead' }),
|
|
78
|
+
externalComponent('not-found-search', 'inputText', { placeholder: 'Search instead', ariaLabel: 'Search' }),
|
|
76
79
|
button('not-found-home', 'Back to the dashboard', { severity: 'secondary', targetScreen: 'Dashboard' }),
|
|
77
80
|
]),
|
|
78
81
|
],
|
|
79
82
|
},
|
|
80
83
|
displayName: 'Not found',
|
|
81
84
|
description: 'A wrong address, with a search box rather than a dead end.',
|
|
85
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
82
86
|
};
|
|
83
87
|
|
|
84
88
|
/** The page that has to do the selling. */
|
|
@@ -112,6 +116,7 @@ export const landingTemplate: ScreenTemplate = {
|
|
|
112
116
|
},
|
|
113
117
|
displayName: 'Landing',
|
|
114
118
|
description: 'The marketing front door, with its own navigation because it has no application chrome.',
|
|
119
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
115
120
|
};
|
|
116
121
|
|
|
117
122
|
/** The four status and marketing templates. */
|
|
@@ -6,6 +6,7 @@ import { SlotName } from '../layouts';
|
|
|
6
6
|
import { TemplateSlotName } from './TemplateSlotName';
|
|
7
7
|
import { button, card, externalComponent, text } from './elements';
|
|
8
8
|
import { field, formActions, pageHeader, table, widget } from './widgets';
|
|
9
|
+
import { defaultBlueprintTemplateProvenance } from '../templateProvenance';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* The five shapes an application needs that are not the CRUD loop: documentation, the signed-in user's own
|
|
@@ -40,6 +41,7 @@ export const documentationTemplate: ScreenTemplate = {
|
|
|
40
41
|
},
|
|
41
42
|
displayName: 'Documentation',
|
|
42
43
|
description: 'Prose with a table of contents beside it.',
|
|
44
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
43
45
|
};
|
|
44
46
|
|
|
45
47
|
/** Profile settings: the signed-in user editing their own account. */
|
|
@@ -67,6 +69,7 @@ export const profileSettingsTemplate: ScreenTemplate = {
|
|
|
67
69
|
},
|
|
68
70
|
displayName: 'Profile settings',
|
|
69
71
|
description: 'The signed-in user editing their own name, photo, password and notifications.',
|
|
72
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
70
73
|
};
|
|
71
74
|
|
|
72
75
|
/** User management: administering everybody else. */
|
|
@@ -99,6 +102,7 @@ export const userManagementTemplate: ScreenTemplate = {
|
|
|
99
102
|
},
|
|
100
103
|
displayName: 'User management',
|
|
101
104
|
description: 'The people table, with roles, status and an invitation action.',
|
|
105
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
102
106
|
};
|
|
103
107
|
|
|
104
108
|
/** Invoice: a printable document, which is a different shape from a screen. */
|
|
@@ -135,6 +139,7 @@ export const invoiceTemplate: ScreenTemplate = {
|
|
|
135
139
|
},
|
|
136
140
|
displayName: 'Invoice',
|
|
137
141
|
description: 'A printable document: parties, line items and totals.',
|
|
142
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
138
143
|
};
|
|
139
144
|
|
|
140
145
|
/** Help: the answers, and a way to ask when they are not there. */
|
|
@@ -145,7 +150,7 @@ export const helpTemplate: ScreenTemplate = {
|
|
|
145
150
|
content: {
|
|
146
151
|
[TemplateSlotName.Header]: [pageHeader('help-header', 'Help', 'Search the answers, or ask us directly')],
|
|
147
152
|
[TemplateSlotName.Body]: [
|
|
148
|
-
externalComponent('help-search', 'inputText', { placeholder: 'Search help' }),
|
|
153
|
+
externalComponent('help-search', 'inputText', { placeholder: 'Search help', ariaLabel: 'Search help' }),
|
|
149
154
|
widget('help-popular', 'Popular answers', [
|
|
150
155
|
text('help-1', 'How do I invite someone to the workspace?'),
|
|
151
156
|
text('help-2', 'Why can I not see the sidebar on my phone?'),
|
|
@@ -158,6 +163,7 @@ export const helpTemplate: ScreenTemplate = {
|
|
|
158
163
|
},
|
|
159
164
|
displayName: 'Help',
|
|
160
165
|
description: 'Searchable answers with a route to a human.',
|
|
166
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
161
167
|
};
|
|
162
168
|
|
|
163
169
|
/** The five support templates. */
|
package/gallery/widgets.ts
CHANGED
|
@@ -32,19 +32,28 @@ export function widget(id: string, title: string, content: SceneElement[]): Scen
|
|
|
32
32
|
return card(id, [text(`${id}-title`, title), ...content], { title });
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/**
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* A table with real columns and real rows, so a list template looks like a list.
|
|
37
|
+
*
|
|
38
|
+
* The properties are the table's own vocabulary - `rows` for the records and `pageSize` to page them - so
|
|
39
|
+
* a host with the real table loaded shows the rows rather than an empty grid. `emptyMessage` is what the
|
|
40
|
+
* same table says once the rows are gone, which is how a preview shows a template's empty state.
|
|
41
|
+
*/
|
|
42
|
+
export function table(id: string, columns: { field: string; header: string }[], rows: Record<string, unknown>[], emptyMessage = 'Nothing to show yet'): SceneElement {
|
|
37
43
|
return externalComponent(
|
|
38
44
|
id,
|
|
39
45
|
'dataTable',
|
|
40
|
-
{
|
|
46
|
+
{ rows, dataKey: columns[0]?.field ?? 'id', emptyMessage, ...(rows.length > 8 ? { pageSize: 8 } : {}) },
|
|
41
47
|
{ columns: columns.map(column => externalComponent(`${id}-${column.field}`, 'column', { field: column.field, header: column.header, sortable: true })) },
|
|
42
48
|
);
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* One labeled input in a form template. The visible label is a separate text element, so the input carries
|
|
53
|
+
* the same words as its accessible name - otherwise a screen reader announces an unnamed field.
|
|
54
|
+
*/
|
|
46
55
|
export function field(id: string, label: string, componentName: string, properties: Record<string, unknown> = {}): SceneElement {
|
|
47
|
-
return panel(id, [text(`${id}-label`, label), externalComponent(`${id}-input`, componentName, properties)]);
|
|
56
|
+
return panel(id, [text(`${id}-label`, label), externalComponent(`${id}-input`, componentName, { ariaLabel: label, ...properties })]);
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
/** A row of buttons closing a form. */
|
|
@@ -6,10 +6,11 @@ import { SlotName, column, grid, slotLeaf } from '../layouts';
|
|
|
6
6
|
import { TemplateSlotName } from './TemplateSlotName';
|
|
7
7
|
import { button, card, externalComponent, text } from './elements';
|
|
8
8
|
import { emptyState, field, formActions, pageHeader, statCard, table, widget } from './widgets';
|
|
9
|
+
import { defaultBlueprintTemplateProvenance, sakaiCompositionProvenance } from '../templateProvenance';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* The
|
|
12
|
-
* designed empty state.
|
|
12
|
+
* The six workhorse shapes inside an application shell: a dashboard, a list, master/detail, a detail, a
|
|
13
|
+
* form and the designed empty state.
|
|
13
14
|
*
|
|
14
15
|
* Every one fits the layout's `content` slot, and every one carries realistic seeded content rather than
|
|
15
16
|
* placeholder text. A gallery whose dashboard shows four boxes labeled "Card" proves the renderer runs; a
|
|
@@ -88,6 +89,7 @@ export const dashboardTemplate: ScreenTemplate = {
|
|
|
88
89
|
},
|
|
89
90
|
displayName: 'Dashboard',
|
|
90
91
|
description: 'Four stat cards over two columns of widgets - the composition every template line opens with.',
|
|
92
|
+
metadata: { ...sakaiCompositionProvenance },
|
|
91
93
|
};
|
|
92
94
|
|
|
93
95
|
/** The list: a filter toolbar, a real table, and the row actions a list needs. */
|
|
@@ -101,7 +103,7 @@ export const crudListTemplate: ScreenTemplate = {
|
|
|
101
103
|
button('crud-new', 'New product', { severity: 'primary', icon: 'pi pi-plus' }),
|
|
102
104
|
button('crud-import', 'Import', { severity: 'secondary', icon: 'pi pi-upload' }),
|
|
103
105
|
]),
|
|
104
|
-
externalComponent('crud-search', 'inputText', { placeholder: 'Search products' }),
|
|
106
|
+
externalComponent('crud-search', 'inputText', { placeholder: 'Search products', ariaLabel: 'Search products' }),
|
|
105
107
|
],
|
|
106
108
|
[TemplateSlotName.Body]: [
|
|
107
109
|
table(
|
|
@@ -125,6 +127,7 @@ export const crudListTemplate: ScreenTemplate = {
|
|
|
125
127
|
},
|
|
126
128
|
displayName: 'List',
|
|
127
129
|
description: 'A searchable table with a header, primary action and row data.',
|
|
130
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
128
131
|
};
|
|
129
132
|
|
|
130
133
|
/** The detail: a summary panel beside the record's own sections. */
|
|
@@ -155,6 +158,61 @@ export const detailViewTemplate: ScreenTemplate = {
|
|
|
155
158
|
},
|
|
156
159
|
displayName: 'Detail',
|
|
157
160
|
description: 'One record: a header with actions, its sections, and a summary panel.',
|
|
161
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Master/detail: the list and the selected record side by side, so working through records does not mean
|
|
166
|
+
* leaving the list. The detail region is an outlet that accepts detail screens, which is what lets a row's
|
|
167
|
+
* destination open a full detail screen in place.
|
|
168
|
+
*
|
|
169
|
+
* At a compact width the two stack, list first, because side-by-side on a phone is two unreadable halves.
|
|
170
|
+
*/
|
|
171
|
+
export const masterDetailTemplate: ScreenTemplate = {
|
|
172
|
+
name: 'MasterDetail',
|
|
173
|
+
fitsSlot: SlotName.Content,
|
|
174
|
+
slots: [{ name: TemplateSlotName.Header }, { name: TemplateSlotName.Primary }, { name: TemplateSlotName.SidePanel }],
|
|
175
|
+
outlets: [{ name: 'master-detail.detail', description: 'The selected record.', accepts: ['Detail'] }],
|
|
176
|
+
arrangement: {
|
|
177
|
+
root: column([slotLeaf(TemplateSlotName.Header), grid([slotLeaf(TemplateSlotName.Primary), slotLeaf(TemplateSlotName.SidePanel)], 2, 16)], 16),
|
|
178
|
+
overrides: [
|
|
179
|
+
{
|
|
180
|
+
width: WidthSizeClass.Compact,
|
|
181
|
+
root: column([slotLeaf(TemplateSlotName.Header), slotLeaf(TemplateSlotName.Primary), slotLeaf(TemplateSlotName.SidePanel)], 16),
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
content: {
|
|
186
|
+
[TemplateSlotName.Header]: [pageHeader('master-header', 'Customers', '1,204 customers, 38 with overdue invoices')],
|
|
187
|
+
[TemplateSlotName.Primary]: [
|
|
188
|
+
table(
|
|
189
|
+
'customers-table',
|
|
190
|
+
[
|
|
191
|
+
{ field: 'name', header: 'Customer' },
|
|
192
|
+
{ field: 'city', header: 'City' },
|
|
193
|
+
{ field: 'balance', header: 'Balance' },
|
|
194
|
+
],
|
|
195
|
+
[
|
|
196
|
+
{ name: 'Northwind Traders', city: 'Seattle', balance: '$4,200.00' },
|
|
197
|
+
{ name: 'Contoso Ltd', city: 'Oslo', balance: '$0.00' },
|
|
198
|
+
{ name: 'Fabrikam', city: 'Lyon', balance: '$12,940.50' },
|
|
199
|
+
{ name: 'Adventure Works', city: 'Denver', balance: '$318.20' },
|
|
200
|
+
],
|
|
201
|
+
'No customers match the search',
|
|
202
|
+
),
|
|
203
|
+
],
|
|
204
|
+
[TemplateSlotName.SidePanel]: [
|
|
205
|
+
widget('customer-detail', 'Northwind Traders', [
|
|
206
|
+
text('customer-contact', 'Contact: Amelia Nyquist'),
|
|
207
|
+
text('customer-terms', 'Payment terms: 30 days'),
|
|
208
|
+
externalComponent('customer-status', 'tag', { value: 'Overdue', severity: 'warning' }),
|
|
209
|
+
button('customer-open', 'Open customer', { severity: 'primary' }),
|
|
210
|
+
]),
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
displayName: 'Master/detail',
|
|
214
|
+
description: 'A list beside the selected record, stacking on narrow screens.',
|
|
215
|
+
metadata: { ...defaultBlueprintTemplateProvenance, type: 'Workspace' },
|
|
158
216
|
};
|
|
159
217
|
|
|
160
218
|
/** The form: fields, grouped, with the actions that close them. */
|
|
@@ -178,6 +236,7 @@ export const formPageTemplate: ScreenTemplate = {
|
|
|
178
236
|
},
|
|
179
237
|
displayName: 'Form',
|
|
180
238
|
description: 'A grouped form with the field types an application actually uses.',
|
|
239
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
181
240
|
};
|
|
182
241
|
|
|
183
242
|
/** The empty state: what a list looks like before anything exists, designed rather than apologized for. */
|
|
@@ -192,7 +251,8 @@ export const emptyTemplate: ScreenTemplate = {
|
|
|
192
251
|
},
|
|
193
252
|
displayName: 'Empty state',
|
|
194
253
|
description: 'The designed empty state for a list that has nothing in it yet.',
|
|
254
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
195
255
|
};
|
|
196
256
|
|
|
197
257
|
/** The five workspace templates. */
|
|
198
|
-
export const workspaceTemplates: ScreenTemplate[] = [dashboardTemplate, crudListTemplate, detailViewTemplate, formPageTemplate, emptyTemplate];
|
|
258
|
+
export const workspaceTemplates: ScreenTemplate[] = [dashboardTemplate, crudListTemplate, masterDetailTemplate, detailViewTemplate, formPageTemplate, emptyTemplate];
|
package/index.ts
CHANGED
package/layouts/appShell.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { FlowArrangement, HeightSizeClass, Layout, WidthSizeClass } from '@crati
|
|
|
5
5
|
import { LayoutName } from './LayoutName';
|
|
6
6
|
import { SlotName } from './SlotName';
|
|
7
7
|
import { column, row, slotLeaf } from './flowBuilders';
|
|
8
|
+
import { sakaiCompositionProvenance } from '../templateProvenance';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* The tree at a regular width and height: a topbar across the top, the sidebar column beside the main
|
|
@@ -103,4 +104,5 @@ export const appShellLayout: Layout = {
|
|
|
103
104
|
{ name: SlotName.ConfigPanel },
|
|
104
105
|
],
|
|
105
106
|
arrangement: appShellArrangement,
|
|
107
|
+
metadata: { ...sakaiCompositionProvenance },
|
|
106
108
|
};
|
package/layouts/fullPage.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { FlowArrangement, Layout, WidthSizeClass } from '@cratis/scene.model';
|
|
|
5
5
|
import { LayoutName } from './LayoutName';
|
|
6
6
|
import { SlotName } from './SlotName';
|
|
7
7
|
import { column, row, slotLeaf } from './flowBuilders';
|
|
8
|
+
import { defaultBlueprintTemplateProvenance } from '../templateProvenance';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* The tree at a regular width: the branding aside beside the content, with the configurator over both.
|
|
@@ -45,4 +46,5 @@ export const fullPageLayout: Layout = {
|
|
|
45
46
|
name: LayoutName.FullPage,
|
|
46
47
|
slots: [{ name: SlotName.Aside }, { name: SlotName.Content }, { name: SlotName.ConfigPanel }],
|
|
47
48
|
arrangement: fullPageArrangement,
|
|
49
|
+
metadata: { ...defaultBlueprintTemplateProvenance },
|
|
48
50
|
};
|