@stack-spot/portal-layout 0.0.3 → 0.0.4
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/dist/Layout.d.ts +17 -3
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +8 -4
- package/dist/Layout.js.map +1 -1
- package/dist/LayoutOverlayManager.d.ts.map +1 -1
- package/dist/LayoutOverlayManager.js +10 -7
- package/dist/LayoutOverlayManager.js.map +1 -1
- package/dist/components/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog.js +4 -1
- package/dist/components/Dialog.js.map +1 -1
- package/dist/components/Header.d.ts +2 -1
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +1 -1
- package/dist/components/Header.js.map +1 -1
- package/dist/components/Menu/MenuContent.d.ts.map +1 -1
- package/dist/components/Menu/MenuContent.js +12 -5
- package/dist/components/Menu/MenuContent.js.map +1 -1
- package/dist/components/Menu/MenuSections.d.ts +1 -0
- package/dist/components/Menu/MenuSections.d.ts.map +1 -1
- package/dist/components/Menu/MenuSections.js +12 -5
- package/dist/components/Menu/MenuSections.js.map +1 -1
- package/dist/components/Menu/PageSelector.d.ts.map +1 -1
- package/dist/components/Menu/PageSelector.js +1 -1
- package/dist/components/Menu/PageSelector.js.map +1 -1
- package/dist/components/Menu/types.d.ts +7 -0
- package/dist/components/Menu/types.d.ts.map +1 -1
- package/dist/components/OverlayContent.d.ts.map +1 -1
- package/dist/components/OverlayContent.js +5 -1
- package/dist/components/OverlayContent.js.map +1 -1
- package/dist/components/SelectionList.d.ts +2 -1
- package/dist/components/SelectionList.d.ts.map +1 -1
- package/dist/components/SelectionList.js +3 -3
- package/dist/components/SelectionList.js.map +1 -1
- package/dist/components/Toaster.d.ts.map +1 -1
- package/dist/components/Toaster.js +5 -1
- package/dist/components/Toaster.js.map +1 -1
- package/dist/dictionary.d.ts +15 -0
- package/dist/dictionary.d.ts.map +1 -0
- package/dist/dictionary.js +23 -0
- package/dist/dictionary.js.map +1 -0
- package/dist/layout.css +22 -8
- package/package.json +4 -3
- package/src/Layout.tsx +34 -12
- package/src/LayoutOverlayManager.tsx +15 -10
- package/src/components/Dialog.tsx +4 -1
- package/src/components/Header.tsx +3 -2
- package/src/components/Menu/MenuContent.tsx +12 -4
- package/src/components/Menu/MenuSections.tsx +14 -6
- package/src/components/Menu/PageSelector.tsx +1 -0
- package/src/components/Menu/types.ts +7 -0
- package/src/components/OverlayContent.tsx +16 -12
- package/src/components/SelectionList.tsx +5 -3
- package/src/components/Toaster.tsx +9 -5
- package/src/dictionary.ts +25 -0
- package/src/layout.css +22 -8
- package/src/citric.fix.d.ts +0 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectionList.js","sourceRoot":"","sources":["../../src/components/SelectionList.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAa,WAAW,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,EAAgB,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAmC1C,MAAM,qBAAqB,GAAG,GAAG,CAAA;
|
|
1
|
+
{"version":3,"file":"SelectionList.js","sourceRoot":"","sources":["../../src/components/SelectionList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../src/components/Toaster.tsx"],"names":[],"mappings":"AAGA,OAAO,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../src/components/Toaster.tsx"],"names":[],"mappings":"AAGA,OAAO,uCAAuC,CAAA;AAY9C,eAAO,MAAM,OAAO,+CAAqD,CAAA"}
|
|
@@ -3,6 +3,10 @@ import { TimesMini } from '@citric/icons';
|
|
|
3
3
|
import { IconButton } from '@citric/ui';
|
|
4
4
|
import { ToastContainer } from 'react-toastify';
|
|
5
5
|
import 'react-toastify/dist/ReactToastify.css';
|
|
6
|
-
|
|
6
|
+
import { useDictionary } from '../dictionary';
|
|
7
|
+
const CloseButton = ({ closeToast }) => {
|
|
8
|
+
const t = useDictionary();
|
|
9
|
+
return (_jsx(IconButton, { onClick: () => closeToast(null), title: t.dismiss, children: _jsx(TimesMini, {}) }));
|
|
10
|
+
};
|
|
7
11
|
export const Toaster = () => _jsx(ToastContainer, { closeButton: CloseButton });
|
|
8
12
|
//# sourceMappingURL=Toaster.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.js","sourceRoot":"","sources":["../../src/components/Toaster.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAoB,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACjE,OAAO,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"Toaster.js","sourceRoot":"","sources":["../../src/components/Toaster.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAoB,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACjE,OAAO,uCAAuC,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,WAAW,GAAG,CAAC,EAAE,UAAU,EAAoB,EAAE,EAAE;IACvD,MAAM,CAAC,GAAG,aAAa,EAAE,CAAA;IACzB,OAAO,CACL,KAAC,UAAU,IAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,YAClE,KAAC,SAAS,KAAG,GACF,CACd,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,KAAC,cAAc,IAAC,WAAW,EAAE,WAAW,GAAI,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const useDictionary: () => Record<"cancel" | "close" | "validationLabel" | "dismiss" | "confirm", string>;
|
|
2
|
+
export declare function getDictionary(): {
|
|
3
|
+
close: string;
|
|
4
|
+
validationLabel: string;
|
|
5
|
+
dismiss: string;
|
|
6
|
+
confirm: string;
|
|
7
|
+
cancel: string;
|
|
8
|
+
} | {
|
|
9
|
+
close: string;
|
|
10
|
+
validationLabel: string;
|
|
11
|
+
dismiss: string;
|
|
12
|
+
confirm: string;
|
|
13
|
+
cancel: string;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=dictionary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary.d.ts","sourceRoot":"","sources":["../src/dictionary.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,aAAa,sFAAiC,CAAA;AAE3D,wBAAgB,aAAa;;;;;;;;;;;;EAG5B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getLanguage, useTranslate } from '@stack-spot/portal-translate';
|
|
2
|
+
const dictionary = {
|
|
3
|
+
en: {
|
|
4
|
+
close: 'Close',
|
|
5
|
+
validationLabel: 'Please, confirm the action by typing "$0" below:',
|
|
6
|
+
dismiss: 'Dismiss',
|
|
7
|
+
confirm: 'OK',
|
|
8
|
+
cancel: 'Cancel',
|
|
9
|
+
},
|
|
10
|
+
pt: {
|
|
11
|
+
close: 'Fechar',
|
|
12
|
+
validationLabel: 'Por favor, confirme a ação digitando "$0" no campo abaixo:',
|
|
13
|
+
dismiss: 'Dispensar',
|
|
14
|
+
confirm: 'OK',
|
|
15
|
+
cancel: 'Cancelar',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
export const useDictionary = () => useTranslate(dictionary);
|
|
19
|
+
export function getDictionary() {
|
|
20
|
+
const language = getLanguage();
|
|
21
|
+
return dictionary[language];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=dictionary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary.js","sourceRoot":"","sources":["../src/dictionary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,WAAW,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAEpF,MAAM,UAAU,GAAG;IACjB,EAAE,EAAE;QACF,KAAK,EAAE,OAAO;QACd,eAAe,EAAE,kDAAkD;QACnE,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,QAAQ;KACjB;IACD,EAAE,EAAE;QACF,KAAK,EAAE,QAAQ;QACf,eAAe,EAAE,4DAA4D;QAC7E,OAAO,EAAE,WAAW;QACpB,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,UAAU;KACnB;CACmB,CAAA;AAEtB,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;AAE3D,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAA;AAC7B,CAAC"}
|
package/dist/layout.css
CHANGED
|
@@ -68,20 +68,23 @@ body {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
#page {
|
|
71
|
-
|
|
71
|
+
position: absolute;
|
|
72
|
+
top: var(--header-height);
|
|
73
|
+
left: var(--menu-sections-width);
|
|
74
|
+
right: 0;
|
|
75
|
+
bottom: 0;
|
|
76
|
+
overflow-y: auto;
|
|
72
77
|
display: flex;
|
|
73
78
|
flex-direction: column;
|
|
74
79
|
background-color: var(--light-300);
|
|
75
80
|
border-top-left-radius: 0.5rem;
|
|
76
81
|
align-items: center;
|
|
77
82
|
padding: 24px;
|
|
78
|
-
|
|
79
|
-
margin-left: var(--menu-sections-width);
|
|
80
|
-
transition: margin ease-in-out var(--menu-animation-duration);
|
|
83
|
+
transition: left ease-in-out var(--menu-animation-duration);
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
#layout.menu-content-visible #page {
|
|
84
|
-
|
|
87
|
+
left: calc(var(--menu-sections-width) + var(--menu-content-width));
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
#content {
|
|
@@ -330,7 +333,7 @@ body {
|
|
|
330
333
|
bottom: -420px;
|
|
331
334
|
left: 20px;
|
|
332
335
|
height: 400px;
|
|
333
|
-
transition:
|
|
336
|
+
transition: bottom 0.3s;
|
|
334
337
|
}
|
|
335
338
|
|
|
336
339
|
#bottomPanel.visible {
|
|
@@ -340,12 +343,23 @@ body {
|
|
|
340
343
|
#bottomDialog {
|
|
341
344
|
position: fixed;
|
|
342
345
|
display: flex;
|
|
343
|
-
flex-direction:
|
|
346
|
+
flex-direction: row;
|
|
344
347
|
bottom: -80px;
|
|
345
348
|
left: 0;
|
|
346
349
|
right: 0;
|
|
347
350
|
height: 80px;
|
|
348
|
-
transition:
|
|
351
|
+
transition: bottom 0.3s;
|
|
352
|
+
background-color: var(--inverse-500);
|
|
353
|
+
color: var(--inverse-contrastText);
|
|
354
|
+
justify-content: center;
|
|
355
|
+
align-items: center;
|
|
356
|
+
gap: 16px;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
#bottomDialog .btn-group {
|
|
360
|
+
display: flex;
|
|
361
|
+
flex-direction: row;
|
|
362
|
+
gap: 8px;
|
|
349
363
|
}
|
|
350
364
|
|
|
351
365
|
#bottomDialog.visible {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/portal-layout",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
"@citric/core": "^5.3.1",
|
|
9
9
|
"@citric/icons": "^5.3.1",
|
|
10
10
|
"@citric/ui": "^5.3.1",
|
|
11
|
-
"@stack-spot/portal-theme": "0.0.3",
|
|
11
|
+
"@stack-spot/portal-theme": "^0.0.3",
|
|
12
|
+
"@stack-spot/portal-translate": "^0.0.4",
|
|
12
13
|
"react": "^18.2.0",
|
|
13
14
|
"react-dom": "^18.2.0",
|
|
14
|
-
"styled-components": "6.1.1"
|
|
15
|
+
"styled-components": "^6.1.1"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/react": "^18.2.37",
|
package/src/Layout.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CSSToCitricAdapter, listToClass, WithStyle } from '@stack-spot/portal-theme'
|
|
2
2
|
import '@stack-spot/portal-theme/dist/theme.css'
|
|
3
|
-
import { ReactElement, ReactNode } from 'react'
|
|
3
|
+
import { ComponentClass, ReactElement, ReactNode } from 'react'
|
|
4
4
|
import { Header, HeaderProps } from './components/Header'
|
|
5
5
|
import { MenuContent } from './components/Menu/MenuContent'
|
|
6
6
|
import { MenuSections } from './components/Menu/MenuSections'
|
|
@@ -9,10 +9,23 @@ import { Toaster } from './components/Toaster'
|
|
|
9
9
|
import './layout.css'
|
|
10
10
|
import { overlay } from './LayoutOverlayManager'
|
|
11
11
|
|
|
12
|
+
type ErrorBoundaryComponent = ComponentClass<{ children: ReactNode }>
|
|
13
|
+
|
|
14
|
+
interface ErrorBoundaries {
|
|
15
|
+
page?: ErrorBoundaryComponent,
|
|
16
|
+
menuSections?: ErrorBoundaryComponent,
|
|
17
|
+
menuContent?: ErrorBoundaryComponent,
|
|
18
|
+
modal?: ErrorBoundaryComponent,
|
|
19
|
+
rightPanel?: ErrorBoundaryComponent,
|
|
20
|
+
header?: ErrorBoundaryComponent,
|
|
21
|
+
bottomDialog?: ErrorBoundaryComponent,
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
interface Props extends WithStyle {
|
|
13
25
|
menu: MenuProps,
|
|
14
26
|
header: HeaderProps,
|
|
15
27
|
children: ReactNode,
|
|
28
|
+
errorBoundaries?: ErrorBoundaries,
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
interface RawProps extends WithStyle {
|
|
@@ -21,9 +34,12 @@ interface RawProps extends WithStyle {
|
|
|
21
34
|
header: ReactElement,
|
|
22
35
|
children: ReactNode,
|
|
23
36
|
compactMenu?: boolean,
|
|
37
|
+
errorBoundaries?: ErrorBoundaries,
|
|
24
38
|
}
|
|
25
39
|
|
|
26
|
-
export const RawLayout = (
|
|
40
|
+
export const RawLayout = (
|
|
41
|
+
{ menuSections, menuContent, header, compactMenu = true, children, errorBoundaries = {}, className, style }: RawProps,
|
|
42
|
+
) => {
|
|
27
43
|
// @ts-ignore
|
|
28
44
|
const { bottomDialog, modal, rightPanel } = overlay.useOverlays()
|
|
29
45
|
const classes = [
|
|
@@ -32,21 +48,26 @@ export const RawLayout = ({ menuSections, menuContent, header, compactMenu = tru
|
|
|
32
48
|
className,
|
|
33
49
|
]
|
|
34
50
|
|
|
51
|
+
function includeErrorBoundary(content: ReactNode, section: keyof ErrorBoundaries) {
|
|
52
|
+
const ErrorBoundary = errorBoundaries[section]
|
|
53
|
+
return ErrorBoundary ? <ErrorBoundary>{content}</ErrorBoundary> : content
|
|
54
|
+
}
|
|
55
|
+
|
|
35
56
|
return (
|
|
36
57
|
<CSSToCitricAdapter>
|
|
37
58
|
<div id="layout" className={listToClass(classes)} style={style}>
|
|
38
|
-
<header id="header">{header}</header>
|
|
39
|
-
<aside id="menu">
|
|
40
|
-
<nav id="menuContent">{menuContent}</nav>
|
|
41
|
-
<nav id="menuSections">{menuSections}</nav>
|
|
42
|
-
</aside>
|
|
43
59
|
<div id="page">
|
|
44
|
-
<article id="content">{children}</article>
|
|
60
|
+
<article id="content">{includeErrorBoundary(children, 'page')}</article>
|
|
45
61
|
</div>
|
|
46
|
-
<
|
|
47
|
-
<
|
|
62
|
+
<header id="header">{includeErrorBoundary(header, 'header')}</header>
|
|
63
|
+
<aside id="menu">
|
|
64
|
+
<nav id="menuContent">{includeErrorBoundary(menuContent, 'menuContent')}</nav>
|
|
65
|
+
<nav id="menuSections">{includeErrorBoundary(menuSections, 'menuSections')}</nav>
|
|
66
|
+
</aside>
|
|
67
|
+
<div id="rightPanel">{includeErrorBoundary(rightPanel, 'rightPanel')}</div>
|
|
68
|
+
<div id="bottomDialog">{includeErrorBoundary(bottomDialog, 'bottomDialog')}</div>
|
|
48
69
|
<div id="backdrop">
|
|
49
|
-
<div id="modal">{modal}</div>
|
|
70
|
+
<div id="modal">{includeErrorBoundary(modal, 'modal')}</div>
|
|
50
71
|
</div>
|
|
51
72
|
<Toaster />
|
|
52
73
|
</div>
|
|
@@ -59,7 +80,7 @@ const MenuContentRenderer = ({ content }: Required<Pick<Props['menu'], 'content'
|
|
|
59
80
|
return <MenuContent {...menuContent} />
|
|
60
81
|
}
|
|
61
82
|
|
|
62
|
-
export const Layout = ({ menu, header, children, className, style }: Props) => (
|
|
83
|
+
export const Layout = ({ menu, header, children, errorBoundaries, className, style }: Props) => (
|
|
63
84
|
<RawLayout
|
|
64
85
|
header={<Header {...header} />}
|
|
65
86
|
menuSections={<MenuSections {...menu} />}
|
|
@@ -68,6 +89,7 @@ export const Layout = ({ menu, header, children, className, style }: Props) => (
|
|
|
68
89
|
: undefined
|
|
69
90
|
}
|
|
70
91
|
compactMenu={menu.compact}
|
|
92
|
+
errorBoundaries={errorBoundaries}
|
|
71
93
|
className={className}
|
|
72
94
|
style={style}
|
|
73
95
|
>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
2
|
|
|
3
|
-
import { Button
|
|
3
|
+
import { Button } from '@citric/core'
|
|
4
4
|
import { ReactElement, useLayoutEffect, useState } from 'react'
|
|
5
5
|
import { Dialog, DialogOptions } from './components/Dialog'
|
|
6
6
|
import { OverlayContent, OverlayContentProps } from './components/OverlayContent'
|
|
7
|
+
import { getDictionary } from './dictionary'
|
|
7
8
|
import { ElementNotFound, LayoutError } from './errors'
|
|
8
9
|
import { showToaster as showReactToaster } from './toaster'
|
|
9
10
|
import { valueOfLayoutVar } from './utils'
|
|
@@ -115,24 +116,28 @@ class LayoutOverlayManager {
|
|
|
115
116
|
})
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
confirm({ confirm
|
|
119
|
-
|
|
119
|
+
confirm({ confirm, cancel, ...options }: DialogOptions): Promise<boolean> {
|
|
120
|
+
const t = getDictionary()
|
|
121
|
+
return this.showDialog({ ...options, confirm: confirm || t.confirm, cancel: cancel || t.cancel })
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
async alert({ confirm
|
|
123
|
-
|
|
124
|
+
async alert({ confirm, showButton = true, ...options }: AlertOptions): Promise<void> {
|
|
125
|
+
const t = getDictionary()
|
|
126
|
+
await this.showDialog({ ...options, confirm: showButton ? (confirm || t.confirm) : undefined })
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
showBottomDialog({ message, cancel, confirm }: BottomDialogOptions): Promise<boolean> {
|
|
127
130
|
if (!this.elements?.bottomDialog) throw new ElementNotFound('bottom dialog', BOTTOM_DIALOG_ID)
|
|
128
131
|
if (!this.setContent.bottomDialog) throw new LayoutError('unable to show bottom dialog, because it has not been setup yet.')
|
|
129
132
|
return new Promise((resolve) => {
|
|
130
|
-
this.setContent.bottomDialog
|
|
131
|
-
|
|
133
|
+
this.setContent.bottomDialog?.(
|
|
134
|
+
<>
|
|
132
135
|
{message}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
<div className="btn-group">
|
|
137
|
+
{cancel && <Button onClick={() => resolve(false)} colorScheme="light" appearance="outlined">{cancel}</Button>}
|
|
138
|
+
{confirm && <Button onClick={() => resolve(true)} colorScheme="light">{confirm}</Button>}
|
|
139
|
+
</div>
|
|
140
|
+
</>,
|
|
136
141
|
)
|
|
137
142
|
this.elements?.bottomDialog?.setAttribute('class', 'visible')
|
|
138
143
|
})
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Button, Flex, Input, Text } from '@citric/core'
|
|
2
|
+
import { interpolate } from '@stack-spot/portal-translate'
|
|
2
3
|
import { ReactNode, useState } from 'react'
|
|
4
|
+
import { useDictionary } from '../dictionary'
|
|
3
5
|
import { OverlayContent } from './OverlayContent'
|
|
4
6
|
|
|
5
7
|
interface Validation {
|
|
@@ -49,6 +51,7 @@ export const Dialog = ({
|
|
|
49
51
|
buttonPlacement = type === 'panel' ? 'left' : 'right',
|
|
50
52
|
}: Props,
|
|
51
53
|
) => {
|
|
54
|
+
const t = useDictionary()
|
|
52
55
|
const [enabled, setEnabled] = useState(!validation)
|
|
53
56
|
|
|
54
57
|
function renderValidation() {
|
|
@@ -56,7 +59,7 @@ export const Dialog = ({
|
|
|
56
59
|
const value = typeof validation === 'string' ? validation : validation.value
|
|
57
60
|
const label = typeof validation === 'object' && validation.label
|
|
58
61
|
? validation.label
|
|
59
|
-
:
|
|
62
|
+
: interpolate(t.validationLabel, value)
|
|
60
63
|
const placeholder = typeof validation === 'object' ? validation.placeholder : undefined
|
|
61
64
|
return (
|
|
62
65
|
<div style={{ margin: '16px 0' }}>
|
|
@@ -6,6 +6,7 @@ import { UserMenu } from './UserMenu'
|
|
|
6
6
|
|
|
7
7
|
export interface HeaderProps {
|
|
8
8
|
logo?: ReactNode,
|
|
9
|
+
logoHref?: string,
|
|
9
10
|
userName?: string,
|
|
10
11
|
email?: string,
|
|
11
12
|
options?: SelectionListProps['items'],
|
|
@@ -13,9 +14,9 @@ export interface HeaderProps {
|
|
|
13
14
|
right?: ReactNode,
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
export const Header = ({ logo, center, right, userName, email, options }: HeaderProps) => (
|
|
17
|
+
export const Header = ({ logo, logoHref, center, right, userName, email, options }: HeaderProps) => (
|
|
17
18
|
<>
|
|
18
|
-
{logo ?? <StackspotLogo
|
|
19
|
+
<a href={logoHref} title="Home">{logo ?? <StackspotLogo style={{ width: 130 }} />}</a>
|
|
19
20
|
<Flex flex={1}>{center}</Flex>
|
|
20
21
|
{right}
|
|
21
22
|
{userName && <UserMenu userName={userName} email={email} options={options} />}
|
|
@@ -5,6 +5,7 @@ import { LoadingCircular } from '@citric/ui'
|
|
|
5
5
|
import { listToClass, theme } from '@stack-spot/portal-theme'
|
|
6
6
|
import { useMemo, useState } from 'react'
|
|
7
7
|
import { styled } from 'styled-components'
|
|
8
|
+
import { hideOverlayImmediately } from './MenuSections'
|
|
8
9
|
import { PageSelector } from './PageSelector'
|
|
9
10
|
import { MENU_CONTENT_ITEM_PADDING as ITEM_PADDING, MENU_CONTENT_PADDING as PADDING } from './constants'
|
|
10
11
|
import { ItemGroup, MenuAction, MenuItem, MenuSectionContent } from './types'
|
|
@@ -128,18 +129,23 @@ const Title = styled.header`
|
|
|
128
129
|
margin: ${PADDING}px 0 24px ${PADDING}px;
|
|
129
130
|
`
|
|
130
131
|
|
|
131
|
-
const ActionItem = ({ label, onClick, href, active, icon, overflow = 'wrap' }: MenuAction) => (
|
|
132
|
+
const ActionItem = ({ label, onClick, href, active, icon, badge, overflow = 'wrap' }: MenuAction) => (
|
|
132
133
|
<a
|
|
133
134
|
href={active ? undefined : href}
|
|
134
|
-
onClick={
|
|
135
|
+
onClick={() => {
|
|
136
|
+
if (active) return
|
|
137
|
+
if (onClick) onClick()
|
|
138
|
+
hideOverlayImmediately()
|
|
139
|
+
}}
|
|
135
140
|
className={listToClass(['action', 'item-row', active ? 'active' : undefined])}
|
|
136
141
|
>
|
|
137
142
|
{icon}
|
|
138
143
|
<Text appearance="body2" className={`label ${overflow}`}>{label}</Text>
|
|
144
|
+
{badge}
|
|
139
145
|
</a>
|
|
140
146
|
)
|
|
141
147
|
|
|
142
|
-
const CollapsibleGroupItem = ({ label, open: initiallyOpened, children, icon, overflow = 'wrap' }: ItemGroup) => {
|
|
148
|
+
const CollapsibleGroupItem = ({ label, open: initiallyOpened, children, icon, badge, overflow = 'wrap' }: ItemGroup) => {
|
|
143
149
|
const [open, setOpen] = useState(initiallyOpened ?? children?.some(c => 'active' in c && c.active) ?? false)
|
|
144
150
|
const items = useMemo(() => children?.map(renderOption), [children])
|
|
145
151
|
|
|
@@ -148,6 +154,7 @@ const CollapsibleGroupItem = ({ label, open: initiallyOpened, children, icon, ov
|
|
|
148
154
|
<a onClick={() => setOpen(!open)} className="item-row">
|
|
149
155
|
{icon}
|
|
150
156
|
<Text appearance="body2" className={`label ${overflow}`}>{label}</Text>
|
|
157
|
+
{badge}
|
|
151
158
|
<IconBox><ChevronDown className={listToClass(['chevron', open ? 'open' : ''])} /></IconBox>
|
|
152
159
|
</a>
|
|
153
160
|
<MenuGroup className={open ? 'open' : undefined}>{items}</MenuGroup>
|
|
@@ -155,7 +162,7 @@ const CollapsibleGroupItem = ({ label, open: initiallyOpened, children, icon, ov
|
|
|
155
162
|
)
|
|
156
163
|
}
|
|
157
164
|
|
|
158
|
-
const RootGroupItem = ({ label, children, icon, overflow = 'wrap' }: ItemGroup) => {
|
|
165
|
+
const RootGroupItem = ({ label, children, icon, badge, overflow = 'wrap' }: ItemGroup) => {
|
|
159
166
|
const items = useMemo(() => children?.filter(i => !i.hidden).map(renderOption), [children])
|
|
160
167
|
|
|
161
168
|
return (
|
|
@@ -163,6 +170,7 @@ const RootGroupItem = ({ label, children, icon, overflow = 'wrap' }: ItemGroup)
|
|
|
163
170
|
<div className="item-row">
|
|
164
171
|
{icon}
|
|
165
172
|
<Text appearance="overheader2" colorScheme="light.700" className={`group-title label ${overflow}`}>{label}</Text>
|
|
173
|
+
{badge}
|
|
166
174
|
</div>
|
|
167
175
|
<MenuGroup className="open no-indentation">{items}</MenuGroup>
|
|
168
176
|
</>
|
|
@@ -16,7 +16,8 @@ function hideOverlay() {
|
|
|
16
16
|
hideOverlayTask = window.setTimeout(hideOverlayImmediately, HIDE_OVERLAY_DELAY_MS)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
20
|
+
export function hideOverlayImmediately() {
|
|
20
21
|
document.getElementById(MENU_OVERLAY_ID)?.classList.remove('visible')
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -45,11 +46,18 @@ const Section = ({
|
|
|
45
46
|
onOpen,
|
|
46
47
|
setCurrentOverlay,
|
|
47
48
|
id,
|
|
48
|
-
|
|
49
|
+
hasContent,
|
|
50
|
+
}: MenuSection & { id: number, setCurrentOverlay: (id: number | undefined) => void, hasContent: boolean }) => {
|
|
49
51
|
const contentToRender = typeof content === 'function' ? content() : content
|
|
50
52
|
|
|
51
53
|
function shouldShowOverlay() {
|
|
52
|
-
|
|
54
|
+
/* The overlay should appear if:
|
|
55
|
+
* 1. The section has some content to render OR:
|
|
56
|
+
* 1.1 The section is active and there is a contextual menu for the active page.
|
|
57
|
+
* 2. The section is inactive OR:
|
|
58
|
+
* 2.1. The contextual menu is hidden.
|
|
59
|
+
*/
|
|
60
|
+
return (!!contentToRender || (hasContent && active)) && (!active || !isMenuContentVisible())
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
function showOverlayAndFixArrowPosition(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
|
|
@@ -106,7 +114,7 @@ export const MenuSections = ({ sections, ...props }: MenuProps) => {
|
|
|
106
114
|
const [currentOverlay, setCurrentOverlay] = useState<number | undefined>()
|
|
107
115
|
|
|
108
116
|
const sectionItems = useMemo(
|
|
109
|
-
() => sections.map((s, i) => <Section key={i} id={i} {...s} setCurrentOverlay={setCurrentOverlay} />),
|
|
117
|
+
() => sections.map((s, i) => <Section key={i} id={i} {...s} setCurrentOverlay={setCurrentOverlay} hasContent={!!props.content} />),
|
|
110
118
|
[sections],
|
|
111
119
|
)
|
|
112
120
|
|
|
@@ -126,12 +134,12 @@ export const MenuSections = ({ sections, ...props }: MenuProps) => {
|
|
|
126
134
|
return (
|
|
127
135
|
<>
|
|
128
136
|
<ul>{sectionItems}</ul>
|
|
129
|
-
<button className="toggle" onClick={toggleMenu} title="Toggle menu panel visibility">
|
|
137
|
+
{!!props.content && <button className="toggle" onClick={toggleMenu} title="Toggle menu panel visibility">
|
|
130
138
|
<IconBox>
|
|
131
139
|
<MenuIcon className="expand" />
|
|
132
140
|
<ChevronLeft className="collapse" />
|
|
133
141
|
</IconBox>
|
|
134
|
-
</button>
|
|
142
|
+
</button>}
|
|
135
143
|
<div id="menuContentOverlay" onMouseEnter={showOverlay} onMouseLeave={hideOverlay}>
|
|
136
144
|
{renderMenuOverlay()}
|
|
137
145
|
<div className="arrow"></div>
|
|
@@ -111,6 +111,7 @@ export const PageSelector = ({ options, value, button, loading, title }: Selecto
|
|
|
111
111
|
items={optionsWithIcon}
|
|
112
112
|
onHide={() => setVisible(false)}
|
|
113
113
|
after={button ? <a className="view-all" href={button.href} onClick={button.onClick}>{button.label}</a> : undefined}
|
|
114
|
+
scroll
|
|
114
115
|
/>
|
|
115
116
|
</>
|
|
116
117
|
)
|
|
@@ -3,7 +3,14 @@ import { Action } from '../types'
|
|
|
3
3
|
|
|
4
4
|
interface BaseMenuItem {
|
|
5
5
|
hidden?: boolean,
|
|
6
|
+
/**
|
|
7
|
+
* React element on the left.
|
|
8
|
+
*/
|
|
6
9
|
icon?: React.ReactElement,
|
|
10
|
+
/**
|
|
11
|
+
* React element on the right.
|
|
12
|
+
*/
|
|
13
|
+
badge?: React.ReactElement,
|
|
7
14
|
/**
|
|
8
15
|
* Whether to wrap overflowing text, just hide or hide and add an ellipsis (...).
|
|
9
16
|
* @default 'wrap'
|
|
@@ -4,6 +4,7 @@ import { IconButton } from '@citric/ui'
|
|
|
4
4
|
import { WithStyle, listToClass, theme } from '@stack-spot/portal-theme'
|
|
5
5
|
import { ReactNode } from 'react'
|
|
6
6
|
import { styled } from 'styled-components'
|
|
7
|
+
import { useDictionary } from '../dictionary'
|
|
7
8
|
|
|
8
9
|
export interface OverlayContentProps extends WithStyle {
|
|
9
10
|
title: string,
|
|
@@ -38,15 +39,18 @@ const ContentBox = styled.section`
|
|
|
38
39
|
}
|
|
39
40
|
`
|
|
40
41
|
|
|
41
|
-
export const OverlayContent = ({ children, title, subtitle, className, style, onClose, type }: Props) =>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
export const OverlayContent = ({ children, title, subtitle, className, style, onClose, type }: Props) => {
|
|
43
|
+
const t = useDictionary()
|
|
44
|
+
return (
|
|
45
|
+
<ContentBox style={style} className={listToClass([className, type])}>
|
|
46
|
+
<header>
|
|
47
|
+
<Flex flexDirection="column" flex={1}>
|
|
48
|
+
<Text appearance={type === 'modal' ? 'h3' : 'h4'}>{title}</Text>
|
|
49
|
+
{subtitle && <Text appearance="body2" colorScheme="light.700">{subtitle}</Text>}
|
|
50
|
+
</Flex>
|
|
51
|
+
<IconButton onClick={onClose} title={t.close} aria-label={t.close}><TimesMini /></IconButton>
|
|
52
|
+
</header>
|
|
53
|
+
{children}
|
|
54
|
+
</ContentBox>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -47,11 +47,12 @@ export interface SelectionListProps extends WithStyle {
|
|
|
47
47
|
maxHeight?: string,
|
|
48
48
|
before?: ReactElement,
|
|
49
49
|
after?: ReactElement,
|
|
50
|
+
scroll?: boolean,
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
const SelectionBox = styled.div<{ $maxHeight: string }>`
|
|
53
|
+
const SelectionBox = styled.div<{ $maxHeight: string, $scroll?: boolean }>`
|
|
53
54
|
max-height: 0;
|
|
54
|
-
overflow-y: auto;
|
|
55
|
+
overflow-y: ${({ $scroll }) => $scroll ? 'auto' : 'hidden'};
|
|
55
56
|
overflow-x: hidden;
|
|
56
57
|
transition: max-height ease-in ${ANIMATION_DURATION_MS / 1000}s;
|
|
57
58
|
z-index: 1;
|
|
@@ -145,7 +146,7 @@ function renderItem(item: ListItem, setCurrent: (current: CurrentItemList) => vo
|
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
export const SelectionList = ({
|
|
148
|
-
items, className, style, visible = true, maxHeight = '300px', onHide, before, after,
|
|
149
|
+
items, className, style, visible = true, maxHeight = '300px', onHide, before, after, scroll,
|
|
149
150
|
}: SelectionListProps) => {
|
|
150
151
|
const wrapper = useRef<HTMLDivElement>(null)
|
|
151
152
|
const itemsRef = useRef(items)
|
|
@@ -182,6 +183,7 @@ export const SelectionList = ({
|
|
|
182
183
|
$maxHeight={maxHeight}
|
|
183
184
|
style={style}
|
|
184
185
|
className={listToClass(['selection-list', visible ? 'visible' : undefined, className])}
|
|
186
|
+
$scroll={scroll}
|
|
185
187
|
>
|
|
186
188
|
<div className="selection-list-content">
|
|
187
189
|
{before}
|
|
@@ -2,11 +2,15 @@ import { TimesMini } from '@citric/icons'
|
|
|
2
2
|
import { IconButton } from '@citric/ui'
|
|
3
3
|
import { CloseButtonProps, ToastContainer } from 'react-toastify'
|
|
4
4
|
import 'react-toastify/dist/ReactToastify.css'
|
|
5
|
+
import { useDictionary } from '../dictionary'
|
|
5
6
|
|
|
6
|
-
const CloseButton = ({ closeToast }: CloseButtonProps) =>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const CloseButton = ({ closeToast }: CloseButtonProps) => {
|
|
8
|
+
const t = useDictionary()
|
|
9
|
+
return (
|
|
10
|
+
<IconButton onClick={() => closeToast(null as any)} title={t.dismiss}>
|
|
11
|
+
<TimesMini />
|
|
12
|
+
</IconButton>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
11
15
|
|
|
12
16
|
export const Toaster = () => <ToastContainer closeButton={CloseButton} />
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
export const useDictionary = () => useTranslate(dictionary)
|
|
21
|
+
|
|
22
|
+
export function getDictionary() {
|
|
23
|
+
const language = getLanguage()
|
|
24
|
+
return dictionary[language]
|
|
25
|
+
}
|