@stack-spot/portal-layout 1.0.2 → 1.1.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/CHANGELOG.md +12 -0
- package/dist/Layout.d.ts +2 -2
- package/dist/Layout.js +1 -1
- package/dist/LayoutOverlayManager.js +6 -6
- package/dist/LayoutOverlayManager.js.map +1 -1
- package/dist/components/Dialog.d.ts +1 -1
- package/dist/components/Dialog.js +1 -1
- package/dist/components/Header.d.ts +1 -1
- package/dist/components/Header.js +1 -1
- package/dist/components/OverlayContent.d.ts +1 -1
- package/dist/components/OverlayContent.js +20 -20
- package/dist/components/PortalSwitcher.d.ts +1 -1
- package/dist/components/PortalSwitcher.js +54 -54
- package/dist/components/Toaster.d.ts +2 -2
- package/dist/components/Toaster.js +1 -1
- package/dist/components/UserMenu.d.ts +1 -1
- package/dist/components/UserMenu.d.ts.map +1 -1
- package/dist/components/UserMenu.js +44 -42
- package/dist/components/UserMenu.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +1 -1
- package/dist/components/error/ErrorBoundary.js +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +1 -1
- package/dist/components/error/SilentErrorBoundary.js +1 -1
- package/dist/components/menu/MenuContent.d.ts +2 -2
- package/dist/components/menu/MenuContent.js +123 -123
- package/dist/components/menu/MenuContent.js.map +1 -1
- package/dist/components/menu/MenuSections.d.ts +1 -1
- package/dist/components/menu/MenuSections.js +1 -1
- package/dist/components/menu/MenuSections.js.map +1 -1
- package/dist/components/menu/PageSelector.d.ts +1 -1
- package/dist/components/menu/PageSelector.js +69 -69
- package/dist/components/menu/PageSelector.js.map +1 -1
- package/dist/components/tour/PortalSwitcherStep.js +1 -1
- package/dist/components/user-menu-manager.d.ts +13 -0
- package/dist/components/user-menu-manager.d.ts.map +1 -0
- package/dist/components/user-menu-manager.js +36 -0
- package/dist/components/user-menu-manager.js.map +1 -0
- package/dist/layout.css +477 -477
- package/dist/toaster.js +1 -1
- package/package.json +9 -6
- package/readme.md +146 -146
- package/src/Layout.tsx +171 -171
- package/src/LayoutOverlayManager.tsx +464 -464
- package/src/components/Dialog.tsx +140 -140
- package/src/components/Header.tsx +62 -62
- package/src/components/OverlayContent.tsx +80 -80
- package/src/components/PortalSwitcher.tsx +161 -161
- package/src/components/Toaster.tsx +95 -95
- package/src/components/UserMenu.tsx +127 -124
- package/src/components/error/ErrorBoundary.tsx +47 -47
- package/src/components/error/ErrorManager.ts +47 -47
- package/src/components/error/SilentErrorBoundary.tsx +64 -64
- package/src/components/menu/MenuContent.tsx +270 -270
- package/src/components/menu/MenuSections.tsx +320 -320
- package/src/components/menu/PageSelector.tsx +164 -164
- package/src/components/menu/constants.ts +2 -2
- package/src/components/menu/types.ts +205 -205
- package/src/components/tour/PortalSwitcherStep.tsx +39 -39
- package/src/components/types.ts +1 -1
- package/src/components/user-menu-manager.ts +31 -0
- package/src/dictionary.ts +28 -28
- package/src/elements.ts +30 -30
- package/src/errors.ts +11 -11
- package/src/index.ts +14 -14
- package/src/layout.css +477 -477
- package/src/toaster.tsx +153 -153
- package/src/utils.ts +29 -29
- package/tsconfig.json +8 -8
|
@@ -1,205 +1,205 @@
|
|
|
1
|
-
import { Action } from '@stack-spot/portal-components/SelectionList'
|
|
2
|
-
import { ReactElement, ReactNode } from 'react'
|
|
3
|
-
|
|
4
|
-
interface BaseMenuItem {
|
|
5
|
-
hidden?: boolean,
|
|
6
|
-
/**
|
|
7
|
-
* React element on the left.
|
|
8
|
-
*/
|
|
9
|
-
icon?: React.ReactElement,
|
|
10
|
-
/**
|
|
11
|
-
* React element on the right.
|
|
12
|
-
*/
|
|
13
|
-
badge?: React.ReactElement,
|
|
14
|
-
/**
|
|
15
|
-
* Whether to wrap overflowing text, just hide or hide and add an ellipsis (...).
|
|
16
|
-
* @default 'wrap'
|
|
17
|
-
*/
|
|
18
|
-
overflow?: 'hidden' | 'wrap' | 'ellipsis',
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ItemGroup extends BaseMenuItem {
|
|
22
|
-
/**
|
|
23
|
-
* The label for this group.
|
|
24
|
-
*/
|
|
25
|
-
label: string,
|
|
26
|
-
/**
|
|
27
|
-
* The items in this group.
|
|
28
|
-
*/
|
|
29
|
-
children: MenuItem[],
|
|
30
|
-
/**
|
|
31
|
-
* Whether it should start opened or not.
|
|
32
|
-
*/
|
|
33
|
-
open?: boolean,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface MenuAction extends Action, BaseMenuItem {
|
|
37
|
-
/**
|
|
38
|
-
* Whether this menu item is currently active or not.
|
|
39
|
-
*/
|
|
40
|
-
active?: boolean,
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export type MenuItem = ItemGroup | MenuAction
|
|
44
|
-
|
|
45
|
-
export interface SelectorItem extends Action {
|
|
46
|
-
/**
|
|
47
|
-
* A unique id for this item.
|
|
48
|
-
*/
|
|
49
|
-
key: string,
|
|
50
|
-
/**
|
|
51
|
-
* An icon to place at the left side of the item.
|
|
52
|
-
*/
|
|
53
|
-
icon?: ReactElement,
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface Selector {
|
|
57
|
-
/**
|
|
58
|
-
* The current value. Must correspond to a `key` in `options`.
|
|
59
|
-
*/
|
|
60
|
-
value?: string,
|
|
61
|
-
/**
|
|
62
|
-
* A series of options to show in the selector.
|
|
63
|
-
*/
|
|
64
|
-
options: SelectorItem[],
|
|
65
|
-
/**
|
|
66
|
-
* An extra button to show after the list of options.
|
|
67
|
-
*/
|
|
68
|
-
button?: Action,
|
|
69
|
-
/**
|
|
70
|
-
* A title of this selector.
|
|
71
|
-
*/
|
|
72
|
-
title?: string,
|
|
73
|
-
/**
|
|
74
|
-
* A subtitle for this selector.
|
|
75
|
-
*/
|
|
76
|
-
subtitle?: string,
|
|
77
|
-
/**
|
|
78
|
-
* Whether or not the options for this selector are loading.
|
|
79
|
-
*/
|
|
80
|
-
loading?: boolean,
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export interface MenuSectionContent {
|
|
84
|
-
/**
|
|
85
|
-
* A link to go back.
|
|
86
|
-
*/
|
|
87
|
-
goBack?: Action,
|
|
88
|
-
/**
|
|
89
|
-
* A title for this menu.
|
|
90
|
-
*/
|
|
91
|
-
title?: string,
|
|
92
|
-
/**
|
|
93
|
-
* A subtitle for this menu.
|
|
94
|
-
*/
|
|
95
|
-
subtitle?: string,
|
|
96
|
-
/**
|
|
97
|
-
* A custom React Node to add right after the menu title.
|
|
98
|
-
*/
|
|
99
|
-
afterTitle?: React.ReactNode,
|
|
100
|
-
/**
|
|
101
|
-
* A page selector.
|
|
102
|
-
*/
|
|
103
|
-
pageSelector?: Selector,
|
|
104
|
-
/**
|
|
105
|
-
* The menu options, may contain subgroups.
|
|
106
|
-
*/
|
|
107
|
-
options?: MenuItem[],
|
|
108
|
-
/**
|
|
109
|
-
* Whether or not the options for this menu are loading.
|
|
110
|
-
*/
|
|
111
|
-
loading?: boolean,
|
|
112
|
-
/**
|
|
113
|
-
* An error to show instead of the menu.
|
|
114
|
-
*/
|
|
115
|
-
error?: string,
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface MenuSection extends Action {
|
|
119
|
-
/**
|
|
120
|
-
* The icon for this section.
|
|
121
|
-
*/
|
|
122
|
-
icon: ReactElement,
|
|
123
|
-
/**
|
|
124
|
-
* The content or a function that creates the content.
|
|
125
|
-
* If this is a function, it will be called only when the section is hovered, i.e. only when the content really needs to be rendered.
|
|
126
|
-
* Tip: this function can be a React Hook.
|
|
127
|
-
*/
|
|
128
|
-
content?: MenuSectionContent | (() => MenuSectionContent),
|
|
129
|
-
/**
|
|
130
|
-
* The content or a function that creates the content.
|
|
131
|
-
* If this is a function, it will be called only when the section is hovered, i.e. only when the content really needs to be rendered.
|
|
132
|
-
* Tip: this function can be a React Hook.
|
|
133
|
-
* This should be used when the content you want to render is not the default content
|
|
134
|
-
*/
|
|
135
|
-
customContent?: ReactNode,
|
|
136
|
-
/**
|
|
137
|
-
* Whether or not this section is currently active.
|
|
138
|
-
*/
|
|
139
|
-
active?: boolean,
|
|
140
|
-
/**
|
|
141
|
-
* A css class to pass to the <li> tag.
|
|
142
|
-
*/
|
|
143
|
-
className?: string,
|
|
144
|
-
hidden?: boolean,
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
interface BaseMenuProps {
|
|
148
|
-
/**
|
|
149
|
-
* The sections of the menu.
|
|
150
|
-
*/
|
|
151
|
-
sections?: MenuSection[],
|
|
152
|
-
/**
|
|
153
|
-
* The content of the menu as a React Element. Use this to create anything you want as the menu content, but prefer using `content`
|
|
154
|
-
* instead, which is a predefined menu.
|
|
155
|
-
*/
|
|
156
|
-
customContent?: ReactNode,
|
|
157
|
-
/**
|
|
158
|
-
* Options for the settings button.
|
|
159
|
-
*/
|
|
160
|
-
settings?: {
|
|
161
|
-
/**
|
|
162
|
-
* Whether or not to show the settings button.
|
|
163
|
-
*/
|
|
164
|
-
show?: boolean,
|
|
165
|
-
/**
|
|
166
|
-
* A function to call when the button is clicked.
|
|
167
|
-
*/
|
|
168
|
-
onClick?: () => void,
|
|
169
|
-
/**
|
|
170
|
-
* A url to go to when the button is clicked.
|
|
171
|
-
*/
|
|
172
|
-
href?: string,
|
|
173
|
-
/**
|
|
174
|
-
* Whether or not this button represents the page currently active.
|
|
175
|
-
*/
|
|
176
|
-
active?: boolean,
|
|
177
|
-
/**
|
|
178
|
-
* A css class to pass to the button.
|
|
179
|
-
*/
|
|
180
|
-
className?: string,
|
|
181
|
-
},
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface MenuPropsWithStaticContent extends BaseMenuProps {
|
|
185
|
-
/**
|
|
186
|
-
* The config for creating the menu content.
|
|
187
|
-
*/
|
|
188
|
-
content?: MenuSectionContent,
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export interface MenuPropsWithDynamicContent extends BaseMenuProps {
|
|
192
|
-
/**
|
|
193
|
-
* The function that creates a config to render a menu content. It will be called only when the content is rendered, i.e. only when the
|
|
194
|
-
* content really needs to be rendered.
|
|
195
|
-
*
|
|
196
|
-
* Tip: this function can be a React Hook.
|
|
197
|
-
*/
|
|
198
|
-
content: MenuSectionContent | (() => MenuSectionContent),
|
|
199
|
-
/**
|
|
200
|
-
* Identifies each content that might be rendered by the menu. This prevents React Hook errors when the content is a React Hook function.
|
|
201
|
-
*/
|
|
202
|
-
contentKey: React.Key,
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export type MenuProps = MenuPropsWithStaticContent | MenuPropsWithDynamicContent
|
|
1
|
+
import { Action } from '@stack-spot/portal-components/SelectionList'
|
|
2
|
+
import { ReactElement, ReactNode } from 'react'
|
|
3
|
+
|
|
4
|
+
interface BaseMenuItem {
|
|
5
|
+
hidden?: boolean,
|
|
6
|
+
/**
|
|
7
|
+
* React element on the left.
|
|
8
|
+
*/
|
|
9
|
+
icon?: React.ReactElement,
|
|
10
|
+
/**
|
|
11
|
+
* React element on the right.
|
|
12
|
+
*/
|
|
13
|
+
badge?: React.ReactElement,
|
|
14
|
+
/**
|
|
15
|
+
* Whether to wrap overflowing text, just hide or hide and add an ellipsis (...).
|
|
16
|
+
* @default 'wrap'
|
|
17
|
+
*/
|
|
18
|
+
overflow?: 'hidden' | 'wrap' | 'ellipsis',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ItemGroup extends BaseMenuItem {
|
|
22
|
+
/**
|
|
23
|
+
* The label for this group.
|
|
24
|
+
*/
|
|
25
|
+
label: string,
|
|
26
|
+
/**
|
|
27
|
+
* The items in this group.
|
|
28
|
+
*/
|
|
29
|
+
children: MenuItem[],
|
|
30
|
+
/**
|
|
31
|
+
* Whether it should start opened or not.
|
|
32
|
+
*/
|
|
33
|
+
open?: boolean,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface MenuAction extends Action, BaseMenuItem {
|
|
37
|
+
/**
|
|
38
|
+
* Whether this menu item is currently active or not.
|
|
39
|
+
*/
|
|
40
|
+
active?: boolean,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type MenuItem = ItemGroup | MenuAction
|
|
44
|
+
|
|
45
|
+
export interface SelectorItem extends Action {
|
|
46
|
+
/**
|
|
47
|
+
* A unique id for this item.
|
|
48
|
+
*/
|
|
49
|
+
key: string,
|
|
50
|
+
/**
|
|
51
|
+
* An icon to place at the left side of the item.
|
|
52
|
+
*/
|
|
53
|
+
icon?: ReactElement,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface Selector {
|
|
57
|
+
/**
|
|
58
|
+
* The current value. Must correspond to a `key` in `options`.
|
|
59
|
+
*/
|
|
60
|
+
value?: string,
|
|
61
|
+
/**
|
|
62
|
+
* A series of options to show in the selector.
|
|
63
|
+
*/
|
|
64
|
+
options: SelectorItem[],
|
|
65
|
+
/**
|
|
66
|
+
* An extra button to show after the list of options.
|
|
67
|
+
*/
|
|
68
|
+
button?: Action,
|
|
69
|
+
/**
|
|
70
|
+
* A title of this selector.
|
|
71
|
+
*/
|
|
72
|
+
title?: string,
|
|
73
|
+
/**
|
|
74
|
+
* A subtitle for this selector.
|
|
75
|
+
*/
|
|
76
|
+
subtitle?: string,
|
|
77
|
+
/**
|
|
78
|
+
* Whether or not the options for this selector are loading.
|
|
79
|
+
*/
|
|
80
|
+
loading?: boolean,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface MenuSectionContent {
|
|
84
|
+
/**
|
|
85
|
+
* A link to go back.
|
|
86
|
+
*/
|
|
87
|
+
goBack?: Action,
|
|
88
|
+
/**
|
|
89
|
+
* A title for this menu.
|
|
90
|
+
*/
|
|
91
|
+
title?: string,
|
|
92
|
+
/**
|
|
93
|
+
* A subtitle for this menu.
|
|
94
|
+
*/
|
|
95
|
+
subtitle?: string,
|
|
96
|
+
/**
|
|
97
|
+
* A custom React Node to add right after the menu title.
|
|
98
|
+
*/
|
|
99
|
+
afterTitle?: React.ReactNode,
|
|
100
|
+
/**
|
|
101
|
+
* A page selector.
|
|
102
|
+
*/
|
|
103
|
+
pageSelector?: Selector,
|
|
104
|
+
/**
|
|
105
|
+
* The menu options, may contain subgroups.
|
|
106
|
+
*/
|
|
107
|
+
options?: MenuItem[],
|
|
108
|
+
/**
|
|
109
|
+
* Whether or not the options for this menu are loading.
|
|
110
|
+
*/
|
|
111
|
+
loading?: boolean,
|
|
112
|
+
/**
|
|
113
|
+
* An error to show instead of the menu.
|
|
114
|
+
*/
|
|
115
|
+
error?: string,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface MenuSection extends Action {
|
|
119
|
+
/**
|
|
120
|
+
* The icon for this section.
|
|
121
|
+
*/
|
|
122
|
+
icon: ReactElement,
|
|
123
|
+
/**
|
|
124
|
+
* The content or a function that creates the content.
|
|
125
|
+
* If this is a function, it will be called only when the section is hovered, i.e. only when the content really needs to be rendered.
|
|
126
|
+
* Tip: this function can be a React Hook.
|
|
127
|
+
*/
|
|
128
|
+
content?: MenuSectionContent | (() => MenuSectionContent),
|
|
129
|
+
/**
|
|
130
|
+
* The content or a function that creates the content.
|
|
131
|
+
* If this is a function, it will be called only when the section is hovered, i.e. only when the content really needs to be rendered.
|
|
132
|
+
* Tip: this function can be a React Hook.
|
|
133
|
+
* This should be used when the content you want to render is not the default content
|
|
134
|
+
*/
|
|
135
|
+
customContent?: ReactNode,
|
|
136
|
+
/**
|
|
137
|
+
* Whether or not this section is currently active.
|
|
138
|
+
*/
|
|
139
|
+
active?: boolean,
|
|
140
|
+
/**
|
|
141
|
+
* A css class to pass to the <li> tag.
|
|
142
|
+
*/
|
|
143
|
+
className?: string,
|
|
144
|
+
hidden?: boolean,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface BaseMenuProps {
|
|
148
|
+
/**
|
|
149
|
+
* The sections of the menu.
|
|
150
|
+
*/
|
|
151
|
+
sections?: MenuSection[],
|
|
152
|
+
/**
|
|
153
|
+
* The content of the menu as a React Element. Use this to create anything you want as the menu content, but prefer using `content`
|
|
154
|
+
* instead, which is a predefined menu.
|
|
155
|
+
*/
|
|
156
|
+
customContent?: ReactNode,
|
|
157
|
+
/**
|
|
158
|
+
* Options for the settings button.
|
|
159
|
+
*/
|
|
160
|
+
settings?: {
|
|
161
|
+
/**
|
|
162
|
+
* Whether or not to show the settings button.
|
|
163
|
+
*/
|
|
164
|
+
show?: boolean,
|
|
165
|
+
/**
|
|
166
|
+
* A function to call when the button is clicked.
|
|
167
|
+
*/
|
|
168
|
+
onClick?: () => void,
|
|
169
|
+
/**
|
|
170
|
+
* A url to go to when the button is clicked.
|
|
171
|
+
*/
|
|
172
|
+
href?: string,
|
|
173
|
+
/**
|
|
174
|
+
* Whether or not this button represents the page currently active.
|
|
175
|
+
*/
|
|
176
|
+
active?: boolean,
|
|
177
|
+
/**
|
|
178
|
+
* A css class to pass to the button.
|
|
179
|
+
*/
|
|
180
|
+
className?: string,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface MenuPropsWithStaticContent extends BaseMenuProps {
|
|
185
|
+
/**
|
|
186
|
+
* The config for creating the menu content.
|
|
187
|
+
*/
|
|
188
|
+
content?: MenuSectionContent,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface MenuPropsWithDynamicContent extends BaseMenuProps {
|
|
192
|
+
/**
|
|
193
|
+
* The function that creates a config to render a menu content. It will be called only when the content is rendered, i.e. only when the
|
|
194
|
+
* content really needs to be rendered.
|
|
195
|
+
*
|
|
196
|
+
* Tip: this function can be a React Hook.
|
|
197
|
+
*/
|
|
198
|
+
content: MenuSectionContent | (() => MenuSectionContent),
|
|
199
|
+
/**
|
|
200
|
+
* Identifies each content that might be rendered by the menu. This prevents React Hook errors when the content is a React Hook function.
|
|
201
|
+
*/
|
|
202
|
+
contentKey: React.Key,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export type MenuProps = MenuPropsWithStaticContent | MenuPropsWithDynamicContent
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { Box, Image, Text } from '@citric/core'
|
|
2
|
-
import { TourStep, tourStepBuilder } from '@stack-spot/portal-components/Tour'
|
|
3
|
-
import { useTranslate } from '@stack-spot/portal-translate'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Tutorial: a React hook for retrieving the React Tour step that explains how the portal switcher works. The portal switcher is a component
|
|
7
|
-
* at the top left corner of the layout (header) that allows the user to switch between the different Stackspot portals.
|
|
8
|
-
* @returns the React Tour step for the PortalSwitcher.
|
|
9
|
-
*/
|
|
10
|
-
export const usePortalSwitcherStep = (): TourStep => {
|
|
11
|
-
const t = useTranslate(translations)
|
|
12
|
-
return tourStepBuilder({
|
|
13
|
-
selector: '.portal-switcher',
|
|
14
|
-
title: t.title,
|
|
15
|
-
content: <>
|
|
16
|
-
<Image src="https://marketing.stackspot.com/switch-v2.gif" alt={t.imageAlt} />
|
|
17
|
-
<Box px={5} py={3}>
|
|
18
|
-
<Text appearance="microtext1" colorScheme="inverse.contrastText">{t.description}</Text>
|
|
19
|
-
</Box>
|
|
20
|
-
</>,
|
|
21
|
-
position: 'right',
|
|
22
|
-
style: {
|
|
23
|
-
width: '300px',
|
|
24
|
-
},
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const translations = {
|
|
29
|
-
en: {
|
|
30
|
-
title: 'Expand Your Horizons with Stackspot',
|
|
31
|
-
description: 'Easily switch between EDP and AI to enhance your projects. Access a wide range of resources with just one click and take your projects to a new level of efficiency. Start your journey now!',
|
|
32
|
-
imageAlt: 'GIF describing how to use product switcher and navigate between AI and EDP portals',
|
|
33
|
-
},
|
|
34
|
-
pt: {
|
|
35
|
-
title: 'Expanda Seus Horizontes com Stackspot',
|
|
36
|
-
description: 'Troque facilmente entre EDP e AI para aprimorar seus projetos. Acesse uma ampla gama de recursos com apenas um clique e leve seus projetos para um novo nível de eficiência. Comece sua jornada agora!',
|
|
37
|
-
imageAlt: 'GIF mostrando como usar o alternador de produtos e navegar entre os portais AI e EDP',
|
|
38
|
-
},
|
|
39
|
-
}
|
|
1
|
+
import { Box, Image, Text } from '@citric/core'
|
|
2
|
+
import { TourStep, tourStepBuilder } from '@stack-spot/portal-components/Tour'
|
|
3
|
+
import { useTranslate } from '@stack-spot/portal-translate'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Tutorial: a React hook for retrieving the React Tour step that explains how the portal switcher works. The portal switcher is a component
|
|
7
|
+
* at the top left corner of the layout (header) that allows the user to switch between the different Stackspot portals.
|
|
8
|
+
* @returns the React Tour step for the PortalSwitcher.
|
|
9
|
+
*/
|
|
10
|
+
export const usePortalSwitcherStep = (): TourStep => {
|
|
11
|
+
const t = useTranslate(translations)
|
|
12
|
+
return tourStepBuilder({
|
|
13
|
+
selector: '.portal-switcher',
|
|
14
|
+
title: t.title,
|
|
15
|
+
content: <>
|
|
16
|
+
<Image src="https://marketing.stackspot.com/switch-v2.gif" alt={t.imageAlt} />
|
|
17
|
+
<Box px={5} py={3}>
|
|
18
|
+
<Text appearance="microtext1" colorScheme="inverse.contrastText">{t.description}</Text>
|
|
19
|
+
</Box>
|
|
20
|
+
</>,
|
|
21
|
+
position: 'right',
|
|
22
|
+
style: {
|
|
23
|
+
width: '300px',
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const translations = {
|
|
29
|
+
en: {
|
|
30
|
+
title: 'Expand Your Horizons with Stackspot',
|
|
31
|
+
description: 'Easily switch between EDP and AI to enhance your projects. Access a wide range of resources with just one click and take your projects to a new level of efficiency. Start your journey now!',
|
|
32
|
+
imageAlt: 'GIF describing how to use product switcher and navigate between AI and EDP portals',
|
|
33
|
+
},
|
|
34
|
+
pt: {
|
|
35
|
+
title: 'Expanda Seus Horizontes com Stackspot',
|
|
36
|
+
description: 'Troque facilmente entre EDP e AI para aprimorar seus projetos. Acesse uma ampla gama de recursos com apenas um clique e leve seus projetos para um novo nível de eficiência. Comece sua jornada agora!',
|
|
37
|
+
imageAlt: 'GIF mostrando como usar o alternador de produtos e navegar entre os portais AI e EDP',
|
|
38
|
+
},
|
|
39
|
+
}
|
package/src/components/types.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export type PortalAcronym = 'EDP' | 'AI' | 'HUB'
|
|
1
|
+
export type PortalAcronym = 'EDP' | 'AI' | 'HUB'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type UserMenuManagerListeners = (visible: boolean) => void
|
|
2
|
+
|
|
3
|
+
class UserMenuManager {
|
|
4
|
+
private visible: boolean = false
|
|
5
|
+
private observers = [] as UserMenuManagerListeners[]
|
|
6
|
+
|
|
7
|
+
changeVisible(isVisible: boolean): void {
|
|
8
|
+
this.visible = isVisible
|
|
9
|
+
this.notify()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
isOpen(): boolean {
|
|
13
|
+
return this.visible
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
subscribe(updateFn: UserMenuManagerListeners) {
|
|
17
|
+
this.observers.push(updateFn)
|
|
18
|
+
this.notify()
|
|
19
|
+
return () => this.pullListener(updateFn)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private pullListener(updateFn: UserMenuManagerListeners) {
|
|
23
|
+
this.observers = this.observers.filter((obs) => obs !== updateFn)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private notify() {
|
|
27
|
+
this.observers.forEach((updateFn) => updateFn(this.visible))
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const userMenuManager = new UserMenuManager()
|
package/src/dictionary.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { Dictionary, getLanguage, useTranslate } from '@stack-spot/portal-translate'
|
|
2
|
-
|
|
3
|
-
const dictionary = {
|
|
4
|
-
en: {
|
|
5
|
-
close: 'Close',
|
|
6
|
-
validationLabel: 'Please, confirm the action by typing "$0" below:',
|
|
7
|
-
dismiss: 'Dismiss',
|
|
8
|
-
confirm: 'OK',
|
|
9
|
-
cancel: 'Cancel',
|
|
10
|
-
},
|
|
11
|
-
pt: {
|
|
12
|
-
close: 'Fechar',
|
|
13
|
-
validationLabel: 'Por favor, confirme a ação digitando "$0" no campo abaixo:',
|
|
14
|
-
dismiss: 'Dispensar',
|
|
15
|
-
confirm: 'OK',
|
|
16
|
-
cancel: 'Cancelar',
|
|
17
|
-
},
|
|
18
|
-
} satisfies Dictionary
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A global dictionary for layout components.
|
|
22
|
-
*/
|
|
23
|
-
export const useDictionary = () => useTranslate(dictionary)
|
|
24
|
-
|
|
25
|
-
export function getDictionary() {
|
|
26
|
-
const language = getLanguage()
|
|
27
|
-
return dictionary[language]
|
|
28
|
-
}
|
|
1
|
+
import { Dictionary, getLanguage, useTranslate } from '@stack-spot/portal-translate'
|
|
2
|
+
|
|
3
|
+
const dictionary = {
|
|
4
|
+
en: {
|
|
5
|
+
close: 'Close',
|
|
6
|
+
validationLabel: 'Please, confirm the action by typing "$0" below:',
|
|
7
|
+
dismiss: 'Dismiss',
|
|
8
|
+
confirm: 'OK',
|
|
9
|
+
cancel: 'Cancel',
|
|
10
|
+
},
|
|
11
|
+
pt: {
|
|
12
|
+
close: 'Fechar',
|
|
13
|
+
validationLabel: 'Por favor, confirme a ação digitando "$0" no campo abaixo:',
|
|
14
|
+
dismiss: 'Dispensar',
|
|
15
|
+
confirm: 'OK',
|
|
16
|
+
cancel: 'Cancelar',
|
|
17
|
+
},
|
|
18
|
+
} satisfies Dictionary
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A global dictionary for layout components.
|
|
22
|
+
*/
|
|
23
|
+
export const useDictionary = () => useTranslate(dictionary)
|
|
24
|
+
|
|
25
|
+
export function getDictionary() {
|
|
26
|
+
const language = getLanguage()
|
|
27
|
+
return dictionary[language]
|
|
28
|
+
}
|
package/src/elements.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The ids of the layout elements.
|
|
3
|
-
*/
|
|
4
|
-
export const elementIds = {
|
|
5
|
-
layout: 'layout',
|
|
6
|
-
backdrop: 'backdrop',
|
|
7
|
-
modal: 'modal',
|
|
8
|
-
rightPanel: 'rightPanel',
|
|
9
|
-
bottomDialog: 'bottomDialog',
|
|
10
|
-
page: 'page',
|
|
11
|
-
content: 'content',
|
|
12
|
-
header: 'header',
|
|
13
|
-
menu: 'menu',
|
|
14
|
-
menuContent: 'menuContent',
|
|
15
|
-
menuSections: 'menuSections',
|
|
16
|
-
accessibilityAnnouncer: 'accessibilityAnnouncer',
|
|
17
|
-
} as const
|
|
18
|
-
|
|
19
|
-
export type LayoutElement = keyof typeof elementIds
|
|
20
|
-
export type LayoutElements = Record<LayoutElement, HTMLElement | null>
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @returns an object with the html elements of the layout.
|
|
24
|
-
*/
|
|
25
|
-
export function getLayoutElements() {
|
|
26
|
-
return (Object.keys(elementIds) as LayoutElement[]).reduce<LayoutElements>(
|
|
27
|
-
(result, id) => ({ ...result, [id]: document.getElementById(id) }),
|
|
28
|
-
{} as LayoutElements,
|
|
29
|
-
)
|
|
30
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* The ids of the layout elements.
|
|
3
|
+
*/
|
|
4
|
+
export const elementIds = {
|
|
5
|
+
layout: 'layout',
|
|
6
|
+
backdrop: 'backdrop',
|
|
7
|
+
modal: 'modal',
|
|
8
|
+
rightPanel: 'rightPanel',
|
|
9
|
+
bottomDialog: 'bottomDialog',
|
|
10
|
+
page: 'page',
|
|
11
|
+
content: 'content',
|
|
12
|
+
header: 'header',
|
|
13
|
+
menu: 'menu',
|
|
14
|
+
menuContent: 'menuContent',
|
|
15
|
+
menuSections: 'menuSections',
|
|
16
|
+
accessibilityAnnouncer: 'accessibilityAnnouncer',
|
|
17
|
+
} as const
|
|
18
|
+
|
|
19
|
+
export type LayoutElement = keyof typeof elementIds
|
|
20
|
+
export type LayoutElements = Record<LayoutElement, HTMLElement | null>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @returns an object with the html elements of the layout.
|
|
24
|
+
*/
|
|
25
|
+
export function getLayoutElements() {
|
|
26
|
+
return (Object.keys(elementIds) as LayoutElement[]).reduce<LayoutElements>(
|
|
27
|
+
(result, id) => ({ ...result, [id]: document.getElementById(id) }),
|
|
28
|
+
{} as LayoutElements,
|
|
29
|
+
)
|
|
30
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export class LayoutError extends Error {
|
|
2
|
-
constructor(message: string) {
|
|
3
|
-
super(`Layout error: ${message}`)
|
|
4
|
-
}
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export class ElementNotFound extends LayoutError {
|
|
8
|
-
constructor(elementName: string, elementId: string) {
|
|
9
|
-
super(`unable to create ${elementName} because no element with id "${elementId}" was found in the view.`)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
1
|
+
export class LayoutError extends Error {
|
|
2
|
+
constructor(message: string) {
|
|
3
|
+
super(`Layout error: ${message}`)
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class ElementNotFound extends LayoutError {
|
|
8
|
+
constructor(elementName: string, elementId: string) {
|
|
9
|
+
super(`unable to create ${elementName} because no element with id "${elementId}" was found in the view.`)
|
|
10
|
+
}
|
|
11
|
+
}
|