@yourdash/uikit 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/components/box/box.module.scss +1 -1
- package/components/box/box.tsx +3 -3
- package/components/button/button.module.scss +3 -3
- package/components/button/button.tsx +2 -1
- package/components/buttonLink/buttonLink.module.scss +5 -1
- package/components/buttonLink/buttonLink.tsx +13 -12
- package/components/buttonWithIcon/buttonWithIcon.module.scss +56 -0
- package/components/buttonWithIcon/buttonWithIcon.tsx +36 -0
- package/components/card/card.module.scss +6 -6
- package/components/card/card.tsx +23 -20
- package/components/container/container.module.scss +20 -0
- package/components/container/container.tsx +22 -0
- package/components/contextMenu/contextMenu.tsx +1 -1
- package/components/contextMenu/contextMenuRoot.module.scss +1 -1
- package/components/contextMenu/contextMenuRoot.tsx +83 -83
- package/components/flex/flex.module.scss +31 -19
- package/components/flex/flex.tsx +23 -2
- package/components/heading/heading.module.scss +1 -1
- package/components/heading/heading.tsx +1 -1
- package/components/icon/icon.tsx +1 -1
- package/components/iconButton/iconButton.module.scss +1 -1
- package/components/iconButton/iconButton.tsx +3 -3
- package/components/image/image.module.scss +72 -1
- package/components/image/image.tsx +65 -10
- package/components/link/link.module.scss +1 -1
- package/components/link/link.tsx +1 -1
- package/components/progressBar/progressBar.module.scss +25 -0
- package/components/progressBar/progressBar.tsx +21 -0
- package/components/redirect/redirect.tsx +1 -1
- package/components/separator/separator.module.scss +9 -4
- package/components/separator/separator.tsx +3 -3
- package/components/spinner/spinner.module.scss +1 -6
- package/components/spinner/spinner.tsx +1 -1
- package/components/subtext/subtext.module.scss +1 -1
- package/components/subtext/subtext.tsx +1 -1
- package/components/tag/tag.module.scss +13 -0
- package/components/tag/tag.tsx +21 -0
- package/components/text/text.module.scss +1 -1
- package/components/text/text.tsx +1 -1
- package/components/textButton/textButton.module.scss +1 -1
- package/components/textButton/textButton.tsx +1 -1
- package/components/textInput/textInput.module.scss +1 -1
- package/components/textInput/textInput.tsx +40 -10
- package/components/toast/toast.module.scss +71 -31
- package/components/toast/toast.ts +12 -0
- package/components/toast/toastAction.ts +12 -0
- package/components/toast/toastContext.ts +5 -3
- package/components/toast/toasts.tsx +99 -0
- package/core/decrementLevel.tsx +13 -13
- package/core/incrementLevel.tsx +1 -1
- package/core/level.tsx +1 -1
- package/core/remToPx.ts +8 -0
- package/core/root.tsx +26 -32
- package/core/toast.ts +18 -17
- package/imports.d.ts +81 -0
- package/package.json +9 -40
- package/theme/defaultTheme.module.scss +16 -4
- package/theme/themeValues.scss +8 -5
- package/tsconfig.json +19 -9
- package/utilityComponent/hasBeenShown/hasBeenShown.tsx +47 -0
- package/utilityComponent/onInView/onInView.tsx +83 -0
- package/views/carousel/carousel.module.scss +77 -0
- package/views/carousel/carousel.tsx +138 -0
- package/views/header/header.module.scss +16 -0
- package/views/header/header.tsx +28 -0
- package/views/infiniteScroll/infiniteScroll.module.scss +26 -0
- package/views/infiniteScroll/infiniteScroll.tsx +90 -0
- package/views/navBar/components/navImage/navImage.module.scss +7 -0
- package/views/navBar/components/navImage/navImage.tsx +15 -0
- package/views/navBar/components/navTitle/navTitle.tsx +13 -0
- package/views/navBar/navBar.module.scss +22 -0
- package/views/navBar/navBar.tsx +37 -0
- package/views/onBoarding/onBoarding.module.scss +84 -0
- package/views/onBoarding/onBoarding.tsx +138 -0
- package/views/panAndZoom/panAndZoom.tsx +121 -114
- package/views/sidebar/Sidebar.module.scss +49 -0
- package/views/sidebar/Sidebar.tsx +30 -0
- package/views/sidebar/SidebarContainer.module.scss +22 -0
- package/views/sidebar/SidebarContainer.tsx +38 -0
- package/views/sidebar/SidebarContext.tsx +15 -0
- package/views/sidebar/SidebarToggleButton.tsx +25 -0
- package/components/toast/toast.tsx +0 -65
@@ -0,0 +1,77 @@
|
|
1
|
+
@use "@yourdash/uikit/theme/themeValues" as *;
|
2
|
+
|
3
|
+
.containerComponent {
|
4
|
+
display: flex;
|
5
|
+
flex-direction: row;
|
6
|
+
max-width: 100%;
|
7
|
+
height: 24rem;
|
8
|
+
position: relative;
|
9
|
+
padding: 0;
|
10
|
+
overflow: hidden;
|
11
|
+
}
|
12
|
+
|
13
|
+
.component {
|
14
|
+
display: flex;
|
15
|
+
align-items: center;
|
16
|
+
max-width: 100%;
|
17
|
+
height: 24rem;
|
18
|
+
gap: 0.5rem;
|
19
|
+
padding: var(#{$theme+$padding});
|
20
|
+
flex-direction: row;
|
21
|
+
overflow-x: auto;
|
22
|
+
scroll-snap-type: x mandatory;
|
23
|
+
scroll-snap-stop: always;
|
24
|
+
scrollbar-width: none;
|
25
|
+
padding-bottom: 2.5rem;
|
26
|
+
|
27
|
+
&::-webkit-scrollbar {
|
28
|
+
display: none;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
.page {
|
33
|
+
display: flex;
|
34
|
+
width: 80%;
|
35
|
+
height: 100%;
|
36
|
+
flex-shrink: 0;
|
37
|
+
scroll-snap-align: center;
|
38
|
+
|
39
|
+
&:first-of-type {
|
40
|
+
margin-left: calc(20% + var(#{$theme+$gap}));
|
41
|
+
}
|
42
|
+
|
43
|
+
&:last-of-type {
|
44
|
+
margin-right: calc(20% + var(#{$theme+$gap}));
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
.controls {
|
49
|
+
position: absolute;
|
50
|
+
bottom: 0;
|
51
|
+
left: 50%;
|
52
|
+
transform: translateX(-50%);
|
53
|
+
display: flex;
|
54
|
+
flex-direction: row;
|
55
|
+
gap: var(#{$theme+$gap});
|
56
|
+
}
|
57
|
+
|
58
|
+
.indicator {
|
59
|
+
display: flex;
|
60
|
+
flex-direction: row;
|
61
|
+
gap: var(#{$theme+$gap});
|
62
|
+
padding: calc(var(#{$theme+$padding}) / 2);
|
63
|
+
border-radius: var(#{$theme+$radius});
|
64
|
+
|
65
|
+
.pageIndicator {
|
66
|
+
background-color: var(#{$theme+$color});
|
67
|
+
padding: 0.5rem;
|
68
|
+
border-radius: var(#{$theme+$radius});
|
69
|
+
transition: var(#{$theme+$transition});
|
70
|
+
position: relative;
|
71
|
+
|
72
|
+
&.selected {
|
73
|
+
padding-right: 1.5rem;
|
74
|
+
padding-left: 1.5rem;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
import page from "@yourdash/web/src/deprecatedLogin/Page.tsx";
|
2
|
+
import React, { useEffect, useRef, useState } from "react";
|
3
|
+
import Card from "../../components/card/card.tsx";
|
4
|
+
import Container from "../../components/container/container.tsx";
|
5
|
+
import { UKIcon } from "../../components/icon/iconDictionary.ts";
|
6
|
+
import IconButton from "../../components/iconButton/iconButton.tsx";
|
7
|
+
import styles from "./carousel.module.scss";
|
8
|
+
import clippy from "@yourdash/shared/web/helpers/clippy.ts";
|
9
|
+
|
10
|
+
const Carousel: React.FC<{
|
11
|
+
items: { element: React.ReactElement; id: string }[];
|
12
|
+
className?: string;
|
13
|
+
}> = ({ items, className }) => {
|
14
|
+
const scrollRef = useRef<HTMLDivElement>(null);
|
15
|
+
const [currentPage, setCurrentPage] = useState<number>(0);
|
16
|
+
|
17
|
+
useEffect(() => {
|
18
|
+
const scrollElement = scrollRef.current;
|
19
|
+
|
20
|
+
if (!scrollElement) return;
|
21
|
+
|
22
|
+
console.log(Array.from(scrollElement.children));
|
23
|
+
|
24
|
+
let timer: Timer;
|
25
|
+
let listener = () => {
|
26
|
+
clearTimeout(timer);
|
27
|
+
timer = setTimeout(function () {
|
28
|
+
Array.from(scrollElement.children).forEach((ele: Element, index: number) => {
|
29
|
+
if (
|
30
|
+
Math.abs(
|
31
|
+
ele.getBoundingClientRect().left +
|
32
|
+
ele.getBoundingClientRect().width / 2 -
|
33
|
+
(scrollElement.getBoundingClientRect().left + scrollElement.getBoundingClientRect().width / 2),
|
34
|
+
) <
|
35
|
+
ele.getBoundingClientRect().width / 2
|
36
|
+
) {
|
37
|
+
setCurrentPage(index);
|
38
|
+
return;
|
39
|
+
}
|
40
|
+
});
|
41
|
+
}, 25);
|
42
|
+
};
|
43
|
+
|
44
|
+
scrollElement.addEventListener("scroll", listener);
|
45
|
+
|
46
|
+
return () => {
|
47
|
+
scrollElement.removeEventListener("scroll", listener);
|
48
|
+
clearTimeout(timer);
|
49
|
+
};
|
50
|
+
}, []);
|
51
|
+
|
52
|
+
return (
|
53
|
+
<Container className={clippy(styles.containerComponent, className)}>
|
54
|
+
<div
|
55
|
+
className={styles.component}
|
56
|
+
ref={scrollRef}
|
57
|
+
>
|
58
|
+
{items.map((child) => {
|
59
|
+
return (
|
60
|
+
<div
|
61
|
+
key={child.id}
|
62
|
+
className={styles.page}
|
63
|
+
>
|
64
|
+
{child.element}
|
65
|
+
</div>
|
66
|
+
);
|
67
|
+
})}
|
68
|
+
</div>
|
69
|
+
<div className={styles.controls}>
|
70
|
+
<IconButton
|
71
|
+
accessibleLabel={"previous page"}
|
72
|
+
icon={UKIcon.ChevronLeft}
|
73
|
+
className={styles.pageControl}
|
74
|
+
onClick={() => {
|
75
|
+
const scrollElement = scrollRef.current;
|
76
|
+
|
77
|
+
if (!scrollElement) {
|
78
|
+
return;
|
79
|
+
}
|
80
|
+
|
81
|
+
const carouselTargetPage = scrollElement.children[currentPage - 1] as HTMLDivElement;
|
82
|
+
|
83
|
+
if (!carouselTargetPage) {
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
|
87
|
+
carouselTargetPage.scrollIntoView({ behavior: "smooth" });
|
88
|
+
}}
|
89
|
+
/>
|
90
|
+
<Card className={styles.indicator}>
|
91
|
+
{items.map((page, index) => {
|
92
|
+
return (
|
93
|
+
<button
|
94
|
+
key={page.id}
|
95
|
+
className={clippy(styles.pageIndicator, index === currentPage && styles.selected)}
|
96
|
+
onClick={() => {
|
97
|
+
const scrollElement = scrollRef.current;
|
98
|
+
|
99
|
+
if (!scrollElement) {
|
100
|
+
return;
|
101
|
+
}
|
102
|
+
|
103
|
+
scrollElement.scrollIntoView({ behavior: "smooth" });
|
104
|
+
|
105
|
+
const carouselTargetPage = scrollElement.children[index] as HTMLDivElement;
|
106
|
+
|
107
|
+
carouselTargetPage.scrollIntoView({ behavior: "smooth" });
|
108
|
+
}}
|
109
|
+
/>
|
110
|
+
);
|
111
|
+
})}
|
112
|
+
</Card>
|
113
|
+
<IconButton
|
114
|
+
accessibleLabel={"next page"}
|
115
|
+
icon={UKIcon.ChevronRight}
|
116
|
+
className={styles.pageControl}
|
117
|
+
onClick={() => {
|
118
|
+
const scrollElement = scrollRef.current;
|
119
|
+
|
120
|
+
if (!scrollElement) {
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
|
124
|
+
const carouselTargetPage = scrollElement.children[currentPage + 1] as HTMLDivElement;
|
125
|
+
|
126
|
+
if (!carouselTargetPage) {
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
|
130
|
+
carouselTargetPage.scrollIntoView({ behavior: "smooth" });
|
131
|
+
}}
|
132
|
+
/>
|
133
|
+
</div>
|
134
|
+
</Container>
|
135
|
+
);
|
136
|
+
};
|
137
|
+
|
138
|
+
export default Carousel;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/*!
|
2
|
+
* Copyright ©2024 Ewsgit <https://ewsgit.uk> and YourDash <https://yourdash.ewsgit.uk> contributors.
|
3
|
+
* YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
|
4
|
+
*/
|
5
|
+
|
6
|
+
@use "@yourdash/uikit/theme/themeValues" as *;
|
7
|
+
|
8
|
+
.view {
|
9
|
+
width: 100%;
|
10
|
+
display: flex;
|
11
|
+
align-items: center;
|
12
|
+
justify-content: center;
|
13
|
+
padding: var(#{$theme+$padding});
|
14
|
+
padding-top: calc(var(#{$theme+$padding}) * 4);
|
15
|
+
padding-bottom: calc(var(#{$theme+$padding}) * 4);
|
16
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright ©2024 Ewsgit <https://ewsgit.uk> and YourDash <https://yourdash.ewsgit.uk> contributors.
|
3
|
+
* YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React from "react";
|
7
|
+
import Heading from "../../components/heading/heading.tsx";
|
8
|
+
import styles from "./header.module.scss";
|
9
|
+
|
10
|
+
const Header: React.FC<{ backgroundImage?: string; heading: string }> = ({ backgroundImage, heading }) => {
|
11
|
+
return (
|
12
|
+
<>
|
13
|
+
<div
|
14
|
+
className={styles.view}
|
15
|
+
style={
|
16
|
+
backgroundImage ? { backgroundImage: backgroundImage } : { backgroundImage: "linear-gradient(-45deg, #ff8093aa, #ffd264aa)" }
|
17
|
+
}
|
18
|
+
>
|
19
|
+
<Heading
|
20
|
+
level={1}
|
21
|
+
text={heading}
|
22
|
+
/>
|
23
|
+
</div>
|
24
|
+
</>
|
25
|
+
);
|
26
|
+
};
|
27
|
+
|
28
|
+
export default Header;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
/*!
|
2
|
+
* Copyright ©2024 Ewsgit<https://ewsgit.uk> and YourDash<https://yourdash.ewsgit.uk> contributors.
|
3
|
+
* YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
|
4
|
+
*/
|
5
|
+
|
6
|
+
@use "@yourdash/uikit/theme/themeValues" as *;
|
7
|
+
|
8
|
+
.component {
|
9
|
+
display: flex;
|
10
|
+
flex-direction: column;
|
11
|
+
width: 100%;
|
12
|
+
height: 100%;
|
13
|
+
gap: 1rem;
|
14
|
+
align-items: center;
|
15
|
+
}
|
16
|
+
|
17
|
+
.items {
|
18
|
+
height: 100%;
|
19
|
+
}
|
20
|
+
|
21
|
+
.endOfItems {
|
22
|
+
text-align: center;
|
23
|
+
padding: var(#{$theme+$padding});
|
24
|
+
gap: var(#{$theme+$gap});
|
25
|
+
width: calc(100% - calc(var(#{$theme+$padding}) * 2));
|
26
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright ©2024 Ewsgit<https://ewsgit.uk> and YourDash<https://yourdash.ewsgit.uk> contributors.
|
3
|
+
* YourDash is licensed under the MIT License. (https://mit.ewsgit.uk)
|
4
|
+
*/
|
5
|
+
|
6
|
+
import clippy from "@yourdash/shared/web/helpers/clippy.ts";
|
7
|
+
import React, { useEffect, useState } from "react";
|
8
|
+
import Heading from "../../components/heading/heading.tsx";
|
9
|
+
import Separator from "../../components/separator/separator.tsx";
|
10
|
+
import Text from "../../components/text/text.tsx";
|
11
|
+
import styles from "./infiniteScroll.module.scss";
|
12
|
+
|
13
|
+
const InfiniteScroll: React.FC<{
|
14
|
+
children: React.ReactNode | React.ReactNode[];
|
15
|
+
fetchNextPage: (nextPageNumber: number) => Promise<{ hasAnotherPage?: boolean }>;
|
16
|
+
containerClassName?: string;
|
17
|
+
className?: string;
|
18
|
+
resetState?: string;
|
19
|
+
}> = ({ children, fetchNextPage, containerClassName, className, resetState }) => {
|
20
|
+
const endOfItemsRef = React.useRef<HTMLDivElement>(null);
|
21
|
+
const lastFetchedPage = React.useRef<number>(-1);
|
22
|
+
const [isLoading, setIsLoading] = useState<boolean>(false);
|
23
|
+
const [isLastPage, setIsLastPage] = useState<boolean>(false);
|
24
|
+
|
25
|
+
useEffect(() => {
|
26
|
+
lastFetchedPage.current = -1;
|
27
|
+
setIsLoading(false);
|
28
|
+
setIsLastPage(false);
|
29
|
+
fetchNextPageWrapper();
|
30
|
+
}, [resetState]);
|
31
|
+
|
32
|
+
async function fetchNextPageWrapper() {
|
33
|
+
if (isLoading) return;
|
34
|
+
setIsLoading(true);
|
35
|
+
const { hasAnotherPage } = await fetchNextPage(lastFetchedPage.current + 1);
|
36
|
+
lastFetchedPage.current++;
|
37
|
+
setIsLoading(false);
|
38
|
+
setIsLastPage(hasAnotherPage || false);
|
39
|
+
}
|
40
|
+
|
41
|
+
useEffect(() => {
|
42
|
+
if (!endOfItemsRef.current) return;
|
43
|
+
|
44
|
+
const element: HTMLDivElement = endOfItemsRef.current;
|
45
|
+
|
46
|
+
const observer = new IntersectionObserver((elem) => {
|
47
|
+
console.log("observer update");
|
48
|
+
const isVisible = elem[0].isIntersecting;
|
49
|
+
|
50
|
+
if (isVisible) fetchNextPageWrapper();
|
51
|
+
});
|
52
|
+
|
53
|
+
observer.observe(element);
|
54
|
+
}, []);
|
55
|
+
|
56
|
+
// TODO: Use interaction observer to detect when the last item is shown on the screen and fetch the next page
|
57
|
+
|
58
|
+
return (
|
59
|
+
<div className={clippy(containerClassName, styles.component)}>
|
60
|
+
{/* @ts-ignore */}
|
61
|
+
{children?.length > 0 ? (
|
62
|
+
<div className={clippy(className, styles.items)}>{children}</div>
|
63
|
+
) : (
|
64
|
+
<div className={"text-center"}>
|
65
|
+
<Heading
|
66
|
+
level={1}
|
67
|
+
text={"Whoops."}
|
68
|
+
/>
|
69
|
+
<Separator direction={"column"} />
|
70
|
+
<Text text={"It looks like nothing could be found..."} />
|
71
|
+
</div>
|
72
|
+
)}
|
73
|
+
<div
|
74
|
+
ref={endOfItemsRef}
|
75
|
+
className={styles.endOfItems}
|
76
|
+
>
|
77
|
+
{isLoading && <Text text={"Loading more content"} />}
|
78
|
+
<Separator direction={"column"} />
|
79
|
+
{isLastPage && (
|
80
|
+
<Text
|
81
|
+
text={"No more items to load"}
|
82
|
+
className={styles.endOfItems}
|
83
|
+
/>
|
84
|
+
)}
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
);
|
88
|
+
};
|
89
|
+
|
90
|
+
export default InfiniteScroll;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import Image from "../../../../components/image/image.tsx";
|
3
|
+
import styles from "./navImage.module.scss";
|
4
|
+
|
5
|
+
const NavImage: React.FC<{ src: string }> = ({ src }) => {
|
6
|
+
return (
|
7
|
+
<Image
|
8
|
+
accessibleLabel=""
|
9
|
+
src={src}
|
10
|
+
className={styles.component}
|
11
|
+
/>
|
12
|
+
);
|
13
|
+
};
|
14
|
+
|
15
|
+
export default NavImage;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import Heading from "../../../../components/heading/heading.tsx";
|
3
|
+
|
4
|
+
const NavTitle: React.FC<{ title: string }> = ({ title }) => {
|
5
|
+
return (
|
6
|
+
<Heading
|
7
|
+
text={title}
|
8
|
+
level={2}
|
9
|
+
/>
|
10
|
+
);
|
11
|
+
};
|
12
|
+
|
13
|
+
export default NavTitle;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
@use "@yourdash/uikit/theme/themeValues" as *;
|
2
|
+
|
3
|
+
.component {
|
4
|
+
--nav-height: calc(2rem + var(#{$theme+$padding}));
|
5
|
+
|
6
|
+
width: 100%;
|
7
|
+
height: calc(var(--nav-height) + calc(var(#{$theme+$padding}) * 2));
|
8
|
+
border-top: 0;
|
9
|
+
border-left: 0;
|
10
|
+
border-right: 0;
|
11
|
+
padding: var(#{$theme+$padding});
|
12
|
+
display: grid;
|
13
|
+
grid-template-columns: auto 1fr auto;
|
14
|
+
justify-content: center;
|
15
|
+
align-items: center;
|
16
|
+
}
|
17
|
+
|
18
|
+
.segment {
|
19
|
+
display: flex;
|
20
|
+
align-items: center;
|
21
|
+
justify-content: center;
|
22
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import Box from "../../components/box/box.tsx";
|
3
|
+
import styles from "./navBar.module.scss";
|
4
|
+
import Flex from "../../components/flex/flex.tsx";
|
5
|
+
import clippy from "@yourdash/shared/web/helpers/clippy.ts";
|
6
|
+
|
7
|
+
const NavBar: React.FC<{
|
8
|
+
leftSection?: React.ReactElement | React.ReactElement[];
|
9
|
+
centerSection?: React.ReactElement | React.ReactElement[];
|
10
|
+
rightSection?: React.ReactElement | React.ReactElement[];
|
11
|
+
className?: string;
|
12
|
+
}> = ({ leftSection, centerSection, rightSection, className }) => {
|
13
|
+
return (
|
14
|
+
<Box className={clippy(styles.component, className)}>
|
15
|
+
<Flex
|
16
|
+
className={styles.segment}
|
17
|
+
direction="row"
|
18
|
+
>
|
19
|
+
{leftSection}
|
20
|
+
</Flex>
|
21
|
+
<Flex
|
22
|
+
className={styles.segment}
|
23
|
+
direction="row"
|
24
|
+
>
|
25
|
+
{centerSection}
|
26
|
+
</Flex>
|
27
|
+
<Flex
|
28
|
+
className={styles.segment}
|
29
|
+
direction="row"
|
30
|
+
>
|
31
|
+
{rightSection}
|
32
|
+
</Flex>
|
33
|
+
</Box>
|
34
|
+
);
|
35
|
+
};
|
36
|
+
|
37
|
+
export default NavBar;
|
@@ -0,0 +1,84 @@
|
|
1
|
+
@use "@yourdash/uikit/theme/themeValues" as *;
|
2
|
+
|
3
|
+
.page {
|
4
|
+
display: flex;
|
5
|
+
align-items: center;
|
6
|
+
justify-content: center;
|
7
|
+
flex-direction: column;
|
8
|
+
width: 100%;
|
9
|
+
height: 100%;
|
10
|
+
position: relative;
|
11
|
+
animation: fadeIn 1s 0s cubic-bezier(0.215, 0.610, 0.355, 1);
|
12
|
+
|
13
|
+
&::before {
|
14
|
+
content: "";
|
15
|
+
//noinspection CssUnknownTarget
|
16
|
+
background-image: url("/assets/productLogos/yourdash.svg");
|
17
|
+
background-size: 20rem;
|
18
|
+
background-repeat: repeat;
|
19
|
+
width: 1000rem;
|
20
|
+
height: 1000rem;
|
21
|
+
position: absolute;
|
22
|
+
filter: blur(0.25rem) grayscale(1);
|
23
|
+
opacity: 0.1;
|
24
|
+
transform: rotate(-45deg);
|
25
|
+
z-index: -1;
|
26
|
+
}
|
27
|
+
|
28
|
+
@keyframes fadeIn {
|
29
|
+
from {
|
30
|
+
transform: translateY(2.5rem);
|
31
|
+
opacity: 0;
|
32
|
+
}
|
33
|
+
to {
|
34
|
+
transform: translateY(0);
|
35
|
+
opacity: 1;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
.card {
|
41
|
+
display: flex;
|
42
|
+
align-items: center;
|
43
|
+
justify-content: center;
|
44
|
+
flex-direction: column;
|
45
|
+
gap: calc(var(#{$theme+$gap}) * 2);
|
46
|
+
padding: 2rem;
|
47
|
+
position: relative;
|
48
|
+
transition: var(--transition);
|
49
|
+
}
|
50
|
+
|
51
|
+
.cardContainer {
|
52
|
+
box-shadow: #00000088 0 0 4rem;
|
53
|
+
}
|
54
|
+
|
55
|
+
.goBackButton {
|
56
|
+
position: absolute;
|
57
|
+
top: var(#{$theme+$padding});
|
58
|
+
left: var(#{$theme+$padding});
|
59
|
+
}
|
60
|
+
|
61
|
+
.headerImage {
|
62
|
+
height: 16rem;
|
63
|
+
}
|
64
|
+
|
65
|
+
.header {
|
66
|
+
line-height: 1;
|
67
|
+
text-align: center;
|
68
|
+
}
|
69
|
+
|
70
|
+
.body {
|
71
|
+
text-align: center;
|
72
|
+
}
|
73
|
+
|
74
|
+
.actions {
|
75
|
+
}
|
76
|
+
|
77
|
+
.action {
|
78
|
+
}
|
79
|
+
|
80
|
+
.actionWithoutIcon {
|
81
|
+
}
|
82
|
+
|
83
|
+
.actionWithIcon {
|
84
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
import * as React from "react";
|
2
|
+
import Card from "../../components/card/card.tsx";
|
3
|
+
import { UKIcon } from "../../components/icon/iconDictionary.ts";
|
4
|
+
import IconButton from "../../components/iconButton/iconButton.tsx";
|
5
|
+
import Image from "../../components/image/image.tsx";
|
6
|
+
import Heading from "../../components/heading/heading.tsx";
|
7
|
+
import Text from "../../components/text/text.tsx";
|
8
|
+
import ButtonWithIcon from "../../components/buttonWithIcon/buttonWithIcon.tsx";
|
9
|
+
import Button from "../../components/button/button.tsx";
|
10
|
+
import { Outlet } from "react-router";
|
11
|
+
import styles from "./onBoarding.module.scss";
|
12
|
+
import Flex from "../../components/flex/flex.tsx";
|
13
|
+
import clippy from "@yourdash/shared/web/helpers/clippy.ts";
|
14
|
+
|
15
|
+
const OnBoarding: React.FC<{
|
16
|
+
meta: { id: string };
|
17
|
+
pages: {
|
18
|
+
headerImage: string;
|
19
|
+
header: string;
|
20
|
+
body: string;
|
21
|
+
actions: { label: string; icon?: UKIcon; onClick: () => void; changeTo?: "next" | "previous" | "remain" | "completed" }[];
|
22
|
+
allowGoBack?: boolean;
|
23
|
+
}[];
|
24
|
+
}> = ({ pages, meta }) => {
|
25
|
+
const [currentPage, setCurrentPage] = React.useState<number>(0);
|
26
|
+
const page = pages[currentPage];
|
27
|
+
|
28
|
+
if (localStorage.getItem(`yourdash-application-visited-${meta.id}`) || currentPage > pages.length - 1) {
|
29
|
+
localStorage.setItem(`yourdash-application-visited-${meta.id}`, "true");
|
30
|
+
|
31
|
+
return <Outlet />;
|
32
|
+
}
|
33
|
+
|
34
|
+
return (
|
35
|
+
<div className={styles.page}>
|
36
|
+
<Card
|
37
|
+
className={styles.card}
|
38
|
+
containerClassName={styles.cardContainer}
|
39
|
+
>
|
40
|
+
{page.allowGoBack && (
|
41
|
+
<IconButton
|
42
|
+
className={clippy(styles.goBackButton, "animate__animated animate__fadeInDown")}
|
43
|
+
accessibleLabel="Go back to the last page"
|
44
|
+
icon={UKIcon.ChevronLeft}
|
45
|
+
onClick={() => {
|
46
|
+
setCurrentPage(currentPage - 1);
|
47
|
+
}}
|
48
|
+
/>
|
49
|
+
)}
|
50
|
+
<Image
|
51
|
+
className={styles.headerImage}
|
52
|
+
src={page.headerImage}
|
53
|
+
accessibleLabel=""
|
54
|
+
/>
|
55
|
+
<Heading
|
56
|
+
className={styles.header}
|
57
|
+
text={page.header}
|
58
|
+
/>
|
59
|
+
<Text
|
60
|
+
className={styles.body}
|
61
|
+
text={page.body}
|
62
|
+
/>
|
63
|
+
<Flex
|
64
|
+
className={styles.actions}
|
65
|
+
direction="row"
|
66
|
+
>
|
67
|
+
{page.actions.map((action) => {
|
68
|
+
if (action.icon) {
|
69
|
+
return (
|
70
|
+
<>
|
71
|
+
<ButtonWithIcon
|
72
|
+
key={action.label}
|
73
|
+
className={clippy(styles.action, styles.actionWithIcon, "animate__animated animate__fadeInUp")}
|
74
|
+
text={action.label}
|
75
|
+
icon={action.icon}
|
76
|
+
onClick={() => {
|
77
|
+
action.onClick();
|
78
|
+
if (action.changeTo) {
|
79
|
+
switch (action.changeTo) {
|
80
|
+
case "next":
|
81
|
+
setCurrentPage(currentPage + 1);
|
82
|
+
break;
|
83
|
+
case "previous":
|
84
|
+
if (currentPage > 0) setCurrentPage(currentPage - 1);
|
85
|
+
break;
|
86
|
+
case "remain":
|
87
|
+
break;
|
88
|
+
case "completed":
|
89
|
+
setCurrentPage(pages.length + 1);
|
90
|
+
break;
|
91
|
+
default:
|
92
|
+
break;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}}
|
96
|
+
/>
|
97
|
+
</>
|
98
|
+
);
|
99
|
+
}
|
100
|
+
|
101
|
+
return (
|
102
|
+
<>
|
103
|
+
<Button
|
104
|
+
key={action.icon}
|
105
|
+
className={clippy(styles.action, styles.actionWithoutIcon, "animate__animated animate__fadeInUp")}
|
106
|
+
text={action.label}
|
107
|
+
onClick={() => {
|
108
|
+
action.onClick();
|
109
|
+
|
110
|
+
if (action.changeTo) {
|
111
|
+
switch (action.changeTo) {
|
112
|
+
case "next":
|
113
|
+
setCurrentPage(currentPage + 1);
|
114
|
+
break;
|
115
|
+
case "previous":
|
116
|
+
if (currentPage > 0) setCurrentPage(currentPage - 1);
|
117
|
+
break;
|
118
|
+
case "remain":
|
119
|
+
break;
|
120
|
+
case "completed":
|
121
|
+
setCurrentPage(pages.length + 1);
|
122
|
+
break;
|
123
|
+
default:
|
124
|
+
break;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}}
|
128
|
+
/>
|
129
|
+
</>
|
130
|
+
);
|
131
|
+
})}
|
132
|
+
</Flex>
|
133
|
+
</Card>
|
134
|
+
</div>
|
135
|
+
);
|
136
|
+
};
|
137
|
+
|
138
|
+
export default OnBoarding;
|