@stack-spot/portal-layout 2.0.1 → 2.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/LayoutOverlayManager.d.ts +20 -0
  3. package/dist/LayoutOverlayManager.d.ts.map +1 -1
  4. package/dist/LayoutOverlayManager.js +74 -22
  5. package/dist/LayoutOverlayManager.js.map +1 -1
  6. package/dist/components/Backdrop.d.ts +10 -0
  7. package/dist/components/Backdrop.d.ts.map +1 -0
  8. package/dist/components/Backdrop.js +18 -0
  9. package/dist/components/Backdrop.js.map +1 -0
  10. package/dist/components/Header.d.ts +5 -1
  11. package/dist/components/Header.d.ts.map +1 -1
  12. package/dist/components/Header.js +3 -2
  13. package/dist/components/Header.js.map +1 -1
  14. package/dist/components/NotificationCenter/NotificationPanel.d.ts +3 -0
  15. package/dist/components/NotificationCenter/NotificationPanel.d.ts.map +1 -0
  16. package/dist/components/NotificationCenter/NotificationPanel.js +16 -0
  17. package/dist/components/NotificationCenter/NotificationPanel.js.map +1 -0
  18. package/dist/components/NotificationCenter/NotificationPanelHeader.d.ts +3 -0
  19. package/dist/components/NotificationCenter/NotificationPanelHeader.d.ts.map +1 -0
  20. package/dist/components/NotificationCenter/NotificationPanelHeader.js +16 -0
  21. package/dist/components/NotificationCenter/NotificationPanelHeader.js.map +1 -0
  22. package/dist/components/NotificationCenter/NotificationsPanelFooter.d.ts +4 -0
  23. package/dist/components/NotificationCenter/NotificationsPanelFooter.d.ts.map +1 -0
  24. package/dist/components/NotificationCenter/NotificationsPanelFooter.js +12 -0
  25. package/dist/components/NotificationCenter/NotificationsPanelFooter.js.map +1 -0
  26. package/dist/components/NotificationCenter/dictionary.d.ts +2 -0
  27. package/dist/components/NotificationCenter/dictionary.d.ts.map +1 -0
  28. package/dist/components/NotificationCenter/dictionary.js +43 -0
  29. package/dist/components/NotificationCenter/dictionary.js.map +1 -0
  30. package/dist/components/NotificationCenter/index.d.ts +2 -0
  31. package/dist/components/NotificationCenter/index.d.ts.map +1 -0
  32. package/dist/components/NotificationCenter/index.js +36 -0
  33. package/dist/components/NotificationCenter/index.js.map +1 -0
  34. package/dist/components/NotificationCenter/styled.d.ts +4 -0
  35. package/dist/components/NotificationCenter/styled.d.ts.map +1 -0
  36. package/dist/components/NotificationCenter/styled.js +74 -0
  37. package/dist/components/NotificationCenter/styled.js.map +1 -0
  38. package/dist/components/NotificationCenter/tour.d.ts +2 -0
  39. package/dist/components/NotificationCenter/tour.d.ts.map +1 -0
  40. package/dist/components/NotificationCenter/tour.js +15 -0
  41. package/dist/components/NotificationCenter/tour.js.map +1 -0
  42. package/dist/components/NotificationCenter/types.d.ts +21 -0
  43. package/dist/components/NotificationCenter/types.d.ts.map +1 -0
  44. package/dist/components/NotificationCenter/types.js +2 -0
  45. package/dist/components/NotificationCenter/types.js.map +1 -0
  46. package/dist/components/NotificationCenter/utils.d.ts +5 -0
  47. package/dist/components/NotificationCenter/utils.d.ts.map +1 -0
  48. package/dist/components/NotificationCenter/utils.js +18 -0
  49. package/dist/components/NotificationCenter/utils.js.map +1 -0
  50. package/dist/components/error/ErrorBoundary.d.ts +3 -0
  51. package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
  52. package/dist/components/error/SilentErrorBoundary.d.ts +3 -0
  53. package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
  54. package/dist/index.d.ts +4 -4
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +4 -4
  57. package/dist/index.js.map +1 -1
  58. package/package.json +2 -2
  59. package/readme.md +1 -0
  60. package/src/LayoutOverlayManager.tsx +69 -16
  61. package/src/components/Backdrop.tsx +32 -0
  62. package/src/components/Header.tsx +7 -1
  63. package/src/components/NotificationCenter/NotificationPanel.tsx +35 -0
  64. package/src/components/NotificationCenter/NotificationPanelHeader.tsx +53 -0
  65. package/src/components/NotificationCenter/NotificationsPanelFooter.tsx +25 -0
  66. package/src/components/NotificationCenter/dictionary.ts +44 -0
  67. package/src/components/NotificationCenter/index.tsx +61 -0
  68. package/src/components/NotificationCenter/styled.ts +75 -0
  69. package/src/components/NotificationCenter/tour.tsx +19 -0
  70. package/src/components/NotificationCenter/types.ts +24 -0
  71. package/src/components/NotificationCenter/utils.ts +20 -0
  72. package/src/index.ts +4 -4
@@ -0,0 +1,61 @@
1
+ import { IconBox } from '@citric/core'
2
+ import { Bell } from '@citric/icons'
3
+ import { IconButton } from '@citric/ui'
4
+ import { useEffectOnce } from '@stack-spot/portal-components'
5
+ import { useNotificationController, useNotificationList, useUnreadNotifications } from '@stack-spot/portal-components/Notifications'
6
+ import { listToClass } from '@stack-spot/portal-theme'
7
+ import { useEffect, useState } from 'react'
8
+ import { useNotificationsDictionary } from './dictionary'
9
+ import { NotificationPanel } from './NotificationPanel'
10
+ import { NotificationBox } from './styled'
11
+ import { useNotificationsTourStep } from './tour'
12
+ import { getFiltersFromName, getNameFromFilters } from './utils'
13
+
14
+ const MAX_ITEMS = 10
15
+
16
+ export const NotificationCenter = () => {
17
+ const [open, setOpen] = useState(false)
18
+ const t = useNotificationsDictionary()
19
+ const { applyFilters, filters, items, status, error } = useNotificationList({ size: MAX_ITEMS })
20
+ const hasUnreadNotification = useUnreadNotifications()
21
+ const controller = useNotificationController()
22
+ useNotificationsTourStep()
23
+
24
+ useEffectOnce(() => {
25
+ controller.checkUnread()
26
+ })
27
+
28
+ useEffect(() => {
29
+ if (open && (hasUnreadNotification || getNameFromFilters(filters) !== 'ALL')) {
30
+ applyFilters(getFiltersFromName('ALL'))
31
+ }
32
+ }, [open])
33
+
34
+ return (
35
+ <NotificationBox>
36
+ <IconButton
37
+ aria-label={status === 'startup' ? t.loadingNotifications : t.openNotifications}
38
+ onClick={status === 'startup' ? undefined : () => setOpen(true)}
39
+ className={listToClass([
40
+ 'notification-button',
41
+ status === 'startup' && 'loading',
42
+ status !== 'startup' && hasUnreadNotification && 'unread',
43
+ ])}
44
+ aria-expanded={open}
45
+ >
46
+ <IconBox size="md" className="notificationsTour" >
47
+ <Bell />
48
+ </IconBox>
49
+ </IconButton>
50
+ <NotificationPanel
51
+ filter={getNameFromFilters(filters)}
52
+ loading={status === 'loading'}
53
+ error={error}
54
+ items={items}
55
+ visible={open}
56
+ onClose={() => setOpen(false)}
57
+ onFilter={filter => applyFilters({ ...getFiltersFromName(filter), size: MAX_ITEMS })}
58
+ />
59
+ </NotificationBox>
60
+ )
61
+ }
@@ -0,0 +1,75 @@
1
+ import { theme } from '@stack-spot/portal-theme'
2
+ import { styled } from 'styled-components'
3
+ import { Backdrop } from '../Backdrop'
4
+
5
+ export const NotificationBox = styled.div`
6
+ .notification-button {
7
+ border: none;
8
+ background: transparent;
9
+ margin: 0 40px;
10
+ position: relative;
11
+
12
+ &.loading {
13
+ cursor: progress;
14
+ opacity: 0.5;
15
+ }
16
+
17
+ &:before {
18
+ content: '';
19
+ position: absolute;
20
+ top: -1px;
21
+ right: -1px;
22
+ width: 12px;
23
+ height: 12px;
24
+ border-radius: 50%;
25
+ background-color: ${theme.color.danger['500']};
26
+ transform: scale(0);
27
+ transition: transform ease-in 0.3s;
28
+ }
29
+
30
+ &.unread:before {
31
+ transform: scale(1);
32
+ }
33
+ }
34
+ `
35
+
36
+ export const StyledBackdrop = styled(Backdrop)`
37
+ position: absolute;
38
+ top: calc(var(--header-height) + 10px);
39
+ right: 60px;
40
+ box-shadow: 4px 4px 48px ${theme.color.danger.contrastText};
41
+
42
+ .notification-panel {
43
+ width: 368px;
44
+ padding: 16px;
45
+ border-radius: 4px;
46
+ background-color: ${theme.color.light[300]};
47
+ border: 1px solid ${theme.color.light[400]};
48
+ }
49
+
50
+ .filter-list {
51
+ list-style: none;
52
+ margin: 16px 0;
53
+ padding: 0;
54
+ display: flex;
55
+ flex-direction: row;
56
+ justify-content: space-between;
57
+ .filter-btn {
58
+ &:focus {
59
+ border-color: transparent;
60
+ }
61
+ &[aria-pressed="true"] {
62
+ border-color: ${theme.color.primary[500]};
63
+ }
64
+ }
65
+ }
66
+
67
+ .see-all {
68
+ margin-top: 8px;
69
+ width: 100%;
70
+ }
71
+
72
+ .error-feedback {
73
+ flex-direction: column;
74
+ }
75
+ `
@@ -0,0 +1,19 @@
1
+ import { Box, Text } from '@citric/core'
2
+ import { useTour } from '../tour'
3
+ import { useNotificationsDictionary } from './dictionary'
4
+
5
+ export const useNotificationsTourStep = () => {
6
+ const t = useNotificationsDictionary()
7
+ const { addStep } = useTour()
8
+
9
+ addStep({
10
+ content: <Box px={5} py={3}>
11
+ <Text appearance="microtext1" colorScheme="inverse.contrastText">
12
+ {t.tour}
13
+ </Text>
14
+ </Box>,
15
+ selector: '.notificationsTour',
16
+ title: t.notifications,
17
+ position: 'bottom',
18
+ } as any)
19
+ }
@@ -0,0 +1,24 @@
1
+ import { NotificationListProps } from '@stack-spot/portal-components/Notifications'
2
+
3
+ export type NotificationFilter = 'ALL' | 'UNREAD' | 'HIGH' | 'MEDIUM' | 'LOW'
4
+
5
+ export interface NotificationPanelProps extends Omit<NotificationListProps, 'compact' | 'onCommit'> {
6
+ filter: NotificationFilter,
7
+ loading: boolean,
8
+ error: any,
9
+ onFilter: (filter: NotificationFilter) => Promise<void>,
10
+ visible: boolean,
11
+ onClose: () => void,
12
+ }
13
+
14
+ export interface NotificationPanelHeaderProps {
15
+ filter: NotificationFilter,
16
+ onChangeFilter: (value: NotificationFilter) => Promise<void>,
17
+ onClose: () => void,
18
+ }
19
+
20
+ export interface FilterButtonProps {
21
+ value: NotificationFilter,
22
+ current: NotificationFilter,
23
+ onChangeFilter: (value: NotificationFilter) => void,
24
+ }
@@ -0,0 +1,20 @@
1
+ import { LoadNotificationsFilters } from '@stack-spot/portal-components/Notifications'
2
+ import { NotificationFilter } from './types'
3
+
4
+ const empty: LoadNotificationsFilters = { committed: undefined, context: undefined, criticality: undefined, search: undefined }
5
+
6
+ export function getFiltersFromName(filterName: NotificationFilter): LoadNotificationsFilters {
7
+ switch (filterName) {
8
+ case 'ALL': return empty
9
+ case 'HIGH': return { ...empty, criticality: 'HIGH' }
10
+ case 'LOW': return { ...empty, criticality: 'LOW' }
11
+ case 'MEDIUM': return { ...empty, criticality: 'MEDIUM' }
12
+ case 'UNREAD': return { ...empty, committed: false }
13
+ }
14
+ }
15
+
16
+ export function getNameFromFilters(filters: LoadNotificationsFilters): NotificationFilter {
17
+ if (filters.committed === false) return 'UNREAD'
18
+ if (filters.criticality) return filters.criticality
19
+ return 'ALL'
20
+ }
package/src/index.ts CHANGED
@@ -1,15 +1,15 @@
1
- export { Layout, RawLayout } from './Layout'
2
- export { overlay } from './LayoutOverlayManager'
3
1
  export { Dialog } from './components/Dialog'
4
2
  export { Header, HeaderProps } from './components/Header'
5
- export { OverlayContent } from './components/OverlayContent'
6
- export { PortalSwitcher } from './components/PortalSwitcher'
7
3
  export { ActionItem, MenuContent, MenuGroup, Title } from './components/menu/MenuContent'
8
4
  export { MenuSections } from './components/menu/MenuSections'
9
5
  export * from './components/menu/types'
6
+ export { CLOSE_OVERLAY_ID, OverlayContent } from './components/OverlayContent'
7
+ export { PortalSwitcher } from './components/PortalSwitcher'
10
8
  export * from './components/tour'
11
9
  export * from './components/types'
12
10
  export * from './elements'
13
11
  export * from './errors'
12
+ export { Layout, RawLayout } from './Layout'
13
+ export { overlay } from './LayoutOverlayManager'
14
14
  export * from './utils'
15
15