@stack-spot/portal-layout 2.0.1 → 2.1.1
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 +16 -0
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +0 -1
- package/dist/Layout.js.map +1 -1
- package/dist/LayoutOverlayManager.d.ts +20 -5
- package/dist/LayoutOverlayManager.d.ts.map +1 -1
- package/dist/LayoutOverlayManager.js +75 -23
- package/dist/LayoutOverlayManager.js.map +1 -1
- package/dist/components/Backdrop.d.ts +10 -0
- package/dist/components/Backdrop.d.ts.map +1 -0
- package/dist/components/Backdrop.js +18 -0
- package/dist/components/Backdrop.js.map +1 -0
- package/dist/components/Header.d.ts +5 -1
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +3 -2
- package/dist/components/Header.js.map +1 -1
- package/dist/components/NotificationCenter/NotificationPanel.d.ts +3 -0
- package/dist/components/NotificationCenter/NotificationPanel.d.ts.map +1 -0
- package/dist/components/NotificationCenter/NotificationPanel.js +16 -0
- package/dist/components/NotificationCenter/NotificationPanel.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.d.ts +3 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.d.ts.map +1 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.js +16 -0
- package/dist/components/NotificationCenter/NotificationPanelHeader.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.d.ts +4 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.d.ts.map +1 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.js +12 -0
- package/dist/components/NotificationCenter/NotificationsPanelFooter.js.map +1 -0
- package/dist/components/NotificationCenter/dictionary.d.ts +2 -0
- package/dist/components/NotificationCenter/dictionary.d.ts.map +1 -0
- package/dist/components/NotificationCenter/dictionary.js +43 -0
- package/dist/components/NotificationCenter/dictionary.js.map +1 -0
- package/dist/components/NotificationCenter/index.d.ts +2 -0
- package/dist/components/NotificationCenter/index.d.ts.map +1 -0
- package/dist/components/NotificationCenter/index.js +36 -0
- package/dist/components/NotificationCenter/index.js.map +1 -0
- package/dist/components/NotificationCenter/styled.d.ts +4 -0
- package/dist/components/NotificationCenter/styled.d.ts.map +1 -0
- package/dist/components/NotificationCenter/styled.js +74 -0
- package/dist/components/NotificationCenter/styled.js.map +1 -0
- package/dist/components/NotificationCenter/tour.d.ts +2 -0
- package/dist/components/NotificationCenter/tour.d.ts.map +1 -0
- package/dist/components/NotificationCenter/tour.js +15 -0
- package/dist/components/NotificationCenter/tour.js.map +1 -0
- package/dist/components/NotificationCenter/types.d.ts +21 -0
- package/dist/components/NotificationCenter/types.d.ts.map +1 -0
- package/dist/components/NotificationCenter/types.js +2 -0
- package/dist/components/NotificationCenter/types.js.map +1 -0
- package/dist/components/NotificationCenter/utils.d.ts +5 -0
- package/dist/components/NotificationCenter/utils.d.ts.map +1 -0
- package/dist/components/NotificationCenter/utils.js +18 -0
- package/dist/components/NotificationCenter/utils.js.map +1 -0
- package/dist/components/error/ErrorBoundary.d.ts +3 -0
- package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +3 -0
- package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/readme.md +1 -0
- package/src/Layout.tsx +0 -1
- package/src/LayoutOverlayManager.tsx +71 -18
- package/src/components/Backdrop.tsx +32 -0
- package/src/components/Header.tsx +7 -1
- package/src/components/NotificationCenter/NotificationPanel.tsx +35 -0
- package/src/components/NotificationCenter/NotificationPanelHeader.tsx +53 -0
- package/src/components/NotificationCenter/NotificationsPanelFooter.tsx +25 -0
- package/src/components/NotificationCenter/dictionary.ts +44 -0
- package/src/components/NotificationCenter/index.tsx +61 -0
- package/src/components/NotificationCenter/styled.ts +75 -0
- package/src/components/NotificationCenter/tour.tsx +19 -0
- package/src/components/NotificationCenter/types.ts +24 -0
- package/src/components/NotificationCenter/utils.ts +20 -0
- package/src/index.ts +4 -4
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const NotificationBox: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
3
|
+
export declare const StyledBackdrop: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").FastOmit<import("../Backdrop.js").BackdropProps, never>> & string & Omit<({ children, visible, onClose, className, style }: import("../Backdrop.js").BackdropProps) => import("react").ReactPortal | null, keyof import("react").Component<any, {}, any>>;
|
|
4
|
+
//# sourceMappingURL=styled.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styled.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationCenter/styled.ts"],"names":[],"mappings":";AAIA,eAAO,MAAM,eAAe,wOA6B3B,CAAA;AAED,eAAO,MAAM,cAAc,+VAuC1B,CAAA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { theme } from '@stack-spot/portal-theme';
|
|
2
|
+
import { styled } from 'styled-components';
|
|
3
|
+
import { Backdrop } from '../Backdrop.js';
|
|
4
|
+
export const NotificationBox = styled.div `
|
|
5
|
+
.notification-button {
|
|
6
|
+
border: none;
|
|
7
|
+
background: transparent;
|
|
8
|
+
margin: 0 40px;
|
|
9
|
+
position: relative;
|
|
10
|
+
|
|
11
|
+
&.loading {
|
|
12
|
+
cursor: progress;
|
|
13
|
+
opacity: 0.5;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&:before {
|
|
17
|
+
content: '';
|
|
18
|
+
position: absolute;
|
|
19
|
+
top: -1px;
|
|
20
|
+
right: -1px;
|
|
21
|
+
width: 12px;
|
|
22
|
+
height: 12px;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
background-color: ${theme.color.danger['500']};
|
|
25
|
+
transform: scale(0);
|
|
26
|
+
transition: transform ease-in 0.3s;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.unread:before {
|
|
30
|
+
transform: scale(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
export const StyledBackdrop = styled(Backdrop) `
|
|
35
|
+
position: absolute;
|
|
36
|
+
top: calc(var(--header-height) + 10px);
|
|
37
|
+
right: 60px;
|
|
38
|
+
box-shadow: 4px 4px 48px ${theme.color.danger.contrastText};
|
|
39
|
+
|
|
40
|
+
.notification-panel {
|
|
41
|
+
width: 368px;
|
|
42
|
+
padding: 16px;
|
|
43
|
+
border-radius: 4px;
|
|
44
|
+
background-color: ${theme.color.light[300]};
|
|
45
|
+
border: 1px solid ${theme.color.light[400]};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.filter-list {
|
|
49
|
+
list-style: none;
|
|
50
|
+
margin: 16px 0;
|
|
51
|
+
padding: 0;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: row;
|
|
54
|
+
justify-content: space-between;
|
|
55
|
+
.filter-btn {
|
|
56
|
+
&:focus {
|
|
57
|
+
border-color: transparent;
|
|
58
|
+
}
|
|
59
|
+
&[aria-pressed="true"] {
|
|
60
|
+
border-color: ${theme.color.primary[500]};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.see-all {
|
|
66
|
+
margin-top: 8px;
|
|
67
|
+
width: 100%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.error-feedback {
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
//# sourceMappingURL=styled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/components/NotificationCenter/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;0BAoBf,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;;;;;;;;;CASlD,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;;;;6BAIjB,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY;;;;;;wBAMpC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;wBACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;wBAetB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAa/C,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tour.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationCenter/tour.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,YAcpC,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from '@citric/core';
|
|
3
|
+
import { useTour } from '../tour/index.js';
|
|
4
|
+
import { useNotificationsDictionary } from './dictionary.js';
|
|
5
|
+
export const useNotificationsTourStep = () => {
|
|
6
|
+
const t = useNotificationsDictionary();
|
|
7
|
+
const { addStep } = useTour();
|
|
8
|
+
addStep({
|
|
9
|
+
content: _jsx(Box, { px: 5, py: 3, children: _jsx(Text, { appearance: "microtext1", colorScheme: "inverse.contrastText", children: t.tour }) }),
|
|
10
|
+
selector: '.notificationsTour',
|
|
11
|
+
title: t.notifications,
|
|
12
|
+
position: 'bottom',
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=tour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tour.js","sourceRoot":"","sources":["../../../src/components/NotificationCenter/tour.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAEzD,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,EAAE;IAC3C,MAAM,CAAC,GAAG,0BAA0B,EAAE,CAAA;IACtC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAA;IAE7B,OAAO,CAAC;QACN,OAAO,EAAE,KAAC,GAAG,IAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YACxB,KAAC,IAAI,IAAC,UAAU,EAAC,YAAY,EAAC,WAAW,EAAC,sBAAsB,YAC7D,CAAC,CAAC,IAAI,GACF,GACH;QACN,QAAQ,EAAE,oBAAoB;QAC9B,KAAK,EAAE,CAAC,CAAC,aAAa;QACtB,QAAQ,EAAE,QAAQ;KACZ,CAAC,CAAA;AACX,CAAC,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NotificationListProps } from '@stack-spot/portal-components/Notifications';
|
|
2
|
+
export type NotificationFilter = 'ALL' | 'UNREAD' | 'HIGH' | 'MEDIUM' | 'LOW';
|
|
3
|
+
export interface NotificationPanelProps extends Omit<NotificationListProps, 'compact' | 'onCommit'> {
|
|
4
|
+
filter: NotificationFilter;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: any;
|
|
7
|
+
onFilter: (filter: NotificationFilter) => Promise<void>;
|
|
8
|
+
visible: boolean;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
}
|
|
11
|
+
export interface NotificationPanelHeaderProps {
|
|
12
|
+
filter: NotificationFilter;
|
|
13
|
+
onChangeFilter: (value: NotificationFilter) => Promise<void>;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
}
|
|
16
|
+
export interface FilterButtonProps {
|
|
17
|
+
value: NotificationFilter;
|
|
18
|
+
current: NotificationFilter;
|
|
19
|
+
onChangeFilter: (value: NotificationFilter) => void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationCenter/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;AAEnF,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAA;AAE7E,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,UAAU,CAAC;IACjG,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,cAAc,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACrD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/NotificationCenter/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { LoadNotificationsFilters } from '@stack-spot/portal-components/Notifications';
|
|
2
|
+
import { NotificationFilter } from './types.js';
|
|
3
|
+
export declare function getFiltersFromName(filterName: NotificationFilter): LoadNotificationsFilters;
|
|
4
|
+
export declare function getNameFromFilters(filters: LoadNotificationsFilters): NotificationFilter;
|
|
5
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/components/NotificationCenter/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAA;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAI5C,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,GAAG,wBAAwB,CAQ3F;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,GAAG,kBAAkB,CAIxF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const empty = { committed: undefined, context: undefined, criticality: undefined, search: undefined };
|
|
2
|
+
export function getFiltersFromName(filterName) {
|
|
3
|
+
switch (filterName) {
|
|
4
|
+
case 'ALL': return empty;
|
|
5
|
+
case 'HIGH': return { ...empty, criticality: 'HIGH' };
|
|
6
|
+
case 'LOW': return { ...empty, criticality: 'LOW' };
|
|
7
|
+
case 'MEDIUM': return { ...empty, criticality: 'MEDIUM' };
|
|
8
|
+
case 'UNREAD': return { ...empty, committed: false };
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function getNameFromFilters(filters) {
|
|
12
|
+
if (filters.committed === false)
|
|
13
|
+
return 'UNREAD';
|
|
14
|
+
if (filters.criticality)
|
|
15
|
+
return filters.criticality;
|
|
16
|
+
return 'ALL';
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/components/NotificationCenter/utils.ts"],"names":[],"mappings":"AAGA,MAAM,KAAK,GAA6B,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;AAE/H,MAAM,UAAU,kBAAkB,CAAC,UAA8B;IAC/D,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,KAAK,CAAC,CAAC,OAAO,KAAK,CAAA;QACxB,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,CAAA;QACrD,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAA;QACnD,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAA;QACzD,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IACtD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAiC;IAClE,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAA;IAChD,IAAI,OAAO,CAAC,WAAW;QAAE,OAAO,OAAO,CAAC,WAAW,CAAA;IACnD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -30,6 +30,9 @@ export declare class ErrorBoundary extends Component<Props, State> {
|
|
|
30
30
|
} | undefined;
|
|
31
31
|
body?: import("react").ReactNode;
|
|
32
32
|
image?: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | undefined;
|
|
33
|
+
direction?: "column" | "row" | undefined;
|
|
34
|
+
style?: import("react").CSSProperties | undefined;
|
|
35
|
+
className?: string | undefined;
|
|
33
36
|
hasError: boolean;
|
|
34
37
|
};
|
|
35
38
|
componentDidCatch(error: any, errorInfo: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/error/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiB,MAAM,qCAAqC,CAAA;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjC,UAAU,KAAM,SAAQ,gBAAgB;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAc,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBAC5C,KAAK,EAAE,KAAK;IAKxB,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG
|
|
1
|
+
{"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/error/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiB,MAAM,qCAAqC,CAAA;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjC,UAAU,KAAM,SAAQ,gBAAgB;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAc,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBAC5C,KAAK,EAAE,KAAK;IAKxB,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG;;;;;;;;;;;;;;;;;;IAI1C,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IAM5C,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC;IAI7C,MAAM;CAKP"}
|
|
@@ -31,6 +31,9 @@ export declare class SilentErrorBoundary extends Component<Props, State> {
|
|
|
31
31
|
} | undefined;
|
|
32
32
|
body?: import("react").ReactNode;
|
|
33
33
|
image?: import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | undefined;
|
|
34
|
+
direction?: "column" | "row" | undefined;
|
|
35
|
+
style?: import("react").CSSProperties | undefined;
|
|
36
|
+
className?: string | undefined;
|
|
34
37
|
hasError: boolean;
|
|
35
38
|
};
|
|
36
39
|
componentDidCatch(error: any, errorInfo: any): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SilentErrorBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/error/SilentErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAA;AAEtE,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjC,UAAU,KAAM,SAAQ,gBAAgB;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBAClD,KAAK,EAAE,KAAK;IAKxB,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG
|
|
1
|
+
{"version":3,"file":"SilentErrorBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/error/SilentErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAA;AAEtE,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjC,UAAU,KAAM,SAAQ,gBAAgB;IACtC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBAClD,KAAK,EAAE,KAAK;IAKxB,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG;;;;;;;;;;;;;;;;;;IAI1C,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG;IAM5C,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC;IAI7C,MAAM;CAoBP"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export { Layout, RawLayout } from './Layout.js';
|
|
2
|
-
export { overlay } from './LayoutOverlayManager.js';
|
|
3
1
|
export { Dialog } from './components/Dialog.js';
|
|
4
2
|
export { Header, HeaderProps } from './components/Header.js';
|
|
5
|
-
export { OverlayContent } from './components/OverlayContent.js';
|
|
6
|
-
export { PortalSwitcher } from './components/PortalSwitcher.js';
|
|
7
3
|
export { ActionItem, MenuContent, MenuGroup, Title } from './components/menu/MenuContent.js';
|
|
8
4
|
export { MenuSections } from './components/menu/MenuSections.js';
|
|
9
5
|
export * from './components/menu/types.js';
|
|
6
|
+
export { CLOSE_OVERLAY_ID, OverlayContent } from './components/OverlayContent.js';
|
|
7
|
+
export { PortalSwitcher } from './components/PortalSwitcher.js';
|
|
10
8
|
export * from './components/tour/index.js';
|
|
11
9
|
export * from './components/types.js';
|
|
12
10
|
export * from './elements.js';
|
|
13
11
|
export * from './errors.js';
|
|
12
|
+
export { Layout, RawLayout } from './Layout.js';
|
|
13
|
+
export { overlay } from './LayoutOverlayManager.js';
|
|
14
14
|
export * from './utils.js';
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,cAAc,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export { Layout, RawLayout } from './Layout.js';
|
|
2
|
-
export { overlay } from './LayoutOverlayManager.js';
|
|
3
1
|
export { Dialog } from './components/Dialog.js';
|
|
4
2
|
export { Header } from './components/Header.js';
|
|
5
|
-
export { OverlayContent } from './components/OverlayContent.js';
|
|
6
|
-
export { PortalSwitcher } from './components/PortalSwitcher.js';
|
|
7
3
|
export { ActionItem, MenuContent, MenuGroup, Title } from './components/menu/MenuContent.js';
|
|
8
4
|
export { MenuSections } from './components/menu/MenuSections.js';
|
|
9
5
|
export * from './components/menu/types.js';
|
|
6
|
+
export { CLOSE_OVERLAY_ID, OverlayContent } from './components/OverlayContent.js';
|
|
7
|
+
export { PortalSwitcher } from './components/PortalSwitcher.js';
|
|
10
8
|
export * from './components/tour/index.js';
|
|
11
9
|
export * from './components/types.js';
|
|
12
10
|
export * from './elements.js';
|
|
13
11
|
export * from './errors.js';
|
|
12
|
+
export { Layout, RawLayout } from './Layout.js';
|
|
13
|
+
export { overlay } from './LayoutOverlayManager.js';
|
|
14
14
|
export * from './utils.js';
|
|
15
15
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,cAAc,SAAS,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/portal-layout",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@citric/ui": "^5.7.2 || ^6.0.0",
|
|
16
16
|
"@stack-spot/portal-theme": "^1.0.0",
|
|
17
17
|
"@stack-spot/portal-translate": "^1.0.0",
|
|
18
|
-
"@stack-spot/portal-components": "^2.
|
|
18
|
+
"@stack-spot/portal-components": "^2.1.0",
|
|
19
19
|
"react": "^18.2.0",
|
|
20
20
|
"react-dom": "^18.2.0",
|
|
21
21
|
"styled-components": "^6.1.10"
|
package/readme.md
CHANGED
package/src/Layout.tsx
CHANGED
|
@@ -81,7 +81,6 @@ export const RawLayout = (
|
|
|
81
81
|
extra, errorDescriptor, onError, className, style }:
|
|
82
82
|
RawProps,
|
|
83
83
|
) => {
|
|
84
|
-
// @ts-ignore
|
|
85
84
|
const { bottomDialog, modal, rightPanel } = overlay.useOverlays()
|
|
86
85
|
const { layout } = getLayoutElements()
|
|
87
86
|
const isCompactedOnlyIcons = layout?.classList.contains('menu-compact')
|
|
@@ -71,31 +71,60 @@ class LayoutOverlayManager {
|
|
|
71
71
|
*/
|
|
72
72
|
private lastActiveElement: Element | null = null
|
|
73
73
|
|
|
74
|
+
private closeCustomBackdrops(elements: NodeListOf<Element>) {
|
|
75
|
+
// this is the easiest way to close each custom backdrop by calling their respective "onClose" callbacks. This is a hidden button
|
|
76
|
+
// that exists in every <Backdrop> component.
|
|
77
|
+
elements.forEach(element => (element.querySelector('[data-custom-backdrop-close]') as HTMLElement)?.click?.())
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private onClickBackdrop(event: MouseEvent) {
|
|
81
|
+
if (this.isModalOpen()) !this.elements?.modal?.contains?.(event.target as Node) && this.closeModal()
|
|
82
|
+
else if (this.isRightPanelOpen()) !this.elements?.rightPanel?.contains?.(event.target as Node) && this.closeRightPanel()
|
|
83
|
+
else {
|
|
84
|
+
const customBackdrops = this.getAllVisibleCustomBackdrops()
|
|
85
|
+
if (customBackdrops.length) {
|
|
86
|
+
let isClickInside = false
|
|
87
|
+
customBackdrops.forEach((element) => {
|
|
88
|
+
if (element.contains(event.target as Node)) isClickInside = true
|
|
89
|
+
})
|
|
90
|
+
if (!isClickInside) this.closeCustomBackdrops(customBackdrops)
|
|
91
|
+
} else {
|
|
92
|
+
this.setMainContentInteractivity(true)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private onPressKeyInBackdrop(event: KeyboardEvent) {
|
|
98
|
+
if (event.key !== 'Escape') return
|
|
99
|
+
if (this.isModalOpen()) this.closeModal()
|
|
100
|
+
if (this.isRightPanelOpen()) this.closeRightPanel()
|
|
101
|
+
else {
|
|
102
|
+
const customBackdrops = this.getAllVisibleCustomBackdrops()
|
|
103
|
+
if (customBackdrops.length) this.closeCustomBackdrops(customBackdrops)
|
|
104
|
+
else this.setMainContentInteractivity(true)
|
|
105
|
+
}
|
|
106
|
+
event.preventDefault()
|
|
107
|
+
}
|
|
108
|
+
|
|
74
109
|
private setupElements() {
|
|
75
110
|
this.elements = getLayoutElements()
|
|
76
|
-
this.elements.backdrop?.addEventListener('mousedown', (event) =>
|
|
77
|
-
|
|
78
|
-
else if (this.isRightPanelOpen()) !this.elements?.rightPanel?.contains?.(event.target as Node) && this.closeRightPanel()
|
|
79
|
-
else this.setMainContentInteractivity(true)
|
|
80
|
-
})
|
|
81
|
-
this.elements.backdrop?.addEventListener('keydown', (event) => {
|
|
82
|
-
if (event.key !== 'Escape') return
|
|
83
|
-
if (this.isModalOpen()) this.closeModal()
|
|
84
|
-
if (this.isRightPanelOpen()) this.closeRightPanel()
|
|
85
|
-
else this.setMainContentInteractivity(true)
|
|
86
|
-
event.preventDefault()
|
|
87
|
-
})
|
|
111
|
+
this.elements.backdrop?.addEventListener('mousedown', (event) => this.onClickBackdrop(event))
|
|
112
|
+
this.elements.backdrop?.addEventListener('keydown', (event) => this.onPressKeyInBackdrop(event))
|
|
88
113
|
this.setInteractivity(this.elements?.modal, false)
|
|
89
114
|
this.setInteractivity(this.elements?.rightPanel, false)
|
|
90
115
|
this.setInteractivity(this.elements?.bottomDialog, false)
|
|
91
116
|
}
|
|
117
|
+
|
|
118
|
+
private getAllVisibleCustomBackdrops() {
|
|
119
|
+
return document.querySelectorAll('[data-custom-backdrop-visibility=true]')
|
|
120
|
+
}
|
|
92
121
|
|
|
93
122
|
/**
|
|
94
123
|
* Setup the overlay layout elements.
|
|
95
124
|
* @returns the content for the modal, rightPanel and bottomDialog.
|
|
125
|
+
* @internal
|
|
96
126
|
*/
|
|
97
|
-
|
|
98
|
-
private useOverlays() {
|
|
127
|
+
useOverlays() {
|
|
99
128
|
useLayoutEffect(() => {
|
|
100
129
|
if (!this.elements) this.setupElements()
|
|
101
130
|
}, [])
|
|
@@ -130,9 +159,9 @@ class LayoutOverlayManager {
|
|
|
130
159
|
this.elements?.backdrop?.setAttribute('class', interactive ? '' : 'visible')
|
|
131
160
|
}
|
|
132
161
|
|
|
133
|
-
private showOverlay(element: HTMLElement | null | undefined, extraClasses: string[] = [], blockMainContent = true) {
|
|
162
|
+
private showOverlay(element: HTMLElement | null | undefined, extraClasses: string[] = [], blockMainContent = true, manageClasses = true) {
|
|
134
163
|
this.lastActiveElement = document.activeElement
|
|
135
|
-
element?.classList.add('visible', ...extraClasses)
|
|
164
|
+
if (manageClasses) element?.classList.add('visible', ...extraClasses)
|
|
136
165
|
this.setInteractivity(element, true)
|
|
137
166
|
if (blockMainContent) this.setMainContentInteractivity(false)
|
|
138
167
|
setTimeout(() => focusFirstChild(
|
|
@@ -141,12 +170,36 @@ class LayoutOverlayManager {
|
|
|
141
170
|
), 50)
|
|
142
171
|
}
|
|
143
172
|
|
|
144
|
-
private hideOverlay(element: HTMLElement | null | undefined) {
|
|
145
|
-
element?.setAttribute('class', '')
|
|
173
|
+
private hideOverlay(element: HTMLElement | null | undefined, manageClasses = true) {
|
|
174
|
+
if (manageClasses) element?.setAttribute('class', '')
|
|
146
175
|
this.setInteractivity(element, false)
|
|
147
176
|
this.setMainContentInteractivity(true)
|
|
148
177
|
}
|
|
149
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Shows the backdrop. The element passed as parameter must be a child of backdrop. Some accessibility features will be attached to
|
|
181
|
+
* the element.
|
|
182
|
+
*
|
|
183
|
+
* Consider using the component <Backdrop> from this library instead of calling this function directly.
|
|
184
|
+
* @param element the element to show inside the backdrop. It must already be a child of the backdrop.
|
|
185
|
+
*/
|
|
186
|
+
showBackdrop(element?: HTMLElement | null) {
|
|
187
|
+
this.showOverlay(element, [], true, false)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Closes the backdrop. The element passed as parameter must be a child of backdrop. Some accessibility features will be run on the
|
|
192
|
+
* element.
|
|
193
|
+
*
|
|
194
|
+
* Consider using the component <Backdrop> from this library instead of calling this function directly.
|
|
195
|
+
* @param element the element showing inside the backdrop. It must be a child of the backdrop.
|
|
196
|
+
*/
|
|
197
|
+
closeBackdrop(element?: HTMLElement | null) {
|
|
198
|
+
this.hideOverlay(element, false)
|
|
199
|
+
const lastActiveElement = this.lastActiveElement as HTMLElement | null
|
|
200
|
+
lastActiveElement?.focus?.()
|
|
201
|
+
}
|
|
202
|
+
|
|
150
203
|
/**
|
|
151
204
|
* @returns true if the modal is currently opened. False otherwise.
|
|
152
205
|
*/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'react'
|
|
2
|
+
import { createPortal } from 'react-dom'
|
|
3
|
+
import { getLayoutElements } from '../elements'
|
|
4
|
+
import { overlay } from '../LayoutOverlayManager'
|
|
5
|
+
|
|
6
|
+
export interface BackdropProps {
|
|
7
|
+
children: React.ReactNode,
|
|
8
|
+
visible: boolean,
|
|
9
|
+
onClose: () => void,
|
|
10
|
+
style?: React.CSSProperties,
|
|
11
|
+
className?: string,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const Backdrop = ({ children, visible = false, onClose, className, style }: BackdropProps) => {
|
|
15
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
16
|
+
|
|
17
|
+
useLayoutEffect(() => {
|
|
18
|
+
if (visible) overlay.showBackdrop(ref.current)
|
|
19
|
+
else overlay.closeBackdrop(ref.current)
|
|
20
|
+
}, [visible])
|
|
21
|
+
|
|
22
|
+
const backdropContent = (
|
|
23
|
+
<div ref={ref} data-custom-backdrop-visibility={visible} className={className} style={style}>
|
|
24
|
+
{children}
|
|
25
|
+
{/* This button allows the OverlayManager to programmatically close any custom backdrop by calling their respective onClose prop. */}
|
|
26
|
+
<button data-custom-backdrop-close onClick={onClose} style={{ display: 'none' }}>Close</button>
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const backdrop = getLayoutElements().backdrop
|
|
31
|
+
return backdrop ? createPortal(backdropContent, backdrop) : null
|
|
32
|
+
}
|
|
@@ -3,6 +3,7 @@ import { SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
|
3
3
|
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
4
4
|
import { Logo } from '@stack-spot/portal-components/svg'
|
|
5
5
|
import { ReactNode } from 'react'
|
|
6
|
+
import { NotificationCenter } from './NotificationCenter'
|
|
6
7
|
import { PortalSwitcher, PortalSwitcherProps } from './PortalSwitcher'
|
|
7
8
|
import { UserMenu } from './UserMenu'
|
|
8
9
|
|
|
@@ -39,13 +40,17 @@ export interface HeaderProps {
|
|
|
39
40
|
* A custom React Node to show at the right (end) of the header.
|
|
40
41
|
*/
|
|
41
42
|
right?: ReactNode,
|
|
43
|
+
/**
|
|
44
|
+
* Whether or not to show the notification center.
|
|
45
|
+
*/
|
|
46
|
+
showNotificationCenter?: boolean,
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
/**
|
|
45
50
|
* The page header.
|
|
46
51
|
* @param props the React props for the header {@link HeaderProps}.
|
|
47
52
|
*/
|
|
48
|
-
export const Header = ({ logo, logoHref, center, right, userName, email, options, portalSwitch }: HeaderProps) => {
|
|
53
|
+
export const Header = ({ logo, logoHref, center, right, userName, email, options, portalSwitch, showNotificationCenter }: HeaderProps) => {
|
|
49
54
|
const Link = useAnchorTag()
|
|
50
55
|
|
|
51
56
|
return (
|
|
@@ -56,6 +61,7 @@ export const Header = ({ logo, logoHref, center, right, userName, email, options
|
|
|
56
61
|
}
|
|
57
62
|
<Flex flex={1}>{center}</Flex>
|
|
58
63
|
{right}
|
|
64
|
+
{showNotificationCenter && <NotificationCenter />}
|
|
59
65
|
{userName && <UserMenu userName={userName} email={email} options={options} />}
|
|
60
66
|
</>
|
|
61
67
|
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AnimatedHeight } from '@stack-spot/portal-components/AnimatedHeight'
|
|
2
|
+
import { ErrorFeedback } from '@stack-spot/portal-components/error'
|
|
3
|
+
import { NotificationList, useNotificationController } from '@stack-spot/portal-components/Notifications'
|
|
4
|
+
import { ScrollView } from '@stack-spot/portal-components/ScrollView'
|
|
5
|
+
import { NotificationPanelHeader } from './NotificationPanelHeader'
|
|
6
|
+
import { NotificationPanelFooter } from './NotificationsPanelFooter'
|
|
7
|
+
import { StyledBackdrop } from './styled'
|
|
8
|
+
import { NotificationPanelProps } from './types'
|
|
9
|
+
|
|
10
|
+
export const NotificationPanel = ({ filter, onFilter, loading, error, visible, onClose, ...props }: NotificationPanelProps) => {
|
|
11
|
+
const controller = useNotificationController()
|
|
12
|
+
return (
|
|
13
|
+
<StyledBackdrop visible={visible} onClose={onClose}>
|
|
14
|
+
<AnimatedHeight
|
|
15
|
+
className="notification-panel"
|
|
16
|
+
visible={visible}
|
|
17
|
+
header={<NotificationPanelHeader filter={filter} onChangeFilter={onFilter} onClose={onClose} />}
|
|
18
|
+
footer={<NotificationPanelFooter onClose={onClose} />}
|
|
19
|
+
>
|
|
20
|
+
<ScrollView direction="vertical" style={{ maxHeight: 'calc(100vh - 300px)' }}>
|
|
21
|
+
{error ? <ErrorFeedback code={error.code} direction="column" /> : <NotificationList
|
|
22
|
+
{...props}
|
|
23
|
+
compact
|
|
24
|
+
loading={loading}
|
|
25
|
+
onCommit={id => controller.markAsCommitted(id)}
|
|
26
|
+
onClickAction={(id) => {
|
|
27
|
+
onClose()
|
|
28
|
+
controller.config.onClickAction?.(id)
|
|
29
|
+
}}
|
|
30
|
+
/>}
|
|
31
|
+
</ScrollView>
|
|
32
|
+
</AnimatedHeight>
|
|
33
|
+
</StyledBackdrop>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Button, Flex, IconBox, Text } from '@citric/core'
|
|
2
|
+
import { TimesMini } from '@citric/icons'
|
|
3
|
+
import { IconButton } from '@citric/ui'
|
|
4
|
+
import { CLOSE_OVERLAY_ID } from '../OverlayContent'
|
|
5
|
+
import { useNotificationsDictionary } from './dictionary'
|
|
6
|
+
import { FilterButtonProps, NotificationPanelHeaderProps } from './types'
|
|
7
|
+
|
|
8
|
+
const FilterButton = ({ current, onChangeFilter, value }: FilterButtonProps) => {
|
|
9
|
+
const t = useNotificationsDictionary()
|
|
10
|
+
const active = current === value
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Button
|
|
14
|
+
appearance="text"
|
|
15
|
+
role="button"
|
|
16
|
+
aria-label={t[`${value}.ariaLabel`]}
|
|
17
|
+
aria-pressed={active}
|
|
18
|
+
onClick={() => onChangeFilter(value)}
|
|
19
|
+
className="filter-btn"
|
|
20
|
+
>
|
|
21
|
+
<Flex flexDirection="row" style={{ gap: '8px' }} alignItems="center">
|
|
22
|
+
<Text colorScheme="inverse" appearance="microtext1">
|
|
23
|
+
{t[`${value}.label`]}
|
|
24
|
+
</Text>
|
|
25
|
+
</Flex>
|
|
26
|
+
</Button>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const NotificationPanelHeader = ({ filter, onChangeFilter, onClose }: NotificationPanelHeaderProps) => {
|
|
31
|
+
const t = useNotificationsDictionary()
|
|
32
|
+
return (
|
|
33
|
+
<Flex flexDirection="column">
|
|
34
|
+
<Flex justifyContent="space-between">
|
|
35
|
+
<Text appearance="h4">
|
|
36
|
+
{t.notifications}
|
|
37
|
+
</Text>
|
|
38
|
+
<IconButton id={CLOSE_OVERLAY_ID} aria-label={t.close} onClick={onClose}>
|
|
39
|
+
<IconBox size="xs">
|
|
40
|
+
<TimesMini />
|
|
41
|
+
</IconBox>
|
|
42
|
+
</IconButton>
|
|
43
|
+
</Flex>
|
|
44
|
+
<ul className="filter-list">
|
|
45
|
+
<li><FilterButton current={filter} onChangeFilter={onChangeFilter} value="ALL" /></li>
|
|
46
|
+
<li><FilterButton current={filter} onChangeFilter={onChangeFilter} value="UNREAD" /></li>
|
|
47
|
+
<li><FilterButton current={filter} onChangeFilter={onChangeFilter} value="HIGH" /></li>
|
|
48
|
+
<li><FilterButton current={filter} onChangeFilter={onChangeFilter} value="MEDIUM" /></li>
|
|
49
|
+
<li><FilterButton current={filter} onChangeFilter={onChangeFilter} value="LOW" /></li>
|
|
50
|
+
</ul>
|
|
51
|
+
</Flex>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Button, Text } from '@citric/core'
|
|
2
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
3
|
+
import { useNotificationController } from '@stack-spot/portal-components/Notifications'
|
|
4
|
+
import { useNotificationsDictionary } from './dictionary'
|
|
5
|
+
|
|
6
|
+
export const NotificationPanelFooter = ({ onClose }: { onClose: () => void }) => {
|
|
7
|
+
const t = useNotificationsDictionary()
|
|
8
|
+
const controller = useNotificationController()
|
|
9
|
+
const Link = useAnchorTag()
|
|
10
|
+
return (
|
|
11
|
+
<Button
|
|
12
|
+
as={Link}
|
|
13
|
+
onClick={onClose}
|
|
14
|
+
size="sm"
|
|
15
|
+
colorScheme="inverse"
|
|
16
|
+
appearance="text"
|
|
17
|
+
className="see-all"
|
|
18
|
+
href={controller.config.notificationsPath}
|
|
19
|
+
>
|
|
20
|
+
<Text appearance="microtext1">
|
|
21
|
+
{t.seeAll}
|
|
22
|
+
</Text>
|
|
23
|
+
</Button>
|
|
24
|
+
)
|
|
25
|
+
}
|