@stack-spot/portal-layout 1.1.1 → 2.0.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 (80) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/Layout.d.ts +2 -11
  3. package/dist/Layout.d.ts.map +1 -1
  4. package/dist/Layout.js +6 -13
  5. package/dist/Layout.js.map +1 -1
  6. package/dist/WelcomeTour.d.ts +2 -0
  7. package/dist/WelcomeTour.d.ts.map +1 -0
  8. package/dist/WelcomeTour.js +8 -0
  9. package/dist/WelcomeTour.js.map +1 -0
  10. package/dist/components/PortalSwitcher.d.ts +6 -0
  11. package/dist/components/PortalSwitcher.d.ts.map +1 -1
  12. package/dist/components/PortalSwitcher.js +34 -2
  13. package/dist/components/PortalSwitcher.js.map +1 -1
  14. package/dist/components/error/ErrorBoundary.d.ts +10 -1
  15. package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
  16. package/dist/components/error/ErrorBoundary.js +1 -1
  17. package/dist/components/error/ErrorBoundary.js.map +1 -1
  18. package/dist/components/error/ErrorManager.d.ts +1 -1
  19. package/dist/components/error/ErrorManager.d.ts.map +1 -1
  20. package/dist/components/error/SilentErrorBoundary.d.ts +10 -1
  21. package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
  22. package/dist/components/menu/MenuSections.d.ts.map +1 -1
  23. package/dist/components/menu/MenuSections.js +2 -2
  24. package/dist/components/menu/MenuSections.js.map +1 -1
  25. package/dist/components/tour/StepContainer.d.ts +29 -0
  26. package/dist/components/tour/StepContainer.d.ts.map +1 -0
  27. package/dist/components/tour/StepContainer.js +52 -0
  28. package/dist/components/tour/StepContainer.js.map +1 -0
  29. package/dist/components/tour/StepNavigation.d.ts +29 -0
  30. package/dist/components/tour/StepNavigation.d.ts.map +1 -0
  31. package/dist/components/tour/StepNavigation.js +36 -0
  32. package/dist/components/tour/StepNavigation.js.map +1 -0
  33. package/dist/components/tour/StepTitle.d.ts +17 -0
  34. package/dist/components/tour/StepTitle.d.ts.map +1 -0
  35. package/dist/components/tour/StepTitle.js +9 -0
  36. package/dist/components/tour/StepTitle.js.map +1 -0
  37. package/dist/components/tour/hook.d.ts +3 -0
  38. package/dist/components/tour/hook.d.ts.map +1 -0
  39. package/dist/components/tour/hook.js +10 -0
  40. package/dist/components/tour/hook.js.map +1 -0
  41. package/dist/components/tour/index.d.ts +5 -0
  42. package/dist/components/tour/index.d.ts.map +1 -0
  43. package/dist/components/tour/index.js +5 -0
  44. package/dist/components/tour/index.js.map +1 -0
  45. package/dist/components/tour/manager.d.ts +32 -0
  46. package/dist/components/tour/manager.d.ts.map +1 -0
  47. package/dist/components/tour/manager.js +98 -0
  48. package/dist/components/tour/manager.js.map +1 -0
  49. package/dist/components/tour/utils.d.ts +50 -0
  50. package/dist/components/tour/utils.d.ts.map +1 -0
  51. package/dist/components/tour/utils.js +60 -0
  52. package/dist/components/tour/utils.js.map +1 -0
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +1 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/layout.css +0 -1
  58. package/package.json +7 -4
  59. package/readme.md +1 -0
  60. package/src/Layout.tsx +23 -41
  61. package/src/WelcomeTour.tsx +8 -0
  62. package/src/components/PortalSwitcher.tsx +42 -1
  63. package/src/components/error/ErrorBoundary.tsx +1 -1
  64. package/src/components/error/ErrorManager.ts +1 -1
  65. package/src/components/error/SilentErrorBoundary.tsx +1 -1
  66. package/src/components/menu/MenuSections.tsx +3 -4
  67. package/src/components/tour/StepContainer.tsx +83 -0
  68. package/src/components/tour/StepNavigation.tsx +70 -0
  69. package/src/components/tour/StepTitle.tsx +27 -0
  70. package/src/components/tour/hook.ts +12 -0
  71. package/src/components/tour/index.ts +6 -0
  72. package/src/components/tour/manager.tsx +111 -0
  73. package/src/components/tour/utils.tsx +100 -0
  74. package/src/index.ts +1 -0
  75. package/src/layout.css +0 -1
  76. package/dist/components/tour/PortalSwitcherStep.d.ts +0 -8
  77. package/dist/components/tour/PortalSwitcherStep.d.ts.map +0 -1
  78. package/dist/components/tour/PortalSwitcherStep.js +0 -34
  79. package/dist/components/tour/PortalSwitcherStep.js.map +0 -1
  80. package/src/components/tour/PortalSwitcherStep.tsx +0 -39
@@ -1,4 +1,4 @@
1
- import { Button, Flex, IconBox, Text } from '@citric/core'
1
+ import { Box, Button, Flex, IconBox, Image, Text } from '@citric/core'
2
2
  import { ArrowRight, CheckCircleFill, Select } from '@citric/icons'
3
3
  import { SelectionList } from '@stack-spot/portal-components/SelectionList'
4
4
  import { AI, EDP, HUB, Logo } from '@stack-spot/portal-components/svg'
@@ -7,6 +7,7 @@ import { useTranslate } from '@stack-spot/portal-translate'
7
7
  import { ReactNode, useState } from 'react'
8
8
  import styled from 'styled-components'
9
9
  import { announce } from '../utils'
10
+ import { useTour } from './tour'
10
11
  import { PortalAcronym } from './types'
11
12
 
12
13
  const Logos: Record<PortalAcronym, ReactNode> = {
@@ -98,6 +99,7 @@ export const PortalSwitcher = ({ portals = [] }: PortalSwitcherProps) => {
98
99
  const [visible, setVisible] = useState<boolean>(false)
99
100
  const t = useTranslate(translations)
100
101
  const currentPortal = portals?.find(portal => location.href.startsWith(portal.url))
102
+ usePortalSwitcherTourStep()
101
103
 
102
104
  return <PortalSwitcherBox>
103
105
  {currentPortal ?
@@ -159,3 +161,42 @@ const translations = {
159
161
  selected: 'selecionado',
160
162
  },
161
163
  }
164
+
165
+
166
+ /**
167
+ * Tutorial: a React hook for retrieving the React Tour step that explains how the portal switcher works. The portal switcher is a component
168
+ * at the top left corner of the layout (header) that allows the user to switch between the different Stackspot portals.
169
+ * @returns the React Tour step for the PortalSwitcher.
170
+ */
171
+ export const usePortalSwitcherTourStep = () => {
172
+ const t = useTranslate(tourTranslations)
173
+ const { addStep } = useTour()
174
+
175
+ addStep({
176
+ selector: '.portal-switcher',
177
+ title: t.title,
178
+ content: <>
179
+ <Image src="https://marketing.stackspot.com/switch-v2.gif" alt={t.imageAlt} />
180
+ <Box px={5} py={3}>
181
+ <Text appearance="microtext1" colorScheme="inverse.contrastText">{t.description}</Text>
182
+ </Box>
183
+ </>,
184
+ position: 'right',
185
+ style: {
186
+ width: '300px',
187
+ },
188
+ })
189
+ }
190
+
191
+ const tourTranslations = {
192
+ en: {
193
+ title: 'Expand Your Horizons with Stackspot',
194
+ description: 'Easily switch between EDP and AI to enhance your projects. Access a wide range of resources with just one click and take your projects to a new level of efficiency. Start your journey now!',
195
+ imageAlt: 'GIF describing how to use product switcher and navigate between AI and EDP portals',
196
+ },
197
+ pt: {
198
+ title: 'Expanda Seus Horizontes com Stackspot',
199
+ description: 'Troque facilmente entre EDP e AI para aprimorar seus projetos. Acesse uma ampla gama de recursos com apenas um clique e leve seus projetos para um novo nível de eficiência. Comece sua jornada agora!',
200
+ imageAlt: 'GIF mostrando como usar o alternador de produtos e navegar entre os portais AI e EDP',
201
+ },
202
+ }
@@ -1,4 +1,4 @@
1
- import { ErrorDescription, ErrorFeedback } from '@stack-spot/portal-components/ErrorFeedback'
1
+ import { ErrorDescription, ErrorFeedback } from '@stack-spot/portal-components/error'
2
2
  import { Component } from 'react'
3
3
  import { ErrorManager } from './ErrorManager'
4
4
 
@@ -1,4 +1,4 @@
1
- import { ErrorDescription } from '@stack-spot/portal-components/ErrorFeedback'
1
+ import { ErrorDescription } from '@stack-spot/portal-components/error'
2
2
 
3
3
  export type DescriptionFn = (error: any) => ErrorDescription
4
4
  export type ErrorHandler = (error: any) => void
@@ -1,4 +1,4 @@
1
- import { ErrorDescription } from '@stack-spot/portal-components/ErrorFeedback'
1
+ import { ErrorDescription } from '@stack-spot/portal-components/error'
2
2
  import { theme } from '@stack-spot/portal-theme'
3
3
  import { Component } from 'react'
4
4
  import { ErrorManager } from './ErrorManager'
@@ -147,8 +147,7 @@ const Section = ({
147
147
  role="menuitem"
148
148
  key={labelText}
149
149
  title={labelText}
150
- className={`section-submenu ${className || ''} ${active ? 'active' : ''}`}
151
- aria-selected={active}>
150
+ className={`section-submenu ${className || ''} ${active ? 'active' : ''}`}>
152
151
  <Link
153
152
  href={href}
154
153
  target={target}
@@ -286,10 +285,10 @@ export const MenuSections = ({ sections = [], ...props }: MenuProps) => {
286
285
 
287
286
  return (
288
287
  <>
289
- <ul>{sectionItems}</ul>
288
+ <ul role="menu">{sectionItems}</ul>
290
289
 
291
290
  <Flex mb={7} alignItems="center">
292
- <button className="toggle sections-footer" onClick={() => toggleMenu(!!props.content || !!props.customContent)}
291
+ <button role="menuitem" className="toggle sections-footer" onClick={() => toggleMenu(!!props.content || !!props.customContent)}
293
292
  title={t.toggle} tabIndex={-1}>
294
293
  <IconBox>
295
294
  <Expand className="expand" />
@@ -0,0 +1,83 @@
1
+ import { theme } from '@stack-spot/portal-theme'
2
+ import { ReactNode } from 'react'
3
+ import { styled } from 'styled-components'
4
+ import { NavigationProps, StepNavigation } from './StepNavigation'
5
+ import { StepTitle } from './StepTitle'
6
+ import { useTour } from './hook'
7
+
8
+ interface StepContainerProps {
9
+ children: ReactNode,
10
+ /**
11
+ * The unique identifier for the step.
12
+ */
13
+ stepKey: string,
14
+ /**
15
+ * The title for the step.
16
+ */
17
+ title: string,
18
+ /**
19
+ * The position of the tour overlay related to the content being explained.
20
+ */
21
+ position: PointingArrowPosition,
22
+ /**
23
+ * A customizable set of buttons for navigating the tour steps.
24
+ */
25
+ customNavigation?: Omit<NavigationProps, 'stepKey'>,
26
+ }
27
+
28
+ /**
29
+ * Tutorial: the overlay component for showing a step on React Tour.
30
+ * @param props the react props for the component {@link StepContainerProps}.
31
+ */
32
+ export const StepContainer = ({ title, stepKey, customNavigation, position, children }: StepContainerProps) => {
33
+ const { finishStep } = useTour()
34
+ return <BoxWithPointingArrow $position={position}>
35
+ <StepTitle title={title} onClose={() => finishStep(stepKey)} />
36
+ {children}
37
+ <StepNavigation stepKey={stepKey} {...(customNavigation || {})} />
38
+ </BoxWithPointingArrow>
39
+ }
40
+
41
+ export type PointingArrowPosition = 'right' | 'top' | 'left' | 'bottom'
42
+
43
+ const BoxWithPointingArrow = styled.div < {
44
+ $position: PointingArrowPosition,
45
+ $top?: string,
46
+ $right?: string,
47
+ } > `
48
+ position: relative;
49
+ width: 100%;
50
+ background-color: ${theme.color.inverse[500]};
51
+ &::after {
52
+ content: '';
53
+ position: absolute;
54
+ border-width: 10px;
55
+ border-style: solid;
56
+ border-color: transparent;
57
+ margin-top: -5px;
58
+ border-right-color: ${theme.color.inverse[500]};
59
+ ${({ $position, $top }) => $position === 'right' ?
60
+ `
61
+ top: ${$top || '16px'};
62
+ left: -18px;
63
+ ` : ''}
64
+ ${({ $position, $right }) => $position === 'top' ?
65
+ `
66
+ bottom: 96%;
67
+ right: ${$right || '16px'};
68
+ transform: rotate(90deg);
69
+ ` : ''}
70
+ ${({ $position, $top }) => $position === 'left' ?
71
+ `
72
+ top: ${$top || '16px'};
73
+ right: -18px;
74
+ transform: rotate(180deg);
75
+ ` : ''}
76
+ ${({ $position, $right }) => $position === 'bottom' ?
77
+ `
78
+ top: -13px;
79
+ right: ${$right || '16px'};
80
+ transform: rotate(90deg);
81
+ ` : ''}
82
+ }
83
+ `
@@ -0,0 +1,70 @@
1
+ import { Button, Flex, Text } from '@citric/core'
2
+ import '@stack-spot/portal-theme/dist/theme.css'
3
+ import { useTranslate } from '@stack-spot/portal-translate'
4
+ import { useTour } from './hook'
5
+
6
+ interface CustomNavigationButton {
7
+ /**
8
+ * The text content to render.
9
+ */
10
+ text: string,
11
+ onClick?: () => void,
12
+ }
13
+
14
+ export interface NavigationProps {
15
+ /**
16
+ * The unique identifier of the step.
17
+ */
18
+ stepKey: string,
19
+ /**
20
+ * The text and click handler for the button "next".
21
+ */
22
+ nextButton?: CustomNavigationButton,
23
+ /**
24
+ * The text and click handler for the button "previous".
25
+ */
26
+ prevButton?: CustomNavigationButton,
27
+ }
28
+
29
+ /**
30
+ * Tutorial: the component in a React Tour overlay that shows the next and previous buttons (for step navigation).
31
+ * @param props the react props for the component {@link NavigationProps}.
32
+ */
33
+ export const StepNavigation = ({ stepKey, nextButton, prevButton }: NavigationProps) => {
34
+ const { currentStep, steps, prevStep, finishStep } = useTour()
35
+ const t = useTranslate(translations)
36
+
37
+ return <Flex w={12} px={5} py={2} mt="-1px" bg="inverse.500" justifyContent="space-between" alignItems="center">
38
+ <Text appearance="microtext1" colorScheme="inverse.contrastText">{currentStep + 1} {t.of} {steps.length}</Text>
39
+ <Flex sx={{ gap: '8px' }}>
40
+ {currentStep >= 1 &&
41
+ <Button sx={{ paddingInline: '20px' }} onClick={() => {
42
+ prevStep?.()
43
+ prevButton?.onClick?.()
44
+ }} size="sm" appearance="text" colorScheme="light">
45
+ {prevButton?.text || t.back}
46
+ </Button>}
47
+ <Button sx={{ paddingInline: '20px' }} onClick={() => {
48
+ nextButton?.onClick?.()
49
+ finishStep(stepKey)
50
+ }} size="sm" colorScheme="light">
51
+ {nextButton?.text || (currentStep < steps.length - 1 ? t.next : t.done)}
52
+ </Button>
53
+ </Flex>
54
+ </Flex>
55
+ }
56
+
57
+ const translations = {
58
+ en: {
59
+ of: 'of',
60
+ back: 'Back',
61
+ next: 'Next',
62
+ done: 'Done',
63
+ },
64
+ pt: {
65
+ of: 'de',
66
+ back: 'Voltar',
67
+ next: 'Próximo',
68
+ done: 'Finalizado',
69
+ },
70
+ }
@@ -0,0 +1,27 @@
1
+ import { Button, Flex, IconBox, Text } from '@citric/core'
2
+ import { TimesMini } from '@citric/icons'
3
+
4
+ interface StepTitleProps {
5
+ /**
6
+ * The step's title.
7
+ */
8
+ title: string,
9
+ /**
10
+ * A function to run once the step is closed.
11
+ */
12
+ onClose?: () => void,
13
+ }
14
+
15
+ /**
16
+ * Tutorial: the component in a React Tour overlay that renders the title.
17
+ * @param props the react props for the component {@link StepTitleProps}.
18
+ */
19
+ export const StepTitle = ({ title, onClose }: StepTitleProps) =>
20
+ <Flex w={12} pl={5} py={3} flexWrap="nowrap" justifyContent="space-between" alignItems="center">
21
+ <Text appearance="body2" colorScheme="inverse.contrastText" weight="medium"> {title} </Text>
22
+ <Button appearance="text" size="sm" onClick={() => onClose?.()} sx={{ ':hover': { borderColor: 'transparent !important' } }}>
23
+ <IconBox size="xs" colorIcon="inverse.contrastText">
24
+ <TimesMini />
25
+ </IconBox>
26
+ </Button>
27
+ </Flex>
@@ -0,0 +1,12 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { TourConfigExtra, tourManager } from './manager'
3
+
4
+ export const useTour = () => {
5
+ const [tourConfig, setTourConfig] = useState<TourConfigExtra>(tourManager.config)
6
+
7
+ useEffect(() => tourManager.subscribe((config) => {
8
+ setTourConfig(config)
9
+ }), [])
10
+
11
+ return tourConfig
12
+ }
@@ -0,0 +1,6 @@
1
+
2
+ export { StepContainer } from './StepContainer'
3
+ export { useTour } from './hook'
4
+ export { TourConfig, TourConfigListener, TourStep, WelcomeTour, tourManager } from './manager'
5
+ export { StackspotTourStep, hasFinishedTourStep, isNewTourStep, tourStepBuilder } from './utils'
6
+
@@ -0,0 +1,111 @@
1
+ import WelcomeTour, { ReactourProps, ReactourStep } from 'reactour'
2
+ import { StackspotTourStep, finishTourStep, isNewTourStep, tourStepBuilder } from './utils'
3
+
4
+ export type TourConfig = Omit<ReactourProps, 'children'>
5
+ export type TourStep = ReactourStep
6
+
7
+ /**
8
+ * Tutorial: the default configuration for a React Tour.
9
+ */
10
+ const defaultTourConfig: TourConfig = Object.freeze({
11
+ steps: [],
12
+ isOpen: true,
13
+ onRequestClose: () => '',
14
+ showButtons: false,
15
+ showNavigation: false,
16
+ showNavigationNumber: false,
17
+ showNumber: false,
18
+ showCloseButton: false,
19
+ disableFocusLock: true,
20
+ })
21
+
22
+
23
+ export type TourConfigExtra = TourConfig & {
24
+ currentStep: number,
25
+ finishStep: (stepSelector: string) => void,
26
+ addStep: (step: StackspotTourStep) => void,
27
+ }
28
+
29
+ type TourConfigListener = (config: TourConfigExtra) => void
30
+
31
+
32
+ /**
33
+ * TourManager: provides state management for React Tour.
34
+ */
35
+ class TourManager {
36
+
37
+ private _steps: TourStep[] = []
38
+ private _currentStep = 0
39
+ private observers: TourConfigListener[] = []
40
+
41
+ get config(): TourConfigExtra {
42
+ const config = {
43
+ ...defaultTourConfig,
44
+ goToStep: this._currentStep,
45
+ update: `${this._currentStep}`,
46
+ steps: this._steps,
47
+ isOpen: !!this._steps.length && (this._currentStep < this._steps.length),
48
+ currentStep: this._currentStep,
49
+ nextStep: () => this.nextStep(),
50
+ prevStep: () => this.prevStep(),
51
+ finishStep: (stepSelector: string) => this.finishStep(stepSelector),
52
+ addStep: (step: StackspotTourStep) => this.addStep(step),
53
+ }
54
+ return config
55
+ }
56
+
57
+ get currentStep() {
58
+ return this._currentStep
59
+ }
60
+
61
+ get steps() {
62
+ return this._steps
63
+ }
64
+
65
+ addStep(step: StackspotTourStep) {
66
+ this.addRawStep(tourStepBuilder(step))
67
+ }
68
+
69
+ addRawStep(step: TourStep) {
70
+ const stepAlreadyAdded = this._steps.some(it => it.selector == step.selector)
71
+ if (!stepAlreadyAdded && isNewTourStep(step)) {
72
+ this._steps = [...this._steps, step]
73
+ this.notify()
74
+ }
75
+ }
76
+
77
+ nextStep() {
78
+ this._currentStep = this._currentStep + 1
79
+ this.notify()
80
+ }
81
+
82
+ prevStep() {
83
+ this._currentStep = this._currentStep - 1
84
+ this.notify()
85
+ }
86
+
87
+ finishStep(stepSelector: string) {
88
+ finishTourStep(stepSelector)
89
+ this.nextStep()
90
+ }
91
+
92
+ subscribe(updateFn: TourConfigListener) {
93
+ this.observers.push(updateFn)
94
+ this.notify()
95
+ return () => this.pullListener(updateFn)
96
+ }
97
+
98
+ private pullListener(updateFn: TourConfigListener) {
99
+ this.observers = this.observers.filter((obs) => obs !== updateFn)
100
+ }
101
+
102
+ private notify() {
103
+ this.observers.forEach((updateFn) => updateFn(this.config))
104
+ }
105
+
106
+ }
107
+
108
+ const tourManager = new TourManager()
109
+
110
+ export { TourConfigListener, WelcomeTour, tourManager }
111
+
@@ -0,0 +1,100 @@
1
+ import { getCookie, setCookie } from '@stack-spot/portal-components'
2
+ import { theme } from '@stack-spot/portal-theme'
3
+ import { ReactNode } from 'react'
4
+ import { ReactourStep } from 'reactour'
5
+ import { PointingArrowPosition, StepContainer } from './StepContainer'
6
+ import { NavigationProps } from './StepNavigation'
7
+
8
+ const TOUR_COOKIE = 'guided-tour-global'
9
+
10
+ const defaultExpires = new Date()
11
+ defaultExpires.setFullYear(new Date().getFullYear() + 1)
12
+
13
+ const getTourCookie = () => {
14
+ const currentTourObject = getCookie(TOUR_COOKIE)
15
+ return currentTourObject ? currentTourObject.split(',') : []
16
+ }
17
+
18
+ /**
19
+ * Tutorial: marks the tour step as finished. This sets a cookie, preventing the tour from showing again.
20
+ * @param key the identifier for the step to mark as finished.
21
+ */
22
+ export const finishTourStep = (key: string) => {
23
+ const finishedTours: string[] = getTourCookie()
24
+ if (!finishedTours.includes(key)) finishedTours.push(key)
25
+ setCookie(TOUR_COOKIE, finishedTours.toString(), { expires: defaultExpires.toUTCString() })
26
+ }
27
+
28
+ /**
29
+ * Tutorial: verifies if the React Tour step has not finished yet.
30
+ *
31
+ * A step has not finished if the array stored as a cookie doesn't include the string value of `step.selector`.
32
+ * @param step the step config.
33
+ * @returns true if the step has not yet been marked as finished. False otherwise.
34
+ */
35
+ export const isNewTourStep = (step: ReactourStep) => !hasFinishedTourStep(`${step.selector}`)
36
+
37
+ /**
38
+ * Tutorial: verifies if the key passed as parameter refers to a React Tour step that has already finished.
39
+ *
40
+ * The key refers to a finished step if the array stored as a cookie includes it.
41
+ * If the cookie is set to 'disabled', then the step will be considered finished.Particularly useful in scenarios like e2e tests.
42
+ * @param key the step's identifier to check.
43
+ * @returns true if the key refers to a finished step. False otherwise.
44
+ */
45
+ export const hasFinishedTourStep = (key: string) => {
46
+ const tourCookie = getTourCookie()
47
+ return tourCookie.includes(key) || tourCookie[0] === 'disabled'
48
+ }
49
+
50
+ export interface StackspotTourStep extends ReactourStep {
51
+ /**
52
+ * The step's title.
53
+ */
54
+ title: string,
55
+ /**
56
+ * The unique identifier for the step (key).
57
+ */
58
+ selector: string,
59
+ /**
60
+ * The step's content.
61
+ */
62
+ content: ReactNode,
63
+ /**
64
+ * A set of properties for customizing the next and previous buttons.
65
+ */
66
+ customNavigation?: NavigationProps,
67
+ }
68
+
69
+ /**
70
+ * Tutorial: utility for building a React Tour step. This already includes some default configuration for tours in Stackspot.
71
+ * @param options the options for building the step: {@link StackspotTourStep}.
72
+ * @returns the React Tour step.
73
+ */
74
+ export const tourStepBuilder = ({
75
+ selector,
76
+ position,
77
+ title,
78
+ content,
79
+ style,
80
+ customNavigation,
81
+ ...rest
82
+ }: StackspotTourStep): ReactourStep => ({
83
+ selector,
84
+ content: (<StepContainer
85
+ stepKey={selector}
86
+ position={position as PointingArrowPosition}
87
+ title={title}
88
+ customNavigation={customNavigation}>
89
+ {content}
90
+ </StepContainer>),
91
+ position,
92
+ style: {
93
+ backgroundColor: theme.color.inverse[500],
94
+ width: '256px',
95
+ padding: 0,
96
+ top: ['right', 'left'].includes(position as PointingArrowPosition) ? '-3px' : '0',
97
+ ...(style || {}),
98
+ },
99
+ ...(rest || {}),
100
+ })
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export { PortalSwitcher } from './components/PortalSwitcher'
7
7
  export { ActionItem, MenuContent, MenuGroup, Title } from './components/menu/MenuContent'
8
8
  export { MenuSections } from './components/menu/MenuSections'
9
9
  export * from './components/menu/types'
10
+ export * from './components/tour'
10
11
  export * from './components/types'
11
12
  export * from './elements'
12
13
  export * from './errors'
package/src/layout.css CHANGED
@@ -179,7 +179,6 @@ body {
179
179
  #menuSections > ul li a {
180
180
  background: transparent;
181
181
  border: none;
182
- outline: none;
183
182
  width: var(--menu-sections-width);
184
183
  height: var(--menu-item-height);
185
184
  display: flex;
@@ -1,8 +0,0 @@
1
- import { TourStep } from '@stack-spot/portal-components/Tour';
2
- /**
3
- * Tutorial: a React hook for retrieving the React Tour step that explains how the portal switcher works. The portal switcher is a component
4
- * at the top left corner of the layout (header) that allows the user to switch between the different Stackspot portals.
5
- * @returns the React Tour step for the PortalSwitcher.
6
- */
7
- export declare const usePortalSwitcherStep: () => TourStep;
8
- //# sourceMappingURL=PortalSwitcherStep.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PortalSwitcherStep.d.ts","sourceRoot":"","sources":["../../../src/components/tour/PortalSwitcherStep.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAmB,MAAM,oCAAoC,CAAA;AAG9E;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAO,QAgBxC,CAAA"}
@@ -1,34 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Image, Text } from '@citric/core';
3
- import { tourStepBuilder } from '@stack-spot/portal-components/Tour';
4
- import { useTranslate } from '@stack-spot/portal-translate';
5
- /**
6
- * Tutorial: a React hook for retrieving the React Tour step that explains how the portal switcher works. The portal switcher is a component
7
- * at the top left corner of the layout (header) that allows the user to switch between the different Stackspot portals.
8
- * @returns the React Tour step for the PortalSwitcher.
9
- */
10
- export const usePortalSwitcherStep = () => {
11
- const t = useTranslate(translations);
12
- return tourStepBuilder({
13
- selector: '.portal-switcher',
14
- title: t.title,
15
- content: _jsxs(_Fragment, { children: [_jsx(Image, { src: "https://marketing.stackspot.com/switch-v2.gif", alt: t.imageAlt }), _jsx(Box, { px: 5, py: 3, children: _jsx(Text, { appearance: "microtext1", colorScheme: "inverse.contrastText", children: t.description }) })] }),
16
- position: 'right',
17
- style: {
18
- width: '300px',
19
- },
20
- });
21
- };
22
- const translations = {
23
- en: {
24
- title: 'Expand Your Horizons with Stackspot',
25
- description: 'Easily switch between EDP and AI to enhance your projects. Access a wide range of resources with just one click and take your projects to a new level of efficiency. Start your journey now!',
26
- imageAlt: 'GIF describing how to use product switcher and navigate between AI and EDP portals',
27
- },
28
- pt: {
29
- title: 'Expanda Seus Horizontes com Stackspot',
30
- description: 'Troque facilmente entre EDP e AI para aprimorar seus projetos. Acesse uma ampla gama de recursos com apenas um clique e leve seus projetos para um novo nível de eficiência. Comece sua jornada agora!',
31
- imageAlt: 'GIF mostrando como usar o alternador de produtos e navegar entre os portais AI e EDP',
32
- },
33
- };
34
- //# sourceMappingURL=PortalSwitcherStep.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PortalSwitcherStep.js","sourceRoot":"","sources":["../../../src/components/tour/PortalSwitcherStep.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAY,eAAe,EAAE,MAAM,oCAAoC,CAAA;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAa,EAAE;IAClD,MAAM,CAAC,GAAG,YAAY,CAAC,YAAY,CAAC,CAAA;IACpC,OAAO,eAAe,CAAC;QACrB,QAAQ,EAAE,kBAAkB;QAC5B,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,OAAO,EAAE,8BACP,KAAC,KAAK,IAAC,GAAG,EAAC,+CAA+C,EAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,GAAI,EAC9E,KAAC,GAAG,IAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,UAAU,EAAC,YAAY,EAAC,WAAW,EAAC,sBAAsB,YAAE,CAAC,CAAC,WAAW,GAAQ,GACnF,IACL;QACH,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE;YACL,KAAK,EAAE,OAAO;SACf;KACF,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,YAAY,GAAG;IACnB,EAAE,EAAE;QACF,KAAK,EAAE,qCAAqC;QAC5C,WAAW,EAAE,8LAA8L;QAC3M,QAAQ,EAAE,oFAAoF;KAC/F;IACD,EAAE,EAAE;QACF,KAAK,EAAE,uCAAuC;QAC9C,WAAW,EAAE,wMAAwM;QACrN,QAAQ,EAAE,sFAAsF;KACjG;CACF,CAAA"}
@@ -1,39 +0,0 @@
1
- import { Box, Image, Text } from '@citric/core'
2
- import { TourStep, tourStepBuilder } from '@stack-spot/portal-components/Tour'
3
- import { useTranslate } from '@stack-spot/portal-translate'
4
-
5
- /**
6
- * Tutorial: a React hook for retrieving the React Tour step that explains how the portal switcher works. The portal switcher is a component
7
- * at the top left corner of the layout (header) that allows the user to switch between the different Stackspot portals.
8
- * @returns the React Tour step for the PortalSwitcher.
9
- */
10
- export const usePortalSwitcherStep = (): TourStep => {
11
- const t = useTranslate(translations)
12
- return tourStepBuilder({
13
- selector: '.portal-switcher',
14
- title: t.title,
15
- content: <>
16
- <Image src="https://marketing.stackspot.com/switch-v2.gif" alt={t.imageAlt} />
17
- <Box px={5} py={3}>
18
- <Text appearance="microtext1" colorScheme="inverse.contrastText">{t.description}</Text>
19
- </Box>
20
- </>,
21
- position: 'right',
22
- style: {
23
- width: '300px',
24
- },
25
- })
26
- }
27
-
28
- const translations = {
29
- en: {
30
- title: 'Expand Your Horizons with Stackspot',
31
- description: 'Easily switch between EDP and AI to enhance your projects. Access a wide range of resources with just one click and take your projects to a new level of efficiency. Start your journey now!',
32
- imageAlt: 'GIF describing how to use product switcher and navigate between AI and EDP portals',
33
- },
34
- pt: {
35
- title: 'Expanda Seus Horizontes com Stackspot',
36
- description: 'Troque facilmente entre EDP e AI para aprimorar seus projetos. Acesse uma ampla gama de recursos com apenas um clique e leve seus projetos para um novo nível de eficiência. Comece sua jornada agora!',
37
- imageAlt: 'GIF mostrando como usar o alternador de produtos e navegar entre os portais AI e EDP',
38
- },
39
- }