@stack-spot/portal-layout 1.1.2 → 2.0.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 +22 -0
- package/dist/Layout.d.ts +2 -11
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +6 -13
- package/dist/Layout.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/PortalSwitcher.d.ts +6 -0
- package/dist/components/PortalSwitcher.d.ts.map +1 -1
- package/dist/components/PortalSwitcher.js +34 -2
- package/dist/components/PortalSwitcher.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +10 -1
- package/dist/components/error/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/error/ErrorBoundary.js +1 -1
- package/dist/components/error/ErrorBoundary.js.map +1 -1
- package/dist/components/error/ErrorManager.d.ts +1 -1
- package/dist/components/error/ErrorManager.d.ts.map +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +10 -1
- package/dist/components/error/SilentErrorBoundary.d.ts.map +1 -1
- package/dist/components/tour/StepContainer.d.ts +29 -0
- package/dist/components/tour/StepContainer.d.ts.map +1 -0
- package/dist/components/tour/StepContainer.js +52 -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 +36 -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 +9 -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 +32 -0
- package/dist/components/tour/manager.d.ts.map +1 -0
- package/dist/components/tour/manager.js +98 -0
- package/dist/components/tour/manager.js.map +1 -0
- package/dist/components/tour/utils.d.ts +50 -0
- package/dist/components/tour/utils.d.ts.map +1 -0
- package/dist/components/tour/utils.js +60 -0
- package/dist/components/tour/utils.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/layout.css +1 -1
- package/package.json +7 -4
- package/readme.md +2 -0
- package/src/Layout.tsx +23 -41
- package/src/WelcomeTour.tsx +8 -0
- package/src/components/PortalSwitcher.tsx +42 -1
- package/src/components/error/ErrorBoundary.tsx +1 -1
- package/src/components/error/ErrorManager.ts +1 -1
- package/src/components/error/SilentErrorBoundary.tsx +1 -1
- package/src/components/tour/StepContainer.tsx +83 -0
- package/src/components/tour/StepNavigation.tsx +70 -0
- package/src/components/tour/StepTitle.tsx +27 -0
- package/src/components/tour/hook.ts +12 -0
- package/src/components/tour/index.ts +6 -0
- package/src/components/tour/manager.tsx +111 -0
- package/src/components/tour/utils.tsx +100 -0
- package/src/index.ts +1 -0
- package/src/layout.css +1 -1
- package/dist/components/tour/PortalSwitcherStep.d.ts +0 -8
- package/dist/components/tour/PortalSwitcherStep.d.ts.map +0 -1
- package/dist/components/tour/PortalSwitcherStep.js +0 -34
- package/dist/components/tour/PortalSwitcherStep.js.map +0 -1
- package/src/components/tour/PortalSwitcherStep.tsx +0 -39
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/tour/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC9F,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/tour/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,EAA4C,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC9F,OAAO,EAAqB,mBAAmB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import WelcomeTour, { ReactourProps, ReactourStep } from 'reactour';
|
|
2
|
+
import { StackspotTourStep } from './utils.js';
|
|
3
|
+
export type TourConfig = Omit<ReactourProps, 'children'>;
|
|
4
|
+
export type TourStep = ReactourStep;
|
|
5
|
+
export type TourConfigExtra = TourConfig & {
|
|
6
|
+
currentStep: number;
|
|
7
|
+
finishStep: (stepSelector: string) => void;
|
|
8
|
+
addStep: (step: StackspotTourStep) => void;
|
|
9
|
+
};
|
|
10
|
+
type TourConfigListener = (config: TourConfigExtra) => void;
|
|
11
|
+
/**
|
|
12
|
+
* TourManager: provides state management for React Tour.
|
|
13
|
+
*/
|
|
14
|
+
declare class TourManager {
|
|
15
|
+
private _steps;
|
|
16
|
+
private _currentStep;
|
|
17
|
+
private observers;
|
|
18
|
+
get config(): TourConfigExtra;
|
|
19
|
+
get currentStep(): number;
|
|
20
|
+
get steps(): ReactourStep[];
|
|
21
|
+
addStep(step: StackspotTourStep): void;
|
|
22
|
+
addRawStep(step: TourStep): void;
|
|
23
|
+
nextStep(): void;
|
|
24
|
+
prevStep(): void;
|
|
25
|
+
finishStep(stepSelector: string): void;
|
|
26
|
+
subscribe(updateFn: TourConfigListener): () => void;
|
|
27
|
+
private pullListener;
|
|
28
|
+
private notify;
|
|
29
|
+
}
|
|
30
|
+
declare const tourManager: TourManager;
|
|
31
|
+
export { TourConfigListener, WelcomeTour, tourManager };
|
|
32
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/components/tour/manager.tsx"],"names":[],"mappings":"AAAA,OAAO,WAAW,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAkD,MAAM,SAAS,CAAA;AAE3F,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AACxD,MAAM,MAAM,QAAQ,GAAG,YAAY,CAAA;AAkBnC,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,OAAO,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC5C,CAAA;AAED,KAAK,kBAAkB,GAAG,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;AAG3D;;GAEG;AACH,cAAM,WAAW;IAEf,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAI;IACxB,OAAO,CAAC,SAAS,CAA2B;IAE5C,IAAI,MAAM,IAAI,eAAe,CAc5B;IAED,IAAI,WAAW,WAEd;IAED,IAAI,KAAK,mBAER;IAED,OAAO,CAAC,IAAI,EAAE,iBAAiB;IAI/B,UAAU,CAAC,IAAI,EAAE,QAAQ;IAQzB,QAAQ;IAKR,QAAQ;IAKR,UAAU,CAAC,YAAY,EAAE,MAAM;IAK/B,SAAS,CAAC,QAAQ,EAAE,kBAAkB;IAMtC,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,MAAM;CAIf;AAED,QAAA,MAAM,WAAW,aAAoB,CAAA;AAErC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import WelcomeTour from 'reactour';
|
|
2
|
+
import { finishTourStep, isNewTourStep, tourStepBuilder } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tutorial: the default configuration for a React Tour.
|
|
5
|
+
*/
|
|
6
|
+
const defaultTourConfig = Object.freeze({
|
|
7
|
+
steps: [],
|
|
8
|
+
isOpen: true,
|
|
9
|
+
onRequestClose: () => '',
|
|
10
|
+
showButtons: false,
|
|
11
|
+
showNavigation: false,
|
|
12
|
+
showNavigationNumber: false,
|
|
13
|
+
showNumber: false,
|
|
14
|
+
showCloseButton: false,
|
|
15
|
+
disableFocusLock: true,
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* TourManager: provides state management for React Tour.
|
|
19
|
+
*/
|
|
20
|
+
class TourManager {
|
|
21
|
+
constructor() {
|
|
22
|
+
Object.defineProperty(this, "_steps", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: []
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(this, "_currentStep", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
value: 0
|
|
33
|
+
});
|
|
34
|
+
Object.defineProperty(this, "observers", {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
configurable: true,
|
|
37
|
+
writable: true,
|
|
38
|
+
value: []
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
get config() {
|
|
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) => this.finishStep(stepSelector),
|
|
52
|
+
addStep: (step) => this.addStep(step),
|
|
53
|
+
};
|
|
54
|
+
return config;
|
|
55
|
+
}
|
|
56
|
+
get currentStep() {
|
|
57
|
+
return this._currentStep;
|
|
58
|
+
}
|
|
59
|
+
get steps() {
|
|
60
|
+
return this._steps;
|
|
61
|
+
}
|
|
62
|
+
addStep(step) {
|
|
63
|
+
this.addRawStep(tourStepBuilder(step));
|
|
64
|
+
}
|
|
65
|
+
addRawStep(step) {
|
|
66
|
+
const stepAlreadyAdded = this._steps.some(it => it.selector == step.selector);
|
|
67
|
+
if (!stepAlreadyAdded && isNewTourStep(step)) {
|
|
68
|
+
this._steps = [...this._steps, step];
|
|
69
|
+
this.notify();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
nextStep() {
|
|
73
|
+
this._currentStep = this._currentStep + 1;
|
|
74
|
+
this.notify();
|
|
75
|
+
}
|
|
76
|
+
prevStep() {
|
|
77
|
+
this._currentStep = this._currentStep - 1;
|
|
78
|
+
this.notify();
|
|
79
|
+
}
|
|
80
|
+
finishStep(stepSelector) {
|
|
81
|
+
finishTourStep(stepSelector);
|
|
82
|
+
this.nextStep();
|
|
83
|
+
}
|
|
84
|
+
subscribe(updateFn) {
|
|
85
|
+
this.observers.push(updateFn);
|
|
86
|
+
this.notify();
|
|
87
|
+
return () => this.pullListener(updateFn);
|
|
88
|
+
}
|
|
89
|
+
pullListener(updateFn) {
|
|
90
|
+
this.observers = this.observers.filter((obs) => obs !== updateFn);
|
|
91
|
+
}
|
|
92
|
+
notify() {
|
|
93
|
+
this.observers.forEach((updateFn) => updateFn(this.config));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const tourManager = new TourManager();
|
|
97
|
+
export { WelcomeTour, tourManager };
|
|
98
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/components/tour/manager.tsx"],"names":[],"mappings":"AAAA,OAAO,WAA4C,MAAM,UAAU,CAAA;AACnE,OAAO,EAAqB,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAK3F;;GAEG;AACH,MAAM,iBAAiB,GAAe,MAAM,CAAC,MAAM,CAAC;IAClD,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,IAAI;IACZ,cAAc,EAAE,GAAG,EAAE,CAAC,EAAE;IACxB,WAAW,EAAE,KAAK;IAClB,cAAc,EAAE,KAAK;IACrB,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE,KAAK;IACjB,eAAe,EAAE,KAAK;IACtB,gBAAgB,EAAE,IAAI;CACvB,CAAC,CAAA;AAYF;;GAEG;AACH,MAAM,WAAW;IAAjB;QAEU;;;;mBAAqB,EAAE;WAAA;QACvB;;;;mBAAe,CAAC;WAAA;QAChB;;;;mBAAkC,EAAE;WAAA;IAmE9C,CAAC;IAjEC,IAAI,MAAM;QACR,MAAM,MAAM,GAAG;YACb,GAAG,iBAAiB;YACpB,QAAQ,EAAE,IAAI,CAAC,YAAY;YAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE;YAC9B,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;YACxE,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE;YAC/B,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE;YAC/B,UAAU,EAAE,CAAC,YAAoB,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;YACnE,OAAO,EAAE,CAAC,IAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;SACzD,CAAA;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,OAAO,CAAC,IAAuB;QAC7B,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;IACxC,CAAC;IAED,UAAU,CAAC,IAAc;QACvB,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC7E,IAAI,CAAC,gBAAgB,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YACpC,IAAI,CAAC,MAAM,EAAE,CAAA;QACf,CAAC;IACH,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAA;QACzC,IAAI,CAAC,MAAM,EAAE,CAAA;IACf,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAA;QACzC,IAAI,CAAC,MAAM,EAAE,CAAA;IACf,CAAC;IAED,UAAU,CAAC,YAAoB;QAC7B,cAAc,CAAC,YAAY,CAAC,CAAA;QAC5B,IAAI,CAAC,QAAQ,EAAE,CAAA;IACjB,CAAC;IAED,SAAS,CAAC,QAA4B;QACpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAA;QACb,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;IAC1C,CAAC;IAEO,YAAY,CAAC,QAA4B;QAC/C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAA;IACnE,CAAC;IAEO,MAAM;QACZ,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7D,CAAC;CAEF;AAED,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;AAErC,OAAO,EAAsB,WAAW,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ReactourStep } from 'reactour';
|
|
3
|
+
import { NavigationProps } from './StepNavigation.js';
|
|
4
|
+
/**
|
|
5
|
+
* Tutorial: marks the tour step as finished. This sets a cookie, preventing the tour from showing again.
|
|
6
|
+
* @param key the identifier for the step to mark as finished.
|
|
7
|
+
*/
|
|
8
|
+
export declare const finishTourStep: (key: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Tutorial: verifies if the React Tour step has not finished yet.
|
|
11
|
+
*
|
|
12
|
+
* A step has not finished if the array stored as a cookie doesn't include the string value of `step.selector`.
|
|
13
|
+
* @param step the step config.
|
|
14
|
+
* @returns true if the step has not yet been marked as finished. False otherwise.
|
|
15
|
+
*/
|
|
16
|
+
export declare const isNewTourStep: (step: ReactourStep) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Tutorial: verifies if the key passed as parameter refers to a React Tour step that has already finished.
|
|
19
|
+
*
|
|
20
|
+
* The key refers to a finished step if the array stored as a cookie includes it.
|
|
21
|
+
* If the cookie is set to 'disabled', then the step will be considered finished.Particularly useful in scenarios like e2e tests.
|
|
22
|
+
* @param key the step's identifier to check.
|
|
23
|
+
* @returns true if the key refers to a finished step. False otherwise.
|
|
24
|
+
*/
|
|
25
|
+
export declare const hasFinishedTourStep: (key: string) => boolean;
|
|
26
|
+
export interface StackspotTourStep extends ReactourStep {
|
|
27
|
+
/**
|
|
28
|
+
* The step's title.
|
|
29
|
+
*/
|
|
30
|
+
title: string;
|
|
31
|
+
/**
|
|
32
|
+
* The unique identifier for the step (key).
|
|
33
|
+
*/
|
|
34
|
+
selector: string;
|
|
35
|
+
/**
|
|
36
|
+
* The step's content.
|
|
37
|
+
*/
|
|
38
|
+
content: ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* A set of properties for customizing the next and previous buttons.
|
|
41
|
+
*/
|
|
42
|
+
customNavigation?: NavigationProps;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Tutorial: utility for building a React Tour step. This already includes some default configuration for tours in Stackspot.
|
|
46
|
+
* @param options the options for building the step: {@link StackspotTourStep}.
|
|
47
|
+
* @returns the React Tour step.
|
|
48
|
+
*/
|
|
49
|
+
export declare const tourStepBuilder: ({ selector, position, title, content, style, customNavigation, ...rest }: StackspotTourStep) => ReactourStep;
|
|
50
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/components/tour/utils.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAYlD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAS,MAAM,SAIzC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,SAAU,YAAY,YAA6C,CAAA;AAE7F;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,QAAS,MAAM,YAG9C,CAAA;AAED,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,OAAO,EAAE,SAAS,CAAC;IACnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACpC;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,6EAQzB,iBAAiB,KAAG,YAkBrB,CAAA"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getCookie, setCookie } from '@stack-spot/portal-components';
|
|
3
|
+
import { theme } from '@stack-spot/portal-theme';
|
|
4
|
+
import { StepContainer } from './StepContainer.js';
|
|
5
|
+
const TOUR_COOKIE = 'guided-tour-global';
|
|
6
|
+
const defaultExpires = new Date();
|
|
7
|
+
defaultExpires.setFullYear(new Date().getFullYear() + 1);
|
|
8
|
+
const getTourCookie = () => {
|
|
9
|
+
const currentTourObject = getCookie(TOUR_COOKIE);
|
|
10
|
+
return currentTourObject ? currentTourObject.split(',') : [];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Tutorial: marks the tour step as finished. This sets a cookie, preventing the tour from showing again.
|
|
14
|
+
* @param key the identifier for the step to mark as finished.
|
|
15
|
+
*/
|
|
16
|
+
export const finishTourStep = (key) => {
|
|
17
|
+
const finishedTours = getTourCookie();
|
|
18
|
+
if (!finishedTours.includes(key))
|
|
19
|
+
finishedTours.push(key);
|
|
20
|
+
setCookie(TOUR_COOKIE, finishedTours.toString(), { expires: defaultExpires.toUTCString() });
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Tutorial: verifies if the React Tour step has not finished yet.
|
|
24
|
+
*
|
|
25
|
+
* A step has not finished if the array stored as a cookie doesn't include the string value of `step.selector`.
|
|
26
|
+
* @param step the step config.
|
|
27
|
+
* @returns true if the step has not yet been marked as finished. False otherwise.
|
|
28
|
+
*/
|
|
29
|
+
export const isNewTourStep = (step) => !hasFinishedTourStep(`${step.selector}`);
|
|
30
|
+
/**
|
|
31
|
+
* Tutorial: verifies if the key passed as parameter refers to a React Tour step that has already finished.
|
|
32
|
+
*
|
|
33
|
+
* The key refers to a finished step if the array stored as a cookie includes it.
|
|
34
|
+
* If the cookie is set to 'disabled', then the step will be considered finished.Particularly useful in scenarios like e2e tests.
|
|
35
|
+
* @param key the step's identifier to check.
|
|
36
|
+
* @returns true if the key refers to a finished step. False otherwise.
|
|
37
|
+
*/
|
|
38
|
+
export const hasFinishedTourStep = (key) => {
|
|
39
|
+
const tourCookie = getTourCookie();
|
|
40
|
+
return tourCookie.includes(key) || tourCookie[0] === 'disabled';
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Tutorial: utility for building a React Tour step. This already includes some default configuration for tours in Stackspot.
|
|
44
|
+
* @param options the options for building the step: {@link StackspotTourStep}.
|
|
45
|
+
* @returns the React Tour step.
|
|
46
|
+
*/
|
|
47
|
+
export const tourStepBuilder = ({ selector, position, title, content, style, customNavigation, ...rest }) => ({
|
|
48
|
+
selector,
|
|
49
|
+
content: (_jsx(StepContainer, { stepKey: selector, position: position, title: title, customNavigation: customNavigation, children: content })),
|
|
50
|
+
position,
|
|
51
|
+
style: {
|
|
52
|
+
backgroundColor: theme.color.inverse[500],
|
|
53
|
+
width: '256px',
|
|
54
|
+
padding: 0,
|
|
55
|
+
top: ['right', 'left'].includes(position) ? '-3px' : '0',
|
|
56
|
+
...(style || {}),
|
|
57
|
+
},
|
|
58
|
+
...(rest || {}),
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/components/tour/utils.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAGhD,OAAO,EAAyB,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAGtE,MAAM,WAAW,GAAG,oBAAoB,CAAA;AAExC,MAAM,cAAc,GAAG,IAAI,IAAI,EAAE,CAAA;AACjC,cAAc,CAAC,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAA;AAExD,MAAM,aAAa,GAAG,GAAG,EAAE;IACzB,MAAM,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC,CAAA;IAChD,OAAO,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AAC9D,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,EAAE;IAC5C,MAAM,aAAa,GAAa,aAAa,EAAE,CAAA;IAC/C,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzD,SAAS,CAAC,WAAW,EAAE,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,cAAc,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AAC7F,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAkB,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;AAE7F;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAE,EAAE;IACjD,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,OAAO,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAA;AACjE,CAAC,CAAA;AAqBD;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,OAAO,EACP,KAAK,EACL,gBAAgB,EAChB,GAAG,IAAI,EACW,EAAgB,EAAE,CAAC,CAAC;IACtC,QAAQ;IACR,OAAO,EAAE,CAAC,KAAC,aAAa,IACtB,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,QAAiC,EAC3C,KAAK,EAAE,KAAK,EACZ,gBAAgB,EAAE,gBAAgB,YACjC,OAAO,GACM,CAAC;IACjB,QAAQ;IACR,KAAK,EAAE;QACL,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QACzC,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,CAAC;QACV,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAiC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;QACjF,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;KACjB;IACD,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;CAChB,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { PortalSwitcher } from './components/PortalSwitcher.js';
|
|
|
7
7
|
export { ActionItem, MenuContent, MenuGroup, Title } from './components/menu/MenuContent.js';
|
|
8
8
|
export { MenuSections } from './components/menu/MenuSections.js';
|
|
9
9
|
export * from './components/menu/types.js';
|
|
10
|
+
export * from './components/tour/index.js';
|
|
10
11
|
export * from './components/types.js';
|
|
11
12
|
export * from './elements.js';
|
|
12
13
|
export * from './errors.js';
|
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,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,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,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,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,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export { PortalSwitcher } from './components/PortalSwitcher.js';
|
|
|
7
7
|
export { ActionItem, MenuContent, MenuGroup, Title } from './components/menu/MenuContent.js';
|
|
8
8
|
export { MenuSections } from './components/menu/MenuSections.js';
|
|
9
9
|
export * from './components/menu/types.js';
|
|
10
|
+
export * from './components/tour/index.js';
|
|
10
11
|
export * from './components/types.js';
|
|
11
12
|
export * from './elements.js';
|
|
12
13
|
export * from './errors.js';
|
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,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,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,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,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,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA"}
|
package/dist/layout.css
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stack-spot/portal-layout",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "rimraf dist && tsc && tsc-esm-fix --target='dist' && cpy src/layout.css dist --flat",
|
|
9
|
-
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
|
9
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
10
|
+
"check-tree-shaking": "agadoo"
|
|
10
11
|
},
|
|
11
12
|
"peerDependencies": {
|
|
12
13
|
"@citric/core": "^6.0.0",
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
"@citric/ui": "^5.7.2 || ^6.0.0",
|
|
15
16
|
"@stack-spot/portal-theme": "^1.0.0",
|
|
16
17
|
"@stack-spot/portal-translate": "^1.0.0",
|
|
17
|
-
"@stack-spot/portal-components": "^
|
|
18
|
+
"@stack-spot/portal-components": "^2.0.0",
|
|
18
19
|
"react": "^18.2.0",
|
|
19
20
|
"react-dom": "^18.2.0",
|
|
20
21
|
"styled-components": "^6.1.10"
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
"@types/react-dom": "^18.2.15",
|
|
25
26
|
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
|
26
27
|
"@typescript-eslint/parser": "^6.10.0",
|
|
28
|
+
"@types/reactour": "^1.18.5",
|
|
27
29
|
"agadoo": "^3.0.0",
|
|
28
30
|
"cpy-cli": "^5.0.0",
|
|
29
31
|
"eslint": "^8.53.0",
|
|
@@ -42,6 +44,7 @@
|
|
|
42
44
|
"styled-components": "6.1.10"
|
|
43
45
|
},
|
|
44
46
|
"dependencies": {
|
|
45
|
-
"react-toastify": "^10.0.5"
|
|
47
|
+
"react-toastify": "^10.0.5",
|
|
48
|
+
"reactour": "^1.19.4"
|
|
46
49
|
}
|
|
47
50
|
}
|
package/readme.md
CHANGED
|
@@ -10,6 +10,7 @@ Implements the general layout for a Stackspot web application.
|
|
|
10
10
|
- Right panel: a floating panel that shows like a modal, but is fixed to the right side of the window.
|
|
11
11
|
- Bottom dialog: a floating fixed panel fixed to the bottom of the window.
|
|
12
12
|
- Toaster: a floating set of cards at the top right corner used to show notifications.
|
|
13
|
+
- Tour: component associated floating cards used to present new features to users.
|
|
13
14
|
|
|
14
15
|
The overlay components (modal, right panel, bottom dialog and toaster) are controlled imperatively through the overlay object. Example:
|
|
15
16
|
`overlay.showModal(options)`.
|
|
@@ -57,6 +58,7 @@ const MyApp = () => {
|
|
|
57
58
|
}
|
|
58
59
|
```
|
|
59
60
|
|
|
61
|
+
|
|
60
62
|
The Header and Menu in a layout are highly customizable. Check the code documentation for more details!
|
|
61
63
|
|
|
62
64
|
## Modal and right panel pitfalls
|
package/src/Layout.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { TourProps, TourProvider, defaultTourConfig, isNewTourStep } from '@stack-spot/portal-components/Tour'
|
|
2
1
|
import { CSSToCitricAdapter, WithStyle, listToClass } from '@stack-spot/portal-theme'
|
|
3
2
|
import '@stack-spot/portal-theme/dist/theme.css'
|
|
4
3
|
import { ReactElement, ReactNode, useEffect } from 'react'
|
|
5
4
|
import { overlay } from './LayoutOverlayManager'
|
|
5
|
+
import { WelcomeTour } from './WelcomeTour'
|
|
6
6
|
import { Header, HeaderProps } from './components/Header'
|
|
7
7
|
import { Toaster } from './components/Toaster'
|
|
8
8
|
import { ErrorBoundary } from './components/error/ErrorBoundary'
|
|
@@ -11,7 +11,6 @@ import { SilentErrorBoundary } from './components/error/SilentErrorBoundary'
|
|
|
11
11
|
import { MenuContent } from './components/menu/MenuContent'
|
|
12
12
|
import { MenuSections } from './components/menu/MenuSections'
|
|
13
13
|
import { MenuProps } from './components/menu/types'
|
|
14
|
-
import { usePortalSwitcherStep } from './components/tour/PortalSwitcherStep'
|
|
15
14
|
import { elementIds, getLayoutElements } from './elements'
|
|
16
15
|
import './layout.css'
|
|
17
16
|
|
|
@@ -40,10 +39,6 @@ interface Props extends WithStyle {
|
|
|
40
39
|
* A function to run whenever an error is catch by an error boundary.
|
|
41
40
|
*/
|
|
42
41
|
onError?: ErrorHandler,
|
|
43
|
-
/**
|
|
44
|
-
* The options for the React Tour's tutorial.
|
|
45
|
-
*/
|
|
46
|
-
tourProps?: TourProps,
|
|
47
42
|
}
|
|
48
43
|
|
|
49
44
|
interface RawProps extends WithStyle {
|
|
@@ -75,10 +70,6 @@ interface RawProps extends WithStyle {
|
|
|
75
70
|
* A function to run whenever an error is catch by an error boundary.
|
|
76
71
|
*/
|
|
77
72
|
onError?: ErrorHandler,
|
|
78
|
-
/**
|
|
79
|
-
* The options for the React Tour's tutorial.
|
|
80
|
-
*/
|
|
81
|
-
tourProps?: TourProps,
|
|
82
73
|
}
|
|
83
74
|
|
|
84
75
|
/**
|
|
@@ -86,7 +77,7 @@ interface RawProps extends WithStyle {
|
|
|
86
77
|
* @param props the component's props {@link RawProps}.
|
|
87
78
|
*/
|
|
88
79
|
export const RawLayout = (
|
|
89
|
-
{ menuSections, menuContent, header, children,
|
|
80
|
+
{ menuSections, menuContent, header, children,
|
|
90
81
|
extra, errorDescriptor, onError, className, style }:
|
|
91
82
|
RawProps,
|
|
92
83
|
) => {
|
|
@@ -94,7 +85,6 @@ export const RawLayout = (
|
|
|
94
85
|
const { bottomDialog, modal, rightPanel } = overlay.useOverlays()
|
|
95
86
|
const { layout } = getLayoutElements()
|
|
96
87
|
const isCompactedOnlyIcons = layout?.classList.contains('menu-compact')
|
|
97
|
-
const portalSwitcherStep = usePortalSwitcherStep()
|
|
98
88
|
|
|
99
89
|
const classes = [
|
|
100
90
|
menuContent && !isCompactedOnlyIcons ? 'menu-content-visible' : undefined,
|
|
@@ -103,12 +93,6 @@ export const RawLayout = (
|
|
|
103
93
|
isCompactedOnlyIcons ? 'menu-compact' : undefined,
|
|
104
94
|
]
|
|
105
95
|
|
|
106
|
-
const tourPropsWithDefaults = { ...defaultTourConfig, ...(tourProps || {}) }
|
|
107
|
-
tourPropsWithDefaults.steps = [
|
|
108
|
-
portalSwitcherStep,
|
|
109
|
-
...tourPropsWithDefaults.steps,
|
|
110
|
-
].filter(isNewTourStep)
|
|
111
|
-
|
|
112
96
|
useEffect(() => {
|
|
113
97
|
if (errorDescriptor) ErrorManager.setDescriptionFunction(errorDescriptor)
|
|
114
98
|
if (onError) ErrorManager.setErrorHandler(onError)
|
|
@@ -116,28 +100,27 @@ export const RawLayout = (
|
|
|
116
100
|
|
|
117
101
|
return (
|
|
118
102
|
<CSSToCitricAdapter>
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
</div>
|
|
103
|
+
<WelcomeTour />
|
|
104
|
+
<div id={elementIds.layout} className={listToClass(classes)} style={style}>
|
|
105
|
+
{header && <header id={elementIds.header}><SilentErrorBoundary>{header}</SilentErrorBoundary></header>}
|
|
106
|
+
{extra && <SilentErrorBoundary>{extra}</SilentErrorBoundary>}
|
|
107
|
+
<aside id={elementIds.menu}>
|
|
108
|
+
<nav role="menubar" id={elementIds.menuContent}><SilentErrorBoundary>{menuContent}</SilentErrorBoundary></nav>
|
|
109
|
+
{menuSections &&
|
|
110
|
+
<nav role="menubar" id={elementIds.menuSections}><SilentErrorBoundary>{menuSections}</SilentErrorBoundary></nav>}
|
|
111
|
+
</aside>
|
|
112
|
+
{children && <div id={elementIds.page}>
|
|
113
|
+
<article id={elementIds.content}><ErrorBoundary>{children}</ErrorBoundary></article>
|
|
114
|
+
</div>}
|
|
115
|
+
<div id={elementIds.bottomDialog} role="dialog"><ErrorBoundary>{bottomDialog}</ErrorBoundary></div>
|
|
116
|
+
<div id={elementIds.backdrop}>
|
|
117
|
+
<div id={elementIds.rightPanel} aria-modal role="dialog"><ErrorBoundary>{rightPanel}</ErrorBoundary></div>
|
|
118
|
+
<div id={elementIds.modal} aria-modal role="dialog"><ErrorBoundary>{modal}</ErrorBoundary></div>
|
|
119
|
+
</div>
|
|
120
|
+
<Toaster />
|
|
121
|
+
<div id={elementIds.accessibilityAnnouncer} aria-atomic aria-live="assertive">
|
|
139
122
|
</div>
|
|
140
|
-
</
|
|
123
|
+
</div>
|
|
141
124
|
</CSSToCitricAdapter>
|
|
142
125
|
)
|
|
143
126
|
}
|
|
@@ -151,7 +134,7 @@ const MenuContentRenderer = ({ content }: Required<Pick<Props['menu'], 'content'
|
|
|
151
134
|
* Renders the layout with a menu and header that follow the config objects passed as parameter.
|
|
152
135
|
* @param props the component's props {@link Props}.
|
|
153
136
|
*/
|
|
154
|
-
export const Layout = ({ menu, header, children, extra, errorDescriptor, onError, className, style
|
|
137
|
+
export const Layout = ({ menu, header, children, extra, errorDescriptor, onError, className, style }: Props) => (
|
|
155
138
|
<RawLayout
|
|
156
139
|
header={<Header {...header} />}
|
|
157
140
|
menuSections={menu.sections ? <MenuSections {...menu} /> : undefined}
|
|
@@ -164,7 +147,6 @@ export const Layout = ({ menu, header, children, extra, errorDescriptor, onError
|
|
|
164
147
|
extra={extra}
|
|
165
148
|
className={className}
|
|
166
149
|
style={style}
|
|
167
|
-
tourProps={tourProps}
|
|
168
150
|
>
|
|
169
151
|
{children}
|
|
170
152
|
</RawLayout>
|
|
@@ -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
|
+
}
|
|
@@ -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 } from '@stack-spot/portal-components/
|
|
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'
|