@stack-spot/portal-layout 0.0.64 → 1.0.0-dev.1768482785050
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 +779 -0
- package/dist/Layout.d.ts +60 -8
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +59 -24
- package/dist/Layout.js.map +1 -1
- package/dist/LayoutOverlayManager.d.ts +274 -19
- package/dist/LayoutOverlayManager.d.ts.map +1 -1
- package/dist/LayoutOverlayManager.js +373 -82
- package/dist/LayoutOverlayManager.js.map +1 -1
- package/dist/WelcomeTour.d.ts +2 -0
- package/dist/WelcomeTour.d.ts.map +1 -0
- package/dist/WelcomeTour.js +8 -0
- package/dist/WelcomeTour.js.map +1 -0
- package/dist/components/Backdrop.d.ts +75 -0
- package/dist/components/Backdrop.d.ts.map +1 -0
- package/dist/components/Backdrop.js +69 -0
- package/dist/components/Backdrop.js.map +1 -0
- package/dist/components/Contact/show-contact-modal.d.ts +5 -0
- package/dist/components/Contact/show-contact-modal.d.ts.map +1 -0
- package/dist/components/Contact/show-contact-modal.js +37 -0
- package/dist/components/Contact/show-contact-modal.js.map +1 -0
- package/dist/components/ContactModal.d.ts +1 -0
- package/dist/components/ContactModal.d.ts.map +1 -0
- package/dist/components/ContactModal.js +2 -0
- package/dist/components/ContactModal.js.map +1 -0
- package/dist/components/Dialog.d.ts +54 -7
- package/dist/components/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog.js +8 -2
- package/dist/components/Dialog.js.map +1 -1
- package/dist/components/Header.d.ts +38 -2
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +9 -4
- 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 +19 -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 +34 -0
- package/dist/components/NotificationCenter/index.js.map +1 -0
- package/dist/components/NotificationCenter/styled.d.ts +3 -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/types.d.ts +21 -0
- package/dist/components/NotificationCenter/types.d.ts.map +1 -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/OverlayContent.d.ts +27 -1
- package/dist/components/OverlayContent.d.ts.map +1 -1
- package/dist/components/OverlayContent.js +8 -4
- package/dist/components/OverlayContent.js.map +1 -1
- package/dist/components/PortalSwitcher.d.ts +19 -1
- package/dist/components/PortalSwitcher.d.ts.map +1 -1
- package/dist/components/PortalSwitcher.js +16 -31
- package/dist/components/PortalSwitcher.js.map +1 -1
- package/dist/components/PrivacyPolicyMessage/hooks.d.ts +10 -0
- package/dist/components/PrivacyPolicyMessage/hooks.d.ts.map +1 -0
- package/dist/components/PrivacyPolicyMessage/hooks.js +33 -0
- package/dist/components/PrivacyPolicyMessage/hooks.js.map +1 -0
- package/dist/components/PrivacyPolicyMessage/index.d.ts +7 -0
- package/dist/components/PrivacyPolicyMessage/index.d.ts.map +1 -0
- package/dist/components/PrivacyPolicyMessage/index.js +5 -0
- package/dist/components/PrivacyPolicyMessage/index.js.map +1 -0
- package/dist/components/Rate/FeedbackModal.d.ts +8 -0
- package/dist/components/Rate/FeedbackModal.d.ts.map +1 -0
- package/dist/components/Rate/FeedbackModal.js +52 -0
- package/dist/components/Rate/FeedbackModal.js.map +1 -0
- package/dist/components/Rate/hook.d.ts +3 -0
- package/dist/components/Rate/hook.d.ts.map +1 -0
- package/dist/components/Rate/hook.js +48 -0
- package/dist/components/Rate/hook.js.map +1 -0
- package/dist/components/Rate/index.d.ts +10 -0
- package/dist/components/Rate/index.d.ts.map +1 -0
- package/dist/components/Rate/index.js +16 -0
- package/dist/components/Rate/index.js.map +1 -0
- package/dist/components/Rate/on-nps-submit.d.ts +7 -0
- package/dist/components/Rate/on-nps-submit.d.ts.map +1 -0
- package/dist/components/Rate/on-nps-submit.js +8 -0
- package/dist/components/Rate/on-nps-submit.js.map +1 -0
- package/dist/components/Rate/show-rate-us-modals.d.ts +17 -0
- package/dist/components/Rate/show-rate-us-modals.d.ts.map +1 -0
- package/dist/components/Rate/show-rate-us-modals.js +14 -0
- package/dist/components/Rate/show-rate-us-modals.js.map +1 -0
- package/dist/components/Rate/utils.d.ts +2 -0
- package/dist/components/Rate/utils.d.ts.map +1 -0
- package/dist/components/Rate/utils.js +10 -0
- package/dist/components/Rate/utils.js.map +1 -0
- package/dist/components/Toaster.d.ts +35 -0
- package/dist/components/Toaster.d.ts.map +1 -1
- package/dist/components/Toaster.js +32 -4
- package/dist/components/Toaster.js.map +1 -1
- package/dist/components/TypeForm/hook.d.ts +2 -0
- package/dist/components/TypeForm/hook.d.ts.map +1 -0
- package/dist/components/TypeForm/hook.js +11 -0
- package/dist/components/TypeForm/hook.js.map +1 -0
- package/dist/components/TypeForm/index.d.ts +6 -0
- package/dist/components/TypeForm/index.d.ts.map +1 -0
- package/dist/components/TypeForm/index.js +23 -0
- package/dist/components/TypeForm/index.js.map +1 -0
- package/dist/components/TypeForm/show-typeform-modal.d.ts +5 -0
- package/dist/components/TypeForm/show-typeform-modal.d.ts.map +1 -0
- package/dist/components/TypeForm/show-typeform-modal.js +11 -0
- package/dist/components/TypeForm/show-typeform-modal.js.map +1 -0
- package/dist/components/TypeForm/utils.d.ts +2 -0
- package/dist/components/TypeForm/utils.d.ts.map +1 -0
- package/dist/components/TypeForm/utils.js +9 -0
- package/dist/components/TypeForm/utils.js.map +1 -0
- package/dist/components/UserMenu.d.ts +19 -2
- package/dist/components/UserMenu.d.ts.map +1 -1
- package/dist/components/UserMenu.js +12 -6
- package/dist/components/UserMenu.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +25 -4
- package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/ErrorBoundary.js +10 -1
- package/dist/components/error/ErrorBoundary.js.map +1 -1
- package/dist/components/error/ErrorManager.d.ts +22 -6
- package/dist/components/error/ErrorManager.d.ts.map +1 -1
- package/dist/components/error/ErrorManager.js +21 -1
- package/dist/components/error/ErrorManager.js.map +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +26 -5
- package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/SilentErrorBoundary.js +10 -0
- package/dist/components/error/SilentErrorBoundary.js.map +1 -1
- package/dist/components/menu/MenuContent.d.ts +20 -547
- package/dist/components/menu/MenuContent.d.ts.map +1 -1
- package/dist/components/menu/MenuContent.js +89 -88
- package/dist/components/menu/MenuContent.js.map +1 -1
- package/dist/components/menu/MenuSectionGroup.d.ts +2 -0
- package/dist/components/menu/MenuSectionGroup.d.ts.map +1 -0
- package/dist/components/menu/MenuSectionGroup.js +121 -0
- package/dist/components/menu/MenuSectionGroup.js.map +1 -0
- package/dist/components/menu/MenuSections.d.ts +17 -0
- package/dist/components/menu/MenuSections.d.ts.map +1 -1
- package/dist/components/menu/MenuSections.js +159 -39
- package/dist/components/menu/MenuSections.js.map +1 -1
- package/dist/components/menu/PageSelector.d.ts +5 -0
- package/dist/components/menu/PageSelector.d.ts.map +1 -1
- package/dist/components/menu/PageSelector.js +9 -4
- package/dist/components/menu/PageSelector.js.map +1 -1
- package/dist/components/menu/types.d.ts +219 -8
- package/dist/components/menu/types.d.ts.map +1 -1
- package/dist/components/tour/StepContainer.d.ts +37 -0
- package/dist/components/tour/StepContainer.d.ts.map +1 -0
- package/dist/components/tour/StepContainer.js +51 -0
- package/dist/components/tour/StepContainer.js.map +1 -0
- package/dist/components/tour/StepNavigation.d.ts +29 -0
- package/dist/components/tour/StepNavigation.d.ts.map +1 -0
- package/dist/components/tour/StepNavigation.js +37 -0
- package/dist/components/tour/StepNavigation.js.map +1 -0
- package/dist/components/tour/StepTitle.d.ts +17 -0
- package/dist/components/tour/StepTitle.d.ts.map +1 -0
- package/dist/components/tour/StepTitle.js +10 -0
- package/dist/components/tour/StepTitle.js.map +1 -0
- package/dist/components/tour/hook.d.ts +3 -0
- package/dist/components/tour/hook.d.ts.map +1 -0
- package/dist/components/tour/hook.js +10 -0
- package/dist/components/tour/hook.js.map +1 -0
- package/dist/components/tour/index.d.ts +5 -0
- package/dist/components/tour/index.d.ts.map +1 -0
- package/dist/components/tour/index.js +5 -0
- package/dist/components/tour/index.js.map +1 -0
- package/dist/components/tour/manager.d.ts +34 -0
- package/dist/components/tour/manager.d.ts.map +1 -0
- package/dist/components/tour/manager.js +104 -0
- package/dist/components/tour/manager.js.map +1 -0
- package/dist/components/tour/utils.d.ts +66 -8
- package/dist/components/tour/utils.d.ts.map +1 -1
- package/dist/components/tour/utils.js +57 -45
- package/dist/components/tour/utils.js.map +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/dictionary.d.ts +6 -1
- package/dist/dictionary.d.ts.map +1 -1
- package/dist/dictionary.js +7 -2
- package/dist/dictionary.js.map +1 -1
- package/dist/elements.d.ts +7 -0
- package/dist/elements.d.ts.map +1 -1
- package/dist/elements.js +7 -0
- package/dist/elements.js.map +1 -1
- package/dist/index.d.ts +15 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/layout.css +190 -35
- package/dist/svg/StarFillWithGradient.d.ts +6 -0
- package/dist/svg/StarFillWithGradient.d.ts.map +1 -0
- package/dist/svg/StarFillWithGradient.js +4 -0
- package/dist/svg/StarFillWithGradient.js.map +1 -0
- package/dist/toaster.d.ts +55 -9
- package/dist/toaster.d.ts.map +1 -1
- package/dist/toaster.js +34 -6
- package/dist/toaster.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +6 -69
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +9 -130
- package/dist/utils.js.map +1 -1
- package/package.dev.json +3 -0
- package/package.json +26 -15
- package/package.stg.json +3 -0
- package/readme.md +147 -0
- package/src/Layout.tsx +166 -57
- package/src/LayoutOverlayManager.tsx +499 -85
- package/src/WelcomeTour.tsx +8 -0
- package/src/components/Backdrop.tsx +116 -0
- package/src/components/Contact/show-contact-modal.tsx +71 -0
- package/src/components/Dialog.tsx +58 -9
- package/src/components/Header.tsx +53 -5
- package/src/components/NotificationCenter/NotificationPanel.tsx +40 -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 +58 -0
- package/src/components/NotificationCenter/styled.ts +75 -0
- package/src/components/NotificationCenter/types.ts +24 -0
- package/src/components/NotificationCenter/utils.ts +20 -0
- package/src/components/OverlayContent.tsx +40 -5
- package/src/components/PortalSwitcher.tsx +33 -39
- package/src/components/PrivacyPolicyMessage/hooks.tsx +49 -0
- package/src/components/PrivacyPolicyMessage/index.tsx +21 -0
- package/src/components/Rate/FeedbackModal.tsx +86 -0
- package/src/components/Rate/hook.tsx +61 -0
- package/src/components/Rate/index.tsx +36 -0
- package/src/components/Rate/on-nps-submit.ts +18 -0
- package/src/components/Rate/show-rate-us-modals.tsx +29 -0
- package/src/components/Rate/utils.ts +11 -0
- package/src/components/Toaster.tsx +82 -3
- package/src/components/TypeForm/hook.tsx +13 -0
- package/src/components/TypeForm/index.tsx +50 -0
- package/src/components/TypeForm/show-typeform-modal.tsx +10 -0
- package/src/components/TypeForm/utils.ts +8 -0
- package/src/components/UserMenu.tsx +32 -8
- package/src/components/error/ErrorBoundary.tsx +11 -2
- package/src/components/error/ErrorManager.ts +22 -6
- package/src/components/error/SilentErrorBoundary.tsx +12 -2
- package/src/components/menu/MenuContent.tsx +102 -110
- package/src/components/menu/MenuSectionGroup.tsx +121 -0
- package/src/components/menu/MenuSections.tsx +342 -93
- package/src/components/menu/PageSelector.tsx +16 -4
- package/src/components/menu/types.ts +221 -9
- package/src/components/tour/StepContainer.tsx +92 -0
- package/src/components/tour/StepNavigation.tsx +72 -0
- package/src/components/tour/StepTitle.tsx +28 -0
- package/src/components/tour/hook.ts +12 -0
- package/src/components/tour/index.ts +6 -0
- package/src/components/tour/manager.tsx +119 -0
- package/src/components/tour/utils.tsx +119 -0
- package/src/components/user-menu-manager.ts +31 -0
- package/src/dictionary.ts +7 -2
- package/src/elements.ts +7 -0
- package/src/index.ts +15 -8
- package/src/layout.css +190 -35
- package/src/svg/StarFillWithGradient.tsx +14 -0
- package/src/toaster.tsx +90 -13
- package/src/types.ts +4 -0
- package/src/utils.ts +9 -142
- package/dist/components/BottomNotification.d.ts +0 -1
- package/dist/components/BottomNotification.d.ts.map +0 -1
- package/dist/components/BottomNotification.js +0 -2
- package/dist/components/BottomNotification.js.map +0 -1
- package/dist/components/BottomPanel.d.ts +0 -1
- package/dist/components/BottomPanel.d.ts.map +0 -1
- package/dist/components/BottomPanel.js +0 -2
- package/dist/components/BottomPanel.js.map +0 -1
- package/dist/components/SelectionList.d.ts +0 -36
- package/dist/components/SelectionList.d.ts.map +0 -1
- package/dist/components/SelectionList.js +0 -140
- package/dist/components/SelectionList.js.map +0 -1
- package/dist/components/error/ErrorDescriptor.d.ts +0 -12
- package/dist/components/error/ErrorDescriptor.d.ts.map +0 -1
- package/dist/components/error/ErrorDescriptor.js +0 -17
- package/dist/components/error/ErrorDescriptor.js.map +0 -1
- package/dist/components/error/ErrorFeedback.d.ts +0 -3
- package/dist/components/error/ErrorFeedback.d.ts.map +0 -1
- package/dist/components/error/ErrorFeedback.js +0 -66
- package/dist/components/error/ErrorFeedback.js.map +0 -1
- package/dist/components/menu/use-check-text-overflow.d.ts +0 -6
- package/dist/components/menu/use-check-text-overflow.d.ts.map +0 -1
- package/dist/components/menu/use-check-text-overflow.js +0 -20
- package/dist/components/menu/use-check-text-overflow.js.map +0 -1
- package/dist/components/menu/use-keyboard-controls.d.ts +0 -23
- package/dist/components/menu/use-keyboard-controls.d.ts.map +0 -1
- package/dist/components/menu/use-keyboard-controls.js +0 -49
- package/dist/components/menu/use-keyboard-controls.js.map +0 -1
- package/dist/components/menu/useCheckTextOverflow.d.ts +0 -6
- package/dist/components/menu/useCheckTextOverflow.d.ts.map +0 -1
- package/dist/components/menu/useCheckTextOverflow.js +0 -20
- package/dist/components/menu/useCheckTextOverflow.js.map +0 -1
- package/dist/components/tour/Navigation.d.ts +0 -8
- package/dist/components/tour/Navigation.d.ts.map +0 -1
- package/dist/components/tour/Navigation.js +0 -15
- package/dist/components/tour/Navigation.js.map +0 -1
- package/dist/components/tour/PortalSwitcherStep.d.ts +0 -3
- package/dist/components/tour/PortalSwitcherStep.d.ts.map +0 -1
- package/dist/components/tour/PortalSwitcherStep.js +0 -29
- package/dist/components/tour/PortalSwitcherStep.js.map +0 -1
- package/dist/components/tour/config.d.ts +0 -3
- package/dist/components/tour/config.d.ts.map +0 -1
- package/dist/components/tour/config.js +0 -22
- package/dist/components/tour/config.js.map +0 -1
- package/dist/components/tour/steps/PortalSwitcherStep.d.ts +0 -3
- package/dist/components/tour/steps/PortalSwitcherStep.d.ts.map +0 -1
- package/dist/components/tour/steps/PortalSwitcherStep.js +0 -30
- package/dist/components/tour/steps/PortalSwitcherStep.js.map +0 -1
- package/dist/components/types.d.ts +0 -15
- package/dist/components/types.d.ts.map +0 -1
- package/dist/components/types.js.map +0 -1
- package/dist/layout-context.d.ts +0 -10
- package/dist/layout-context.d.ts.map +0 -1
- package/dist/layout-context.js +0 -11
- package/dist/layout-context.js.map +0 -1
- package/dist/svg/AI.d.ts +0 -6
- package/dist/svg/AI.d.ts.map +0 -1
- package/dist/svg/AI.js +0 -9
- package/dist/svg/AI.js.map +0 -1
- package/dist/svg/EDP.d.ts +0 -6
- package/dist/svg/EDP.d.ts.map +0 -1
- package/dist/svg/EDP.js +0 -5
- package/dist/svg/EDP.js.map +0 -1
- package/dist/svg/Forbidden.d.ts +0 -6
- package/dist/svg/Forbidden.d.ts.map +0 -1
- package/dist/svg/Forbidden.js +0 -4
- package/dist/svg/Forbidden.js.map +0 -1
- package/dist/svg/HUB.d.ts +0 -6
- package/dist/svg/HUB.d.ts.map +0 -1
- package/dist/svg/HUB.js +0 -5
- package/dist/svg/HUB.js.map +0 -1
- package/dist/svg/Logo.d.ts +0 -2
- package/dist/svg/Logo.d.ts.map +0 -1
- package/dist/svg/Logo.js +0 -4
- package/dist/svg/Logo.js.map +0 -1
- package/dist/svg/NotFound.d.ts +0 -6
- package/dist/svg/NotFound.d.ts.map +0 -1
- package/dist/svg/NotFound.js +0 -4
- package/dist/svg/NotFound.js.map +0 -1
- package/dist/svg/ServerError.d.ts +0 -6
- package/dist/svg/ServerError.d.ts.map +0 -1
- package/dist/svg/ServerError.js +0 -4
- package/dist/svg/ServerError.js.map +0 -1
- package/dist/svg/Unauthenticated.d.ts +0 -6
- package/dist/svg/Unauthenticated.d.ts.map +0 -1
- package/dist/svg/Unauthenticated.js +0 -4
- package/dist/svg/Unauthenticated.js.map +0 -1
- package/src/components/BottomPanel.tsx +0 -0
- package/src/components/SelectionList.tsx +0 -272
- package/src/components/error/ErrorFeedback.tsx +0 -114
- package/src/components/menu/use-check-text-overflow.tsx +0 -26
- package/src/components/menu/use-keyboard-controls.tsx +0 -70
- package/src/components/tour/PortalSwitcherStep.tsx +0 -36
- package/src/components/types.ts +0 -15
- package/src/layout-context.tsx +0 -22
- package/src/svg/AI.tsx +0 -37
- package/src/svg/EDP.tsx +0 -35
- package/src/svg/Forbidden.tsx +0 -22
- package/src/svg/HUB.tsx +0 -35
- package/src/svg/Logo.tsx +0 -35
- package/src/svg/NotFound.tsx +0 -16
- package/src/svg/ServerError.tsx +0 -33
- package/src/svg/Unauthenticated.tsx +0 -16
- /package/dist/components/{types.js → NotificationCenter/types.js} +0 -0
- /package/src/components/{BottomNotification.tsx → ContactModal.tsx} +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { WelcomeTour as WelcomeTourComponent, useTour } from './components/tour'
|
|
2
|
+
|
|
3
|
+
export const WelcomeTour = () => {
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5
|
+
const { currentStep, addStep, finishStep, ...tourConfig } = useTour()
|
|
6
|
+
|
|
7
|
+
return <WelcomeTourComponent {...tourConfig} />
|
|
8
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { delay } from '@stack-spot/portal-components'
|
|
2
|
+
import { listToClass } from '@stack-spot/portal-theme'
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
4
|
+
import { createPortal } from 'react-dom'
|
|
5
|
+
import { getLayoutElements } from '../elements'
|
|
6
|
+
import { overlay } from '../LayoutOverlayManager'
|
|
7
|
+
import { CustomModalSize, RightPanelSize } from '../types'
|
|
8
|
+
import { valueOfLayoutVar } from '../utils'
|
|
9
|
+
|
|
10
|
+
export interface BackdropProps {
|
|
11
|
+
children: React.ReactNode,
|
|
12
|
+
visible: boolean,
|
|
13
|
+
/**
|
|
14
|
+
* A function to run when the backdrop is closed. Since the backdrop is a controlled element, this should be used to set the state
|
|
15
|
+
* of `visible` to false.
|
|
16
|
+
*/
|
|
17
|
+
onClose: () => void,
|
|
18
|
+
style?: React.CSSProperties,
|
|
19
|
+
/**
|
|
20
|
+
* Makes this backdrop act as a modal or a right panel.
|
|
21
|
+
* - `actAs = 'modal'` adds the className 'modal-box' to the backdrop, making it behave like a modal with medium size.
|
|
22
|
+
* - `actAs = 'right-panel'` adds the className 'right-panel-box' to the backdrop, making it behave like a right-panel with medium size.
|
|
23
|
+
* - `actAs = { type: T, size: S }` adds the className 'modal-box' or 'right-panel-box' to the backdrop, depending on the value of `T`.
|
|
24
|
+
* The size will depend on the value of `S`.
|
|
25
|
+
*/
|
|
26
|
+
actAs?: 'modal' | 'right-panel' | { type: 'modal', size: CustomModalSize } | { type: 'right-panel', size: RightPanelSize },
|
|
27
|
+
/**
|
|
28
|
+
* A persistent backdrop is always rendered, despite the value of `visible`. It still appears or disappears according to `visible`, but
|
|
29
|
+
* it never leaves the DOM.
|
|
30
|
+
*
|
|
31
|
+
* This can help preserving complex animations.
|
|
32
|
+
*
|
|
33
|
+
* Attention: if you have many complex backdrops with persistent = true, it may affect performance.
|
|
34
|
+
*
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
persistent?: boolean,
|
|
38
|
+
/**
|
|
39
|
+
* This doesn't change the animation of the backdrop! Use this property if `persistent` is false and the backdrop's content is animated
|
|
40
|
+
* in a different time than `--modal-animation-duration` (layout css variable).
|
|
41
|
+
*
|
|
42
|
+
* This lets you preserve the animations on your content when `persistent` is false.
|
|
43
|
+
*/
|
|
44
|
+
animationMS?: number,
|
|
45
|
+
className?: string,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The backdrop is a component for creating a Modal content. This can have any shape or form, it's free to accept any kind of content, and,
|
|
50
|
+
* by default, it has no animations attached to it (with the exception of the backdrop's animation, which is a fade-in-out).
|
|
51
|
+
*
|
|
52
|
+
* In general, to create modal and side-panels, you should use `overlay.showModal`, `overlay.showCustomModal`, `overlay.showRightPanel` and
|
|
53
|
+
* `overlay.showCustomRightPanel`.
|
|
54
|
+
*
|
|
55
|
+
* Use this when:
|
|
56
|
+
* 1. Your content is neither a modal, nor a right panel, but it needs a backdrop. Meaning, it can't be animated like a modal, but still
|
|
57
|
+
* needs to show a backdrop.
|
|
58
|
+
* 2. Your content is a modal or a right panel, but it needs to update according to an external state. The ideal scenario is to have the
|
|
59
|
+
* modal content completely independent of the external state, but sometimes, we do need to interact with an external state and calling
|
|
60
|
+
* `overlay.show*` multiple times is not ideal.
|
|
61
|
+
*
|
|
62
|
+
* Attention: if you open a modal/right panel through this component, you should not use the methods `overlay.close*` or `overlay.is*Open`
|
|
63
|
+
* to manage it.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* Check the example below for rendering a medium-sized modal. Equivalent to `overlay.showModal`. Remember that calling `overlay.showModal`
|
|
67
|
+
* is always preferable. Use this only if you fall into the second case explained above.
|
|
68
|
+
* ```
|
|
69
|
+
* <Backdrop visible={isOpen} onClose={() => setOpen(false)} actAs="modal">
|
|
70
|
+
* <OverlayContent type="modal" onClose={() => setOpen(false)} title="Title">
|
|
71
|
+
* <p>Hello World!</p>
|
|
72
|
+
* </OverlayContent>
|
|
73
|
+
* </Backdrop>
|
|
74
|
+
* ```
|
|
75
|
+
* @param props the component props {@link BackdropProps}.
|
|
76
|
+
*/
|
|
77
|
+
export const Backdrop = ({ children, visible = false, onClose, className, actAs, persistent, animationMS = 0, style }: BackdropProps) => {
|
|
78
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
79
|
+
const [shouldRender, setShouldRender] = useState(!!persistent)
|
|
80
|
+
const renderDelay = useMemo(() => Math.max(parseFloat(valueOfLayoutVar('--modal-animation-duration')), animationMS) * 1000, [])
|
|
81
|
+
const backdropType = typeof actAs === 'string' ? actAs : actAs?.type
|
|
82
|
+
const backdropSize = typeof actAs === 'string' ? 'medium' : actAs?.size
|
|
83
|
+
const classes = listToClass([
|
|
84
|
+
className,
|
|
85
|
+
backdropType === 'modal' && 'modal-box',
|
|
86
|
+
backdropType === 'right-panel' && 'right-panel-box',
|
|
87
|
+
backdropSize,
|
|
88
|
+
])
|
|
89
|
+
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
(async () => {
|
|
92
|
+
if (visible) {
|
|
93
|
+
setShouldRender(true)
|
|
94
|
+
// arbitrary delay to make sure the content is rendered before actually showing it.
|
|
95
|
+
await delay(10)
|
|
96
|
+
overlay.showBackdrop(ref.current)
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
overlay.closeBackdrop(ref.current)
|
|
100
|
+
await delay(renderDelay)
|
|
101
|
+
setShouldRender(false)
|
|
102
|
+
}
|
|
103
|
+
})()
|
|
104
|
+
}, [visible])
|
|
105
|
+
|
|
106
|
+
const backdropContent = (
|
|
107
|
+
<div ref={ref} data-custom-backdrop-visibility={visible} className={classes} style={style}>
|
|
108
|
+
{children}
|
|
109
|
+
{/* This button allows the OverlayManager to programmatically close any custom backdrop by calling their respective onClose prop. */}
|
|
110
|
+
<button data-custom-backdrop-close onClick={onClose} style={{ display: 'none' }}>Close</button>
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
const backdrop = getLayoutElements().backdrop
|
|
115
|
+
return backdrop && (shouldRender || persistent) ? createPortal(backdropContent, backdrop) : null
|
|
116
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Box, Button, Flex, IconBox, Text } from '@citric/core'
|
|
2
|
+
import { ExternalLink } from '@citric/icons'
|
|
3
|
+
import { Card } from '@citric/ui'
|
|
4
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
5
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
6
|
+
import { ReactElement } from 'react'
|
|
7
|
+
import { overlay } from '../../LayoutOverlayManager'
|
|
8
|
+
|
|
9
|
+
interface CardItemProps {
|
|
10
|
+
title: string,
|
|
11
|
+
description: string,
|
|
12
|
+
buttonText: string,
|
|
13
|
+
onClick?: () => void,
|
|
14
|
+
url?: string,
|
|
15
|
+
icon: ReactElement,
|
|
16
|
+
hasMargin?: boolean,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const CardItem = ({ title, description, hasMargin = false, buttonText, url, icon, onClick }: CardItemProps) => {
|
|
20
|
+
const Link = useAnchorTag()
|
|
21
|
+
return <Card sx={{ p: '7', bg: 'light.500', w: '100%' }}>
|
|
22
|
+
<Flex flexDirection="column">
|
|
23
|
+
<Text appearance="h5" mb="3">{title}</Text>
|
|
24
|
+
<Text appearance="microtext1" colorScheme="light.700" mb="8">{description}</Text>
|
|
25
|
+
<Box mt={hasMargin ? 5: 0}>
|
|
26
|
+
<Link onClick={onClick} href={url} target="_blank">
|
|
27
|
+
<Button size="md" colorScheme="inverse">
|
|
28
|
+
{buttonText}
|
|
29
|
+
<IconBox sx={{ ml: 2 }} colorIcon="inverse.contrastText">
|
|
30
|
+
{icon}
|
|
31
|
+
</IconBox>
|
|
32
|
+
</Button>
|
|
33
|
+
</Link>
|
|
34
|
+
</Box>
|
|
35
|
+
</Flex>
|
|
36
|
+
</Card>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const ContactUsComponent = ({ serviceNowUrl }: {serviceNowUrl:string}) => {
|
|
40
|
+
const t = useTranslate(dictionary)
|
|
41
|
+
|
|
42
|
+
return <Flex sx={{ gap: '8px' }} w={12} mb={10} flexWrap="nowrap">
|
|
43
|
+
<CardItem title={t.support} description={t.supportDescription} buttonText={t.supportButton} url={serviceNowUrl}
|
|
44
|
+
icon={<ExternalLink />} />
|
|
45
|
+
</Flex>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
export const showContactUsModal = ({ title, serviceNowUrl }:{ serviceNowUrl:string, title: string }) => {
|
|
50
|
+
overlay.showModal({
|
|
51
|
+
title,
|
|
52
|
+
children: <ContactUsComponent serviceNowUrl={serviceNowUrl} />,
|
|
53
|
+
size: 'small',
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const dictionary = {
|
|
58
|
+
en: {
|
|
59
|
+
contactUs: 'Contact us',
|
|
60
|
+
support: 'Support and feedback',
|
|
61
|
+
supportDescription: 'Need help or have a feedback? Connect with our Support team',
|
|
62
|
+
supportButton: 'Get in touch',
|
|
63
|
+
},
|
|
64
|
+
pt: {
|
|
65
|
+
contactUs: 'Fale conosco',
|
|
66
|
+
support: 'Suporte e feedback',
|
|
67
|
+
supportDescription: 'Precisa de ajuda ou tem algum feedback? Fale com o nosso time de Suporte',
|
|
68
|
+
supportButton: 'Entre em contato',
|
|
69
|
+
},
|
|
70
|
+
} satisfies Dictionary
|
|
71
|
+
|
|
@@ -6,35 +6,77 @@ import { useDictionary } from '../dictionary'
|
|
|
6
6
|
import { OverlayContent } from './OverlayContent'
|
|
7
7
|
|
|
8
8
|
interface Validation {
|
|
9
|
+
/**
|
|
10
|
+
* The expected value of the field.
|
|
11
|
+
*/
|
|
9
12
|
value: string,
|
|
13
|
+
/**
|
|
14
|
+
* A custom label for the input field.
|
|
15
|
+
*/
|
|
10
16
|
label?: string | ReactNode,
|
|
17
|
+
/**
|
|
18
|
+
* A placeholder for the input field.
|
|
19
|
+
*/
|
|
11
20
|
placeholder?: string,
|
|
12
21
|
}
|
|
13
22
|
|
|
14
23
|
export interface DialogOptions {
|
|
24
|
+
/**
|
|
25
|
+
* The dialog's title.
|
|
26
|
+
*/
|
|
15
27
|
title: string,
|
|
28
|
+
/**
|
|
29
|
+
* The dialog's subtitle.
|
|
30
|
+
*/
|
|
16
31
|
subtitle?: string,
|
|
17
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Function to call when the "go back" button is pressed. If unset, the button is not shown.
|
|
34
|
+
*/
|
|
35
|
+
onGoBack?: () => void,
|
|
36
|
+
/**
|
|
37
|
+
* The dialog's content.
|
|
38
|
+
*/
|
|
39
|
+
children: ReactNode,
|
|
40
|
+
/**
|
|
41
|
+
* A text for the confirm button. If left blank, the confirm button won't render.
|
|
42
|
+
*/
|
|
18
43
|
confirm?: string,
|
|
44
|
+
/**
|
|
45
|
+
* A text for the cancel button. If left blank, the cancel button won't render.
|
|
46
|
+
*/
|
|
19
47
|
cancel?: string,
|
|
48
|
+
/**
|
|
49
|
+
* A validation input field. If the validation is incorrect, the confirm button is disabled.
|
|
50
|
+
* If this is a string, the validation input's value must be equal to this string in order to enable the confirm button.
|
|
51
|
+
* If this is an object, a value, label and placeholder may be specified.
|
|
52
|
+
* Use false or undefined to not include a validation field.
|
|
53
|
+
*/
|
|
20
54
|
validation?: false | string | Validation,
|
|
21
55
|
/**
|
|
56
|
+
* If this is a modal or a rightPanel.
|
|
22
57
|
* @default modal
|
|
23
58
|
*/
|
|
24
59
|
type?: 'modal' | 'panel',
|
|
25
60
|
/**
|
|
26
|
-
*
|
|
61
|
+
* The placement for the confirm/cancel buttons.
|
|
62
|
+
* @default "left" if type is "panel", "right" otherwise.
|
|
27
63
|
*/
|
|
28
|
-
buttonPlacement?: 'left' | 'center' | 'right',
|
|
64
|
+
buttonPlacement?: 'left' | 'center' | 'right' | 'corners',
|
|
29
65
|
/**
|
|
30
66
|
* The color of the primary button.
|
|
31
|
-
* @default primary
|
|
67
|
+
* @default "primary"
|
|
32
68
|
*/
|
|
33
69
|
buttonColor?: ColorSchemeName,
|
|
34
70
|
}
|
|
35
71
|
|
|
36
|
-
interface Props extends DialogOptions {
|
|
37
|
-
|
|
72
|
+
interface Props extends Omit<DialogOptions, 'message'> {
|
|
73
|
+
/**
|
|
74
|
+
* Function to run when the confirm button is clicked.
|
|
75
|
+
*/
|
|
76
|
+
onConfirm?: () => void,
|
|
77
|
+
/**
|
|
78
|
+
* Function to run when the cancel button is clicked.
|
|
79
|
+
*/
|
|
38
80
|
onCancel: () => void,
|
|
39
81
|
}
|
|
40
82
|
|
|
@@ -42,15 +84,22 @@ const justifyButtons: Record<Required<DialogOptions>['buttonPlacement'], React.C
|
|
|
42
84
|
center: 'center',
|
|
43
85
|
left: 'start',
|
|
44
86
|
right: 'end',
|
|
87
|
+
corners: 'space-between',
|
|
45
88
|
}
|
|
46
89
|
|
|
90
|
+
/**
|
|
91
|
+
* A dialog, i.e. A UI with title, subtitle, close button, content and a set of buttons: cancel and confirm. May be placed under a Modal or
|
|
92
|
+
* RightPanel.
|
|
93
|
+
* @param props the React props of the component {@link Props}.
|
|
94
|
+
*/
|
|
47
95
|
export const Dialog = ({
|
|
48
|
-
|
|
96
|
+
children,
|
|
49
97
|
title,
|
|
50
98
|
subtitle,
|
|
51
99
|
cancel,
|
|
52
100
|
confirm,
|
|
53
101
|
validation,
|
|
102
|
+
onGoBack,
|
|
54
103
|
onConfirm,
|
|
55
104
|
onCancel,
|
|
56
105
|
type = 'modal',
|
|
@@ -81,9 +130,9 @@ export const Dialog = ({
|
|
|
81
130
|
}
|
|
82
131
|
|
|
83
132
|
return (
|
|
84
|
-
<OverlayContent title={title} subtitle={subtitle} onClose={onCancel} type={type}>
|
|
133
|
+
<OverlayContent title={title} subtitle={subtitle} onClose={onCancel} type={type} onGoBack={onGoBack}>
|
|
85
134
|
<Flex flexDirection="column" flex={1}>
|
|
86
|
-
{
|
|
135
|
+
{children}
|
|
87
136
|
{renderValidation()}
|
|
88
137
|
</Flex>
|
|
89
138
|
{(cancel || confirm) && <Flex gap justifyContent={justifyButtons[buttonPlacement]} alignItems="center" sx={{ mt: 6 }}>
|
|
@@ -1,23 +1,70 @@
|
|
|
1
1
|
import { Flex } from '@citric/core'
|
|
2
|
+
import { SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
3
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
4
|
+
import { Logo } from '@stack-spot/portal-components/svg'
|
|
2
5
|
import { ReactNode } from 'react'
|
|
3
|
-
import {
|
|
4
|
-
import { Logo } from '../svg/Logo'
|
|
6
|
+
import { NotificationCenter } from './NotificationCenter'
|
|
5
7
|
import { PortalSwitcher, PortalSwitcherProps } from './PortalSwitcher'
|
|
6
|
-
import { SelectionListProps } from './SelectionList'
|
|
7
8
|
import { UserMenu } from './UserMenu'
|
|
8
9
|
|
|
9
10
|
export interface HeaderProps {
|
|
11
|
+
/**
|
|
12
|
+
* The logo to show in the header, if the portal switch feature is disabled.
|
|
13
|
+
*/
|
|
10
14
|
logo?: ReactNode,
|
|
15
|
+
/**
|
|
16
|
+
* The url the logo links to, if the portal switch feature is disabled.
|
|
17
|
+
*/
|
|
11
18
|
logoHref?: string,
|
|
19
|
+
/**
|
|
20
|
+
* The username to show in the user menu.
|
|
21
|
+
*/
|
|
12
22
|
userName?: string,
|
|
23
|
+
/**
|
|
24
|
+
* The user image to show in the user menu.
|
|
25
|
+
*/
|
|
26
|
+
userImage?: string,
|
|
27
|
+
/**
|
|
28
|
+
* The email to show in the user menu.
|
|
29
|
+
*/
|
|
13
30
|
email?: string,
|
|
31
|
+
/**
|
|
32
|
+
* A portal switch config. If not specified, disables the portal switch feature.
|
|
33
|
+
*/
|
|
14
34
|
portalSwitch?: PortalSwitcherProps['portals'],
|
|
35
|
+
/**
|
|
36
|
+
* The options to show in the user menu.
|
|
37
|
+
*/
|
|
15
38
|
options?: SelectionListProps['items'],
|
|
39
|
+
/**
|
|
40
|
+
* A custom React Node to show at the center of the header. This is a good place for a search field, for instance.
|
|
41
|
+
*/
|
|
16
42
|
center?: ReactNode,
|
|
43
|
+
/**
|
|
44
|
+
* A custom React Node to show at the right (end) of the header.
|
|
45
|
+
*/
|
|
17
46
|
right?: ReactNode,
|
|
47
|
+
/**
|
|
48
|
+
* Whether or not to show the notification center.
|
|
49
|
+
*/
|
|
50
|
+
showNotificationCenter?: boolean,
|
|
18
51
|
}
|
|
19
52
|
|
|
20
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The page header.
|
|
55
|
+
* @param props the React props for the header {@link HeaderProps}.
|
|
56
|
+
*/
|
|
57
|
+
export const Header = ({
|
|
58
|
+
logo,
|
|
59
|
+
logoHref,
|
|
60
|
+
center,
|
|
61
|
+
right,
|
|
62
|
+
userName,
|
|
63
|
+
email,
|
|
64
|
+
options,
|
|
65
|
+
portalSwitch,
|
|
66
|
+
showNotificationCenter,
|
|
67
|
+
userImage }: HeaderProps) => {
|
|
21
68
|
const Link = useAnchorTag()
|
|
22
69
|
|
|
23
70
|
return (
|
|
@@ -28,7 +75,8 @@ export const Header = ({ logo, logoHref, center, right, userName, email, options
|
|
|
28
75
|
}
|
|
29
76
|
<Flex flex={1}>{center}</Flex>
|
|
30
77
|
{right}
|
|
31
|
-
{
|
|
78
|
+
{showNotificationCenter && <NotificationCenter />}
|
|
79
|
+
{userName && <UserMenu userName={userName} email={email} options={options} userImage={userImage} />}
|
|
32
80
|
</>
|
|
33
81
|
)
|
|
34
82
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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} persistent>
|
|
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
|
+
onUncommit={id => controller.markAsUncommitted(id)}
|
|
27
|
+
onClickViewNotification={() => {
|
|
28
|
+
onClose()
|
|
29
|
+
controller.config.onClickViewNotification?.()
|
|
30
|
+
}}
|
|
31
|
+
onClickAction={(id) => {
|
|
32
|
+
onClose()
|
|
33
|
+
controller.config.onClickAction?.(id)
|
|
34
|
+
}}
|
|
35
|
+
/>}
|
|
36
|
+
</ScrollView>
|
|
37
|
+
</AnimatedHeight>
|
|
38
|
+
</StyledBackdrop>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -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" as="h2">
|
|
36
|
+
{t.notifications}
|
|
37
|
+
</Text>
|
|
38
|
+
<IconButton id={CLOSE_OVERLAY_ID} aria-label={t.close} onClick={onClose} sx={{ borderRadius: '50%' }}>
|
|
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.viewAll}
|
|
22
|
+
</Text>
|
|
23
|
+
</Button>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
2
|
+
|
|
3
|
+
const dictionary = {
|
|
4
|
+
en: {
|
|
5
|
+
notifications: 'Notifications',
|
|
6
|
+
'ALL.ariaLabel': 'Show all notifications',
|
|
7
|
+
'UNREAD.ariaLabel': 'Show unread notifications',
|
|
8
|
+
'HIGH.ariaLabel': 'Show critical notifications',
|
|
9
|
+
'MEDIUM.ariaLabel': 'Show notifications with medium criticality',
|
|
10
|
+
'LOW.ariaLabel': 'Show notifications with low criticality',
|
|
11
|
+
'ALL.label': 'All',
|
|
12
|
+
'UNREAD.label': 'Unread',
|
|
13
|
+
'HIGH.label': 'High',
|
|
14
|
+
'MEDIUM.label': 'Medium',
|
|
15
|
+
'LOW.label': 'Low',
|
|
16
|
+
viewAll: 'View all notifications',
|
|
17
|
+
openNotifications: 'View notifications',
|
|
18
|
+
hasUnread: 'Has Unread notifications',
|
|
19
|
+
close: 'Close',
|
|
20
|
+
loadingNotifications: "Loading notifications. You'll be able to click this button and see them in a few seconds.",
|
|
21
|
+
tour: 'Now we have Notifications, this will help you stay informed of the latest updates about your Workspaces, Studios, and the Stackspot platform.',
|
|
22
|
+
},
|
|
23
|
+
pt: {
|
|
24
|
+
notifications: 'Notificações',
|
|
25
|
+
'ALL.ariaLabel': 'Mostrar todas as notificações',
|
|
26
|
+
'UNREAD.ariaLabel': 'Mostrar notificações não lidas',
|
|
27
|
+
'HIGH.ariaLabel': 'Mostrar notificações críticas',
|
|
28
|
+
'MEDIUM.ariaLabel': 'Mostrar notificações com criticidade média',
|
|
29
|
+
'LOW.ariaLabel': 'Mostrar notificações com criticidade baixa',
|
|
30
|
+
'ALL.label': 'Todas',
|
|
31
|
+
'UNREAD.label': 'Não lidas',
|
|
32
|
+
'HIGH.label': 'Alto',
|
|
33
|
+
'MEDIUM.label': 'Médio',
|
|
34
|
+
'LOW.label': 'Baixo',
|
|
35
|
+
viewAll: 'Ver todas as notificações',
|
|
36
|
+
openNotifications: 'Visualizar notificações',
|
|
37
|
+
hasUnread: 'Existem notificações não lidas',
|
|
38
|
+
close: 'Fechar',
|
|
39
|
+
loadingNotifications: 'Carregando notificações. Você poderá clicar neste botão e vê-las em alguns segundos.',
|
|
40
|
+
tour: 'Agora temos Notificações, isso irá ajudá-lo a se manter informado sobre as últimas atualizações sobre seus Workspaces, estúdios e a plataforma Stackspot.',
|
|
41
|
+
},
|
|
42
|
+
} satisfies Dictionary
|
|
43
|
+
|
|
44
|
+
export const useNotificationsDictionary = () => useTranslate(dictionary)
|
|
@@ -0,0 +1,58 @@
|
|
|
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 { getFiltersFromName, getNameFromFilters } from './utils'
|
|
12
|
+
|
|
13
|
+
const MAX_ITEMS = 10
|
|
14
|
+
|
|
15
|
+
export const NotificationCenter = () => {
|
|
16
|
+
const [open, setOpen] = useState(false)
|
|
17
|
+
const t = useNotificationsDictionary()
|
|
18
|
+
const { applyFilters, filters, items, status, error } = useNotificationList({ size: MAX_ITEMS })
|
|
19
|
+
const hasUnreadNotification = useUnreadNotifications()
|
|
20
|
+
const controller = useNotificationController()
|
|
21
|
+
|
|
22
|
+
useEffectOnce(() => {
|
|
23
|
+
controller.checkUnread()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (open && (hasUnreadNotification || getNameFromFilters(filters) !== 'ALL')) {
|
|
28
|
+
applyFilters(getFiltersFromName('ALL'))
|
|
29
|
+
}
|
|
30
|
+
}, [open])
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<NotificationBox>
|
|
34
|
+
<IconButton
|
|
35
|
+
aria-label={status === 'startup' ? t.loadingNotifications : t.openNotifications}
|
|
36
|
+
onClick={status === 'startup' ? undefined : () => setOpen(true)}
|
|
37
|
+
className={listToClass([
|
|
38
|
+
'notification-button',
|
|
39
|
+
status === 'startup' && 'loading',
|
|
40
|
+
status !== 'startup' && hasUnreadNotification && 'unread',
|
|
41
|
+
])}
|
|
42
|
+
>
|
|
43
|
+
<IconBox size="md" className="notificationsTour" >
|
|
44
|
+
<Bell />
|
|
45
|
+
</IconBox>
|
|
46
|
+
</IconButton>
|
|
47
|
+
<NotificationPanel
|
|
48
|
+
filter={getNameFromFilters(filters)}
|
|
49
|
+
loading={status === 'loading'}
|
|
50
|
+
error={error}
|
|
51
|
+
items={items}
|
|
52
|
+
visible={open}
|
|
53
|
+
onClose={() => setOpen(false)}
|
|
54
|
+
onFilter={filter => applyFilters({ ...getFiltersFromName(filter), size: MAX_ITEMS })}
|
|
55
|
+
/>
|
|
56
|
+
</NotificationBox>
|
|
57
|
+
)
|
|
58
|
+
}
|