oddsgate-ds 1.0.2

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 (206) hide show
  1. package/. babelrc +3 -0
  2. package/.cache/storybook/default/dev-server/a5a8bf6e622aef57065c6498611f40c911543d7d-3920d97c51b8ad2521918fb1205babd22b0ed3d7 +1 -0
  3. package/.cache/storybook/default/dev-server/a5a8bf6e622aef57065c6498611f40c911543d7d-43fdebe5fc35e4e9fabee9a83c7faea931b05ea0 +1 -0
  4. package/.cache/storybook/default/dev-server/a5a8bf6e622aef57065c6498611f40c911543d7d-f086b87885981c04ce7a583ff90a49313de83de7 +1 -0
  5. package/.eslintrc.cjs +14 -0
  6. package/.storybook/main.ts +28 -0
  7. package/.storybook/preview.ts +22 -0
  8. package/README.md +30 -0
  9. package/package.json +63 -0
  10. package/public/assets/components/quotes.svg +3 -0
  11. package/public/assets/empty-state.svg +19 -0
  12. package/public/assets/placeholder.png +0 -0
  13. package/public/assets/video.mp4 +0 -0
  14. package/public/fonts/miewfont/miewfont.eot +0 -0
  15. package/public/fonts/miewfont/miewfont.svg +35 -0
  16. package/public/fonts/miewfont/miewfont.ttf +0 -0
  17. package/public/fonts/miewfont/miewfont.woff +0 -0
  18. package/src/components/atoms/Button/Button.component.tsx +48 -0
  19. package/src/components/atoms/Button/Button.interface.ts +29 -0
  20. package/src/components/atoms/Button/Button.stories.tsx +58 -0
  21. package/src/components/atoms/Button/Button.theme.ts +126 -0
  22. package/src/components/atoms/Button/index.ts +1 -0
  23. package/src/components/atoms/Chip/Chip.component.tsx +26 -0
  24. package/src/components/atoms/Chip/Chip.interface.ts +10 -0
  25. package/src/components/atoms/Chip/Chip.stories.tsx +34 -0
  26. package/src/components/atoms/Chip/Chip.theme.ts +47 -0
  27. package/src/components/atoms/Chip/index.ts +1 -0
  28. package/src/components/atoms/CloseButton/CloseButton.component.tsx +17 -0
  29. package/src/components/atoms/CloseButton/CloseButton.interface.ts +9 -0
  30. package/src/components/atoms/CloseButton/CloseButton.stories.tsx +24 -0
  31. package/src/components/atoms/CloseButton/CloseButton.theme.ts +66 -0
  32. package/src/components/atoms/CloseButton/index.ts +1 -0
  33. package/src/components/atoms/EmptyState/EmptyState.component.tsx +27 -0
  34. package/src/components/atoms/EmptyState/EmptyState.interface.ts +10 -0
  35. package/src/components/atoms/EmptyState/EmptyState.stories.tsx +34 -0
  36. package/src/components/atoms/EmptyState/EmptyState.theme.ts +27 -0
  37. package/src/components/atoms/EmptyState/index.ts +1 -0
  38. package/src/components/atoms/Flex/Flex.component.tsx +30 -0
  39. package/src/components/atoms/Flex/Flex.interface.ts +22 -0
  40. package/src/components/atoms/Flex/Flex.theme.ts +11 -0
  41. package/src/components/atoms/Flex/index.ts +1 -0
  42. package/src/components/atoms/FlexGrid/FlexGrid.component.tsx +61 -0
  43. package/src/components/atoms/FlexGrid/FlexGrid.interface.ts +55 -0
  44. package/src/components/atoms/FlexGrid/FlexGrid.stories.tsx +55 -0
  45. package/src/components/atoms/FlexGrid/FlexGrid.theme.ts +79 -0
  46. package/src/components/atoms/FlexGrid/index.ts +1 -0
  47. package/src/components/atoms/FormField/CheckRadioField/CheckRadioField.component.tsx +22 -0
  48. package/src/components/atoms/FormField/CheckRadioField/CheckRadioField.interface.tsx +6 -0
  49. package/src/components/atoms/FormField/CheckRadioField/CheckRadioField.theme.ts +126 -0
  50. package/src/components/atoms/FormField/CheckRadioField/index.ts +1 -0
  51. package/src/components/atoms/FormField/FormField.component.tsx +37 -0
  52. package/src/components/atoms/FormField/FormField.interface.ts +9 -0
  53. package/src/components/atoms/FormField/FormField.stories.tsx +499 -0
  54. package/src/components/atoms/FormField/FormField.theme.tsx +122 -0
  55. package/src/components/atoms/FormField/index.ts +1 -0
  56. package/src/components/atoms/Heading/Heading.component.tsx +17 -0
  57. package/src/components/atoms/Heading/Heading.interface.tsx +21 -0
  58. package/src/components/atoms/Heading/Heading.theme.ts +17 -0
  59. package/src/components/atoms/Heading/index.ts +1 -0
  60. package/src/components/atoms/Icon/Icon.component.tsx +19 -0
  61. package/src/components/atoms/Icon/Icon.interface.ts +8 -0
  62. package/src/components/atoms/Icon/Icon.stories.tsx +26 -0
  63. package/src/components/atoms/Icon/Icon.theme.ts +102 -0
  64. package/src/components/atoms/Icon/index.ts +1 -0
  65. package/src/components/atoms/ImageWrapper/ImageWrapper.component.tsx +42 -0
  66. package/src/components/atoms/ImageWrapper/ImageWrapper.interface.ts +16 -0
  67. package/src/components/atoms/ImageWrapper/ImageWrapper.stories.tsx +27 -0
  68. package/src/components/atoms/ImageWrapper/ImageWrapper.theme.ts +51 -0
  69. package/src/components/atoms/ImageWrapper/index.ts +1 -0
  70. package/src/components/atoms/Loader/Loader.component.tsx +26 -0
  71. package/src/components/atoms/Loader/Loader.interface.ts +10 -0
  72. package/src/components/atoms/Loader/Loader.stories.tsx +33 -0
  73. package/src/components/atoms/Loader/Loader.theme.ts +92 -0
  74. package/src/components/atoms/Loader/index.ts +1 -0
  75. package/src/components/atoms/Marquee/Marquee.component.tsx +130 -0
  76. package/src/components/atoms/Marquee/Marquee.interface.ts +8 -0
  77. package/src/components/atoms/Marquee/Marquee.stories.tsx +20 -0
  78. package/src/components/atoms/Marquee/Marquee.theme.ts +42 -0
  79. package/src/components/atoms/Marquee/index.ts +1 -0
  80. package/src/components/atoms/Quote/Quote.component.tsx +29 -0
  81. package/src/components/atoms/Quote/Quote.interface.ts +10 -0
  82. package/src/components/atoms/Quote/Quote.stories.tsx +25 -0
  83. package/src/components/atoms/Quote/Quote.theme.ts +26 -0
  84. package/src/components/atoms/Quote/index.ts +1 -0
  85. package/src/components/atoms/RichText/RichText.component.tsx +31 -0
  86. package/src/components/atoms/RichText/RichText.interface.ts +11 -0
  87. package/src/components/atoms/RichText/RichText.stories.tsx +73 -0
  88. package/src/components/atoms/RichText/RichText.theme.ts +32 -0
  89. package/src/components/atoms/RichText/index.ts +1 -0
  90. package/src/components/atoms/ScrollingNav/ScrollingNav.component.tsx +18 -0
  91. package/src/components/atoms/ScrollingNav/ScrollingNav.interface.ts +8 -0
  92. package/src/components/atoms/ScrollingNav/ScrollingNav.stories.tsx +44 -0
  93. package/src/components/atoms/ScrollingNav/ScrollingNav.theme.ts +55 -0
  94. package/src/components/atoms/ScrollingNav/index.ts +1 -0
  95. package/src/components/atoms/Separator/Separator.component.tsx +19 -0
  96. package/src/components/atoms/Separator/Separator.interface.tsx +9 -0
  97. package/src/components/atoms/Separator/Separator.stories.tsx +28 -0
  98. package/src/components/atoms/Separator/Separator.theme.ts +12 -0
  99. package/src/components/atoms/Separator/index.ts +1 -0
  100. package/src/components/atoms/SocialLinks/SocialLinks.component.tsx +35 -0
  101. package/src/components/atoms/SocialLinks/SocialLinks.interface.ts +8 -0
  102. package/src/components/atoms/SocialLinks/SocialLinks.stories.tsx +36 -0
  103. package/src/components/atoms/SocialLinks/SocialLinks.theme.ts +52 -0
  104. package/src/components/atoms/SocialLinks/index.ts +1 -0
  105. package/src/components/atoms/Spacer/Spacer.component.tsx +27 -0
  106. package/src/components/atoms/Spacer/Spacer.interface.ts +11 -0
  107. package/src/components/atoms/Spacer/Spacer.stories.tsx +28 -0
  108. package/src/components/atoms/Spacer/Spacer.theme.ts +8 -0
  109. package/src/components/atoms/Spacer/index.ts +1 -0
  110. package/src/components/atoms/Video/Video.component.tsx +116 -0
  111. package/src/components/atoms/Video/Video.interface.ts +13 -0
  112. package/src/components/atoms/Video/Video.stories.tsx +37 -0
  113. package/src/components/atoms/Video/Video.theme.ts +44 -0
  114. package/src/components/atoms/Video/index.ts +1 -0
  115. package/src/components/atoms/VideoEmbed/VideoEmbed.component.tsx +109 -0
  116. package/src/components/atoms/VideoEmbed/VideoEmbed.interface.ts +13 -0
  117. package/src/components/atoms/VideoEmbed/VideoEmbed.stories.tsx +23 -0
  118. package/src/components/atoms/VideoEmbed/VideoEmbed.theme.ts +45 -0
  119. package/src/components/atoms/VideoEmbed/index.ts +1 -0
  120. package/src/components/common/PortalComponent/PortalComponent.tsx +48 -0
  121. package/src/components/common/PortalComponent/index.ts +1 -0
  122. package/src/components/molecules/Accordion/Accordion.component.tsx +58 -0
  123. package/src/components/molecules/Accordion/Accordion.interface.ts +15 -0
  124. package/src/components/molecules/Accordion/Accordion.stories.tsx +100 -0
  125. package/src/components/molecules/Accordion/Accordion.theme.ts +66 -0
  126. package/src/components/molecules/Accordion/index.ts +1 -0
  127. package/src/components/molecules/BlogCard/BlogCard.component.tsx +48 -0
  128. package/src/components/molecules/BlogCard/BlogCard.interface.ts +10 -0
  129. package/src/components/molecules/BlogCard/BlogCard.stories.tsx +37 -0
  130. package/src/components/molecules/BlogCard/BlogCard.theme.ts +63 -0
  131. package/src/components/molecules/BlogCard/index.ts +1 -0
  132. package/src/components/molecules/Card/Card.component.tsx +15 -0
  133. package/src/components/molecules/Card/Card.interface.ts +10 -0
  134. package/src/components/molecules/Card/Card.theme.ts +53 -0
  135. package/src/components/molecules/Card/index.ts +1 -0
  136. package/src/components/molecules/Dropdown/Dropdown.component.tsx +67 -0
  137. package/src/components/molecules/Dropdown/Dropdown.interface.ts +26 -0
  138. package/src/components/molecules/Dropdown/Dropdown.stories.tsx +54 -0
  139. package/src/components/molecules/Dropdown/Dropdown.theme.ts +50 -0
  140. package/src/components/molecules/Dropdown/index.ts +1 -0
  141. package/src/components/molecules/IconBox/IconBox.component.tsx +29 -0
  142. package/src/components/molecules/IconBox/IconBox.interface.tsx +10 -0
  143. package/src/components/molecules/IconBox/IconBox.stories.tsx +23 -0
  144. package/src/components/molecules/IconBox/IconBox.theme.ts +25 -0
  145. package/src/components/molecules/IconBox/index.ts +1 -0
  146. package/src/components/molecules/IconTitle/IconTitle.component.tsx +24 -0
  147. package/src/components/molecules/IconTitle/IconTitle.interface.tsx +10 -0
  148. package/src/components/molecules/IconTitle/IconTitle.stories.tsx +49 -0
  149. package/src/components/molecules/IconTitle/IconTitle.theme.ts +10 -0
  150. package/src/components/molecules/IconTitle/index.ts +1 -0
  151. package/src/components/molecules/Modal/Modal.component.tsx +70 -0
  152. package/src/components/molecules/Modal/Modal.interface.ts +11 -0
  153. package/src/components/molecules/Modal/Modal.stories.tsx +57 -0
  154. package/src/components/molecules/Modal/Modal.theme.ts +55 -0
  155. package/src/components/molecules/Modal/index.ts +1 -0
  156. package/src/components/molecules/OffCanvas/OffCanvas.component.tsx +55 -0
  157. package/src/components/molecules/OffCanvas/OffCanvas.interface.ts +12 -0
  158. package/src/components/molecules/OffCanvas/OffCanvas.stories.tsx +55 -0
  159. package/src/components/molecules/OffCanvas/OffCanvas.theme.ts +50 -0
  160. package/src/components/molecules/OffCanvas/index.ts +1 -0
  161. package/src/components/molecules/ProjectCard/ProjectCard.component.tsx +45 -0
  162. package/src/components/molecules/ProjectCard/ProjectCard.interface.ts +8 -0
  163. package/src/components/molecules/ProjectCard/ProjectCard.stories.tsx +72 -0
  164. package/src/components/molecules/ProjectCard/ProjectCard.theme.ts +61 -0
  165. package/src/components/molecules/ProjectCard/index.ts +1 -0
  166. package/src/components/molecules/ShareModal/ShareModal.component.tsx +166 -0
  167. package/src/components/molecules/ShareModal/ShareModal.interface.ts +9 -0
  168. package/src/components/molecules/ShareModal/ShareModal.stories.tsx +33 -0
  169. package/src/components/molecules/ShareModal/ShareModal.theme.ts +101 -0
  170. package/src/components/molecules/ShareModal/index.ts +1 -0
  171. package/src/components/molecules/TeamCard/TeamCard.component.tsx +31 -0
  172. package/src/components/molecules/TeamCard/TeamCard.interface.ts +7 -0
  173. package/src/components/molecules/TeamCard/TeamCard.stories.tsx +33 -0
  174. package/src/components/molecules/TeamCard/TeamCard.theme.ts +12 -0
  175. package/src/components/molecules/TeamCard/index.ts +1 -0
  176. package/src/components/organisms/Cover/Cover.component.tsx +46 -0
  177. package/src/components/organisms/Cover/Cover.interface.ts +14 -0
  178. package/src/components/organisms/Cover/Cover.stories.tsx +97 -0
  179. package/src/components/organisms/Cover/Cover.theme.ts +49 -0
  180. package/src/components/organisms/Cover/index.ts +1 -0
  181. package/src/components/organisms/Slider/Slider.component.tsx +145 -0
  182. package/src/components/organisms/Slider/Slider.interface.ts +17 -0
  183. package/src/components/organisms/Slider/Slider.stories.tsx +73 -0
  184. package/src/components/organisms/Slider/Slider.theme.ts +125 -0
  185. package/src/components/organisms/Slider/Slider.utils.tsx +19 -0
  186. package/src/components/organisms/Slider/index.ts +1 -0
  187. package/src/helpers/clickOutsideToClose.tsx +17 -0
  188. package/src/helpers/getIcons.ts +5 -0
  189. package/src/helpers/useMediaQuery.tsx +24 -0
  190. package/src/helpers/uuid.ts +5 -0
  191. package/src/iconsList.json +1 -0
  192. package/src/index.ts +53 -0
  193. package/src/reportWebVitals.js +13 -0
  194. package/src/stories/Documentation/Colors.stories.tsx +33 -0
  195. package/src/stories/Documentation/Headings.stories.tsx +24 -0
  196. package/src/stories/Documentation/Icons.stories.tsx +73 -0
  197. package/src/stories/Documentation/JWT.stories.tsx +60 -0
  198. package/src/stories/Documentation/Utilities.stories.tsx +65 -0
  199. package/src/styles/Global.ts +296 -0
  200. package/src/styles/grid.ts +70 -0
  201. package/src/styles/reset.ts +47 -0
  202. package/src/styles/utilities.ts +326 -0
  203. package/src/styles/variables.ts +168 -0
  204. package/tsconfig.json +29 -0
  205. package/tsconfig.node.json +11 -0
  206. package/vite.config.ts +87 -0
@@ -0,0 +1,35 @@
1
+ import { ISocialLinks } from './SocialLinks.interface'
2
+ import Icon from '../Icon/Icon.component'
3
+ import React from 'react'
4
+ import { StyledSocialLinks } from './SocialLinks.theme'
5
+
6
+ const SocialLinks = ({
7
+ variant,
8
+ socials,
9
+ className,
10
+ style,
11
+ ...props
12
+ }: ISocialLinks) => {
13
+ if (!socials) return <></>
14
+
15
+ return (
16
+ <StyledSocialLinks variant={variant} className={className} style={style}>
17
+ {Object.keys(socials).map((social: string) => {
18
+ return (
19
+ <li>
20
+ <a
21
+ href={socials[social]}
22
+ target="_blank"
23
+ aria-label={social}
24
+ rel="noreferrer"
25
+ >
26
+ <Icon icon={`icon-${social}`}></Icon>
27
+ </a>
28
+ </li>
29
+ )
30
+ })}
31
+ </StyledSocialLinks>
32
+ )
33
+ }
34
+
35
+ export default SocialLinks
@@ -0,0 +1,8 @@
1
+ import { CSSProperties } from 'react';
2
+
3
+ export type ISocialLinks = {
4
+ variant?: string
5
+ socials?: Record<string, string>
6
+ className?: string,
7
+ style?: CSSProperties
8
+ }
@@ -0,0 +1,36 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+
3
+ import { ISocialLinks } from './SocialLinks.interface'
4
+ import React from 'react'
5
+ import SocialLinks from './SocialLinks.component'
6
+
7
+ // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
8
+ export default {
9
+ title: 'Components/SocialLinks',
10
+ component: SocialLinks,
11
+ tags: ['autodocs'],
12
+ argTypes: {}
13
+ } as Meta
14
+
15
+ export const Light: StoryObj<ISocialLinks> = {
16
+ render: args => <SocialLinks {...args} />,
17
+ args: {
18
+ variant: 'light',
19
+ socials: {
20
+ facebook: 'https://www.facebook.com/wearemiew',
21
+ instagram: 'https://www.instagram.com/wearemiew/',
22
+ youtube: 'https://www.youtube.com/user/miewshapes',
23
+ linkedIn: 'https://www.linkedin.com/company/2470068/admin/',
24
+ dribble: 'https://dribbble.com/wearemiew',
25
+ behance: 'https://www.behance.net/miew/',
26
+ medium: 'https://medium.com/@wearemiew'
27
+ }
28
+ }
29
+ }
30
+
31
+ export const Dark: StoryObj<ISocialLinks> = {
32
+ args: {
33
+ ...Light.args,
34
+ variant: 'dark'
35
+ }
36
+ }
@@ -0,0 +1,52 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ import { ISocialLinks } from './SocialLinks.interface';
4
+ import { colors } from '@/styles/variables';
5
+
6
+ export const StyledSocialLinks = styled.ul<ISocialLinks>`
7
+ display: flex;
8
+ align-items: center;
9
+ gap: 12px;
10
+
11
+ & li{
12
+ & a{
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+
17
+ width: 2.8rem;
18
+ height: 2.8rem;
19
+ border-radius: 50%;
20
+ text-align: center;
21
+
22
+ transition: all 0.3s linear;
23
+
24
+ &:hover{
25
+ opacity: 0.6;
26
+ }
27
+ }
28
+
29
+ & i{
30
+ font-size: 1.6rem;
31
+ }
32
+ }
33
+
34
+ ${(props) => {
35
+ switch (props.variant) {
36
+ case "light": default:
37
+ return css`
38
+ & li a{
39
+ color: ${colors.white};
40
+ background-color: ${colors.primary70};
41
+ }
42
+ `;
43
+ case "dark":
44
+ return css`
45
+ & li a{
46
+ color: ${colors.primary70};
47
+ background-color: ${colors.white};
48
+ }
49
+ `;
50
+ }
51
+ }}
52
+ `;
@@ -0,0 +1 @@
1
+ export { default } from './SocialLinks.component'
@@ -0,0 +1,27 @@
1
+ import { ISpacer } from './Spacer.interface'
2
+ import React from 'react'
3
+ import { StyledSpacer } from './Spacer.theme'
4
+
5
+ const Spacer = ({
6
+ id,
7
+ color,
8
+ customHeight,
9
+ height,
10
+ className,
11
+ ...props
12
+ }: ISpacer) => {
13
+ return (
14
+ <StyledSpacer
15
+ id={id}
16
+ className={className}
17
+ style={{
18
+ backgroundColor: color ? color : ``,
19
+ height: customHeight ? customHeight : `var(--space-${String(height)})`
20
+ }}
21
+ aria-hidden="true"
22
+ {...props}
23
+ />
24
+ )
25
+ }
26
+
27
+ export default Spacer
@@ -0,0 +1,11 @@
1
+ import { CSSProperties } from 'react';
2
+ import { spaces } from '@/styles/variables';
3
+
4
+ export type ISpacer = {
5
+ id?: string
6
+ color?: string
7
+ height?: keyof typeof spaces | string | number
8
+ customHeight?: string
9
+ className?: string;
10
+ style?: CSSProperties
11
+ }
@@ -0,0 +1,28 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+
3
+ import { ISpacer } from '../Spacer/Spacer.interface'
4
+ import React from 'react'
5
+ import Spacer from '../Spacer/Spacer.component'
6
+
7
+ // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
8
+ export default {
9
+ title: 'Components/Spacer',
10
+ component: Spacer,
11
+ tags: ['autodocs'],
12
+ // argTypes: {
13
+ // height: {
14
+ // control: 'text'
15
+ // },
16
+ // color: {
17
+ // control: 'colorpicker'
18
+ // }
19
+ // }
20
+ } as Meta
21
+
22
+ export const Simple: StoryObj<ISpacer> = {
23
+ render: args => <Spacer {...args} />,
24
+ args: {
25
+ customHeight: '50px',
26
+ color: '#000'
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ import { ISpacer } from './Spacer.interface';
4
+
5
+ export const StyledSpacer = styled.div<ISpacer>`
6
+
7
+
8
+ `;
@@ -0,0 +1 @@
1
+ export { default } from "./Spacer.component";
@@ -0,0 +1,116 @@
1
+ import React, { useRef } from 'react'
2
+ import { StyledVideo, StyledVideoMask, StyledVideoPlay } from './Video.theme'
3
+
4
+ import { IVideo } from './Video.interface'
5
+
6
+ const Video = ({
7
+ src,
8
+ poster,
9
+ autoplay,
10
+ controls,
11
+ loop,
12
+ muted,
13
+ playsInline,
14
+ className,
15
+ style,
16
+ ...props
17
+ }: IVideo) => {
18
+ const maskRef: any = useRef()
19
+ const videoRef: any = useRef()
20
+ let isPlaying: boolean = false
21
+
22
+ const setFramed = () => {
23
+ const video = document.createElement('video')
24
+ const source = document.createElement('source')
25
+
26
+ autoplay && video.setAttribute('autoPlay', '')
27
+ controls && video.setAttribute('controls', '')
28
+ loop && video.setAttribute('loop', '')
29
+ muted && video.setAttribute('muted', '')
30
+ playsInline && video.setAttribute('playsInline', '')
31
+
32
+ source.setAttribute('src', src || '')
33
+ source.setAttribute('type', 'video/mp4')
34
+
35
+ video.appendChild(source)
36
+ video.pause()
37
+
38
+ video.onplaying = function () {
39
+ isPlaying = true
40
+ }
41
+ video.onpause = function () {
42
+ isPlaying = false
43
+ }
44
+
45
+ maskRef.current.replaceWith(video)
46
+
47
+ let observerObj = new IntersectionObserver(
48
+ (entries, observer) => {
49
+ const element: any = entries[0].target
50
+ if (entries[0].isIntersecting) {
51
+ if (
52
+ element.paused &&
53
+ !isPlaying &&
54
+ element.getAttribute('autoplay') != undefined
55
+ ) {
56
+ element.muted = true
57
+ element.play()
58
+ }
59
+ } else {
60
+ if (!element.paused && isPlaying) {
61
+ element.pause()
62
+ }
63
+ }
64
+ },
65
+ {
66
+ rootMargin: '0px',
67
+ threshold: 0.3
68
+ }
69
+ )
70
+
71
+ setTimeout(() => {
72
+ observerObj.observe(video)
73
+ }, 500)
74
+ }
75
+
76
+ return (
77
+ <StyledVideo className={className} style={style}>
78
+ {poster ? (
79
+ <StyledVideoMask
80
+ ref={maskRef}
81
+ style={{ backgroundImage: `url(${poster})` }}
82
+ onClick={() => {
83
+ setFramed()
84
+ }}
85
+ >
86
+ <StyledVideoPlay>
87
+ <svg
88
+ viewBox="0 0 62 72"
89
+ fill="none"
90
+ xmlns="http://www.w3.org/2000/svg"
91
+ >
92
+ <path
93
+ fillRule="evenodd"
94
+ clipRule="evenodd"
95
+ d="M1.30184 71.661C1.70029 71.8869 2.1419 72 2.58334 72C3.03735 72.0002 3.49152 71.8797 3.89774 71.6435L60.7311 38.2131C61.5182 37.7486 62 36.9073 62 35.9982C62 35.0891 61.5182 34.2478 60.7311 33.7832L3.89774 0.352633C3.10067 -0.109486 2.11412 -0.119525 1.30184 0.335024C0.496993 0.792041 0 1.64337 0 2.56761V69.4284C0 70.3526 0.496993 71.204 1.30184 71.661ZM5 65V7L54 36.0001L5 65Z"
96
+ />
97
+ </svg>
98
+ </StyledVideoPlay>
99
+ </StyledVideoMask>
100
+ ) : (
101
+ <video
102
+ autoPlay={autoplay}
103
+ controls={controls}
104
+ loop={loop}
105
+ muted={muted}
106
+ playsInline={playsInline}
107
+ >
108
+ <source type="video/mp4" src={src} />
109
+ </video>
110
+ )}
111
+
112
+ </StyledVideo>
113
+ )
114
+ }
115
+
116
+ export default Video
@@ -0,0 +1,13 @@
1
+ import { CSSProperties } from 'react'
2
+
3
+ export type IVideo = {
4
+ src?: string
5
+ poster?: string
6
+ autoplay?: boolean
7
+ controls?: boolean
8
+ loop?: boolean
9
+ muted?: boolean
10
+ playsInline?: boolean
11
+ className?: string
12
+ style?: CSSProperties
13
+ }
@@ -0,0 +1,37 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+
3
+ import Heading from '@/components/atoms/Heading'
4
+ import { IVideo } from './Video.interface'
5
+ import React from 'react'
6
+ import Spacer from '@/components/atoms/Spacer'
7
+ import Video from './Video.component'
8
+
9
+ // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
10
+ export default {
11
+ title: 'Components/Video',
12
+ component: Video,
13
+ argTypes: {}
14
+ } as Meta
15
+
16
+ export const Default: StoryObj<IVideo> = {
17
+ render: args => (
18
+ <div>
19
+ <Video {...args} />
20
+ <Spacer customHeight={'3rem'} />
21
+ <Heading tag="h2" size="h2">
22
+ Scroll to see autoplay in action
23
+ </Heading>
24
+ <Spacer customHeight={'38rem'} />
25
+ </div>
26
+ ),
27
+ args: {
28
+ autoplay: true,
29
+ controls: true,
30
+ loop: true,
31
+ muted: true,
32
+ playsInline: true,
33
+ poster:
34
+ 'https://miew.pt/wp-content/uploads/2021/02/featured-thumb-bmcar-2x-scaled.jpg',
35
+ src: 'https://miew.pt/wp-content/uploads/2021/01/miew_emotion_wide_v5.mp4'
36
+ }
37
+ }
@@ -0,0 +1,44 @@
1
+ import { colors, radius } from '@/styles/variables';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import { IVideo } from './Video.interface';
5
+
6
+ export const StyledVideo = styled.div<IVideo>`
7
+ display: block;
8
+ position: relative;
9
+ border-radius: ${radius.md};
10
+ overflow: hidden;
11
+
12
+ & video {
13
+ width: 100%;
14
+ border-radius: inherit;
15
+ }
16
+ `;
17
+ export const StyledVideoMask = styled.div<IVideo>`
18
+ aspect-ratio: 16/9;
19
+
20
+ background-position: center;
21
+ background-repeat: no-repeat;
22
+ background-size: cover;
23
+
24
+ cursor: pointer;
25
+ `;
26
+
27
+
28
+ export const StyledVideoPlay = styled.div<IVideo>`
29
+ position: absolute;
30
+ left: 50%;
31
+ top: 50%;
32
+ width: 10%;
33
+ transform: translate(-50%,-50%);
34
+ z-index: 1;
35
+
36
+ pointer-events: none;
37
+
38
+ & svg {
39
+ fill: ${colors.white};
40
+ width: 100%;
41
+ height: auto;
42
+ transition: all 0.4s linear;
43
+ }
44
+ `;
@@ -0,0 +1 @@
1
+ export { default } from "./Video.component";
@@ -0,0 +1,109 @@
1
+ import React, { useRef } from 'react'
2
+ import {
3
+ StyledVideo,
4
+ StyledVideoMask,
5
+ StyledVideoPlay
6
+ } from './VideoEmbed.theme'
7
+
8
+ import { IVideoEmbed } from './VideoEmbed.interface'
9
+
10
+ const VideoEmbed = ({
11
+ embed,
12
+ poster,
13
+ autoplay,
14
+ controls,
15
+ loop,
16
+ muted,
17
+ playsInline,
18
+ className,
19
+ style,
20
+ ...props
21
+ }: IVideoEmbed) => {
22
+ const maskRef: any = useRef()
23
+
24
+ const framed: boolean = false
25
+ let videoId: any = []
26
+ let thumb: string = poster || ''
27
+ let embedElement: string = ''
28
+
29
+ if (embed && !framed) {
30
+ if (embed.indexOf('/watch?v=') !== -1) {
31
+ videoId = embed.split('/watch?v=')
32
+ videoId = videoId[videoId.length - 1]
33
+ if (embed.indexOf('&') !== -1) {
34
+ videoId = videoId.split('&')
35
+ videoId = videoId[0]
36
+ }
37
+ } else if (embed.indexOf('/') !== -1) {
38
+ videoId = embed.split('/')
39
+ videoId = videoId[videoId.length - 1]
40
+ if (embed.indexOf('?') !== -1) {
41
+ videoId = videoId.split('?')
42
+ videoId = videoId[0]
43
+ }
44
+ }
45
+
46
+ const videoAttrs = `autoPlay=${autoplay}&controls=${controls}&loop=${loop}&muted=${muted}&playsInline=${playsInline}`
47
+
48
+ if (embed.indexOf('youtube') >= 0) {
49
+ embedElement = `https://www.youtube.com/embed/${videoId}?${videoAttrs}&enablejsapi=1`
50
+
51
+ if (!poster) {
52
+ thumb = `https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`
53
+ }
54
+ } else if (embed.indexOf('vimeo') >= 0) {
55
+ embedElement = `https://player.vimeo.com/video/${videoId}?${videoAttrs}`
56
+
57
+ if (!poster) {
58
+ thumb = `https://i.vimeocdn.com/video/${videoId}_640.jpg`
59
+ }
60
+ }
61
+ }
62
+
63
+ const setFramed = () => {
64
+ const iframe = document.createElement('iframe')
65
+
66
+ iframe.setAttribute('frameborder', '0')
67
+ iframe.setAttribute('allow', 'fullscreen; autoplay')
68
+ iframe.setAttribute('allowfullscreen', '1')
69
+
70
+ iframe.setAttribute('src', embedElement)
71
+
72
+ maskRef.current.replaceWith(iframe)
73
+
74
+ setTimeout(() => {
75
+ iframe?.contentWindow?.postMessage(
76
+ '{"event":"command","func":"playVideo","args":""}',
77
+ '*'
78
+ )
79
+ }, 500)
80
+ }
81
+
82
+ return (
83
+ <StyledVideo className={className} style={style}>
84
+ <StyledVideoMask
85
+ ref={maskRef}
86
+ style={{ backgroundImage: `url(${thumb})` }}
87
+ onClick={() => {
88
+ setFramed()
89
+ }}
90
+ >
91
+ <StyledVideoPlay>
92
+ <svg
93
+ viewBox="0 0 62 72"
94
+ fill="none"
95
+ xmlns="http://www.w3.org/2000/svg"
96
+ >
97
+ <path
98
+ fillRule="evenodd"
99
+ clipRule="evenodd"
100
+ d="M1.30184 71.661C1.70029 71.8869 2.1419 72 2.58334 72C3.03735 72.0002 3.49152 71.8797 3.89774 71.6435L60.7311 38.2131C61.5182 37.7486 62 36.9073 62 35.9982C62 35.0891 61.5182 34.2478 60.7311 33.7832L3.89774 0.352633C3.10067 -0.109486 2.11412 -0.119525 1.30184 0.335024C0.496993 0.792041 0 1.64337 0 2.56761V69.4284C0 70.3526 0.496993 71.204 1.30184 71.661ZM5 65V7L54 36.0001L5 65Z"
101
+ />
102
+ </svg>
103
+ </StyledVideoPlay>
104
+ </StyledVideoMask>
105
+ </StyledVideo>
106
+ )
107
+ }
108
+
109
+ export default VideoEmbed
@@ -0,0 +1,13 @@
1
+ import { CSSProperties } from 'react'
2
+
3
+ export type IVideoEmbed = {
4
+ embed?: string
5
+ poster?: string
6
+ autoplay?: boolean
7
+ controls?: boolean
8
+ loop?: boolean
9
+ muted?: boolean
10
+ playsInline?: boolean
11
+ className?: string
12
+ style?: CSSProperties
13
+ }
@@ -0,0 +1,23 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+
3
+ import { IVideoEmbed } from './VideoEmbed.interface'
4
+ import VideoEmbed from './VideoEmbed.component'
5
+
6
+ // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
7
+ export default {
8
+ title: 'Components/VideoEmbed',
9
+ component: VideoEmbed,
10
+ argTypes: {}
11
+ } as Meta
12
+
13
+ export const Embed: StoryObj<IVideoEmbed> = {
14
+ args: {
15
+ autoplay: true,
16
+ controls: true,
17
+ loop: true,
18
+ muted: true,
19
+ playsInline: true,
20
+ poster: '',
21
+ embed: 'https://www.youtube.com/watch?v=Ijk4j-r7qPA'
22
+ }
23
+ }
@@ -0,0 +1,45 @@
1
+ import { colors, radius } from '@/styles/variables';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import { IVideoEmbed } from './VideoEmbed.interface';
5
+
6
+ export const StyledVideo = styled.div<IVideoEmbed>`
7
+ display: block;
8
+ position: relative;
9
+ border-radius: ${radius.md};
10
+ overflow: hidden;
11
+
12
+ & iframe {
13
+ width: 100%;
14
+ aspect-ratio: 16/9;
15
+ border-radius: inherit;
16
+ }
17
+ `;
18
+
19
+ export const StyledVideoMask = styled.div<IVideoEmbed>`
20
+ aspect-ratio: 16/9;
21
+
22
+ background-position: center;
23
+ background-repeat: no-repeat;
24
+ background-size: cover;
25
+
26
+ cursor: pointer;
27
+ `;
28
+
29
+ export const StyledVideoPlay = styled.div<IVideoEmbed>`
30
+ position: absolute;
31
+ left: 50%;
32
+ top: 50%;
33
+ width: 10%;
34
+ transform: translate(-50%,-50%);
35
+ z-index: 1;
36
+
37
+ pointer-events: none;
38
+
39
+ & svg {
40
+ fill: ${colors.white};
41
+ width: 100%;
42
+ height: auto;
43
+ transition: all 0.4s linear;
44
+ }
45
+ `;
@@ -0,0 +1 @@
1
+ export { default } from "./VideoEmbed.component";
@@ -0,0 +1,48 @@
1
+ import { useLayoutEffect, useState } from 'react'
2
+
3
+ import { createPortal } from 'react-dom'
4
+
5
+ function createWrapperAndAppendToBody(wrapperId: string) {
6
+ const wrapperElement = document.createElement('div')
7
+ wrapperElement.setAttribute('id', wrapperId)
8
+ document.body.appendChild(wrapperElement)
9
+ return wrapperElement
10
+ }
11
+
12
+ type PortalComponentProps = {
13
+ wrapperId: string
14
+ children?: React.ReactNode
15
+ }
16
+
17
+ function PortalComponent({
18
+ wrapperId = 'react-portal-wrapper',
19
+ children
20
+ }: PortalComponentProps): React.ReactPortal | null {
21
+ const [wrapperElement, setWrapperElement] = useState<HTMLElement | null>(null)
22
+
23
+ useLayoutEffect(() => {
24
+ let element = document.getElementById(wrapperId)
25
+ let systemCreated = false
26
+ // if element is not found with wrapperId or wrapperId is not provided,
27
+ // create and append to body
28
+ if (!element) {
29
+ systemCreated = true
30
+ element = createWrapperAndAppendToBody(wrapperId)
31
+ }
32
+ setWrapperElement(element)
33
+
34
+ return () => {
35
+ // delete the programatically created element
36
+ if (systemCreated && element && element.parentNode) {
37
+ element.parentNode.removeChild(element)
38
+ }
39
+ }
40
+ }, [wrapperId])
41
+
42
+ // wrapperElement state will be null on very first render.
43
+ if (wrapperElement === null) return null
44
+
45
+ return createPortal(children, wrapperElement)
46
+ }
47
+
48
+ export default PortalComponent
@@ -0,0 +1 @@
1
+ export { default } from './PortalComponent'