@windstream/react-shared-components 0.0.89 → 0.0.90
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/README.md +635 -635
- package/dist/contentful/index.d.ts +12 -5
- package/dist/contentful/index.esm.js +1 -1
- package/dist/contentful/index.esm.js.map +1 -1
- package/dist/contentful/index.js +1 -1
- package/dist/contentful/index.js.map +1 -1
- package/dist/core.d.ts +3 -3
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +177 -177
- package/src/components/accordion/Accordion.stories.tsx +230 -230
- package/src/components/accordion/types.ts +10 -10
- package/src/components/alert-card/AlertCard.stories.tsx +171 -171
- package/src/components/alert-card/index.tsx +32 -32
- package/src/components/alert-card/types.ts +9 -9
- package/src/components/brand-button/BrandButton.stories.tsx +223 -223
- package/src/components/brand-button/helpers.ts +35 -35
- package/src/components/brand-button/index.tsx +115 -115
- package/src/components/brand-button/types.ts +37 -37
- package/src/components/button/Button.stories.tsx +108 -108
- package/src/components/button/index.tsx +27 -27
- package/src/components/button/types.ts +14 -14
- package/src/components/call-button/CallButton.stories.tsx +324 -324
- package/src/components/call-button/index.tsx +86 -86
- package/src/components/call-button/types.ts +11 -11
- package/src/components/checkbox/Checkbox.stories.tsx +247 -247
- package/src/components/checkbox/index.tsx +197 -197
- package/src/components/checkbox/types.ts +27 -27
- package/src/components/checklist/Checklist.stories.tsx +150 -150
- package/src/components/checklist/index.tsx +55 -54
- package/src/components/checklist/types.ts +14 -9
- package/src/components/collapse/Collapse.stories.tsx +255 -255
- package/src/components/collapse/index.tsx +46 -46
- package/src/components/collapse/types.ts +6 -6
- package/src/components/divider/Divider.stories.tsx +205 -205
- package/src/components/divider/index.tsx +22 -22
- package/src/components/divider/type.ts +3 -3
- package/src/components/image/Image.stories.tsx +113 -113
- package/src/components/image/index.tsx +25 -25
- package/src/components/image/types.ts +40 -40
- package/src/components/input/Input.stories.tsx +325 -325
- package/src/components/input/index.tsx +177 -177
- package/src/components/input/types.ts +37 -37
- package/src/components/link/Link.stories.tsx +163 -163
- package/src/components/link/types.ts +25 -25
- package/src/components/list/List.stories.tsx +272 -272
- package/src/components/list/index.tsx +88 -88
- package/src/components/list/list-item/index.tsx +38 -38
- package/src/components/list/list-item/types.ts +13 -13
- package/src/components/list/types.ts +29 -29
- package/src/components/material-icon/MaterialIcon.stories.tsx +330 -330
- package/src/components/material-icon/constants.ts +98 -98
- package/src/components/material-icon/index.tsx +44 -44
- package/src/components/material-icon/types.ts +31 -31
- package/src/components/modal/Modal.stories.tsx +171 -171
- package/src/components/modal/index.tsx +164 -164
- package/src/components/modal/types.ts +24 -24
- package/src/components/next-image/index.tsx +32 -32
- package/src/components/next-image/types.ts +1 -1
- package/src/components/radio-button/RadioButton.stories.tsx +307 -307
- package/src/components/radio-button/index.tsx +75 -75
- package/src/components/radio-button/types.ts +21 -21
- package/src/components/see-more/SeeMore.stories.tsx +181 -181
- package/src/components/see-more/index.tsx +44 -44
- package/src/components/see-more/types.ts +4 -4
- package/src/components/select/Select.stories.tsx +411 -411
- package/src/components/select/index.tsx +150 -150
- package/src/components/select/types.ts +35 -35
- package/src/components/select-plan-button/SelectPlanButton.stories.tsx +184 -184
- package/src/components/select-plan-button/index.tsx +31 -31
- package/src/components/select-plan-button/types.ts +5 -5
- package/src/components/skeleton/Skeleton.stories.tsx +179 -179
- package/src/components/skeleton/index.tsx +61 -61
- package/src/components/skeleton/types.ts +4 -4
- package/src/components/spinner/Spinner.stories.tsx +335 -335
- package/src/components/spinner/index.tsx +44 -44
- package/src/components/spinner/types.ts +5 -5
- package/src/components/text/Text.stories.tsx +321 -321
- package/src/components/text/index.tsx +25 -25
- package/src/components/text/types.ts +45 -45
- package/src/components/tooltip/Tooltip.stories.tsx +219 -219
- package/src/components/tooltip/index.tsx +74 -74
- package/src/components/tooltip/types.ts +7 -7
- package/src/components/view-cart-button/ViewCartButton.stories.tsx +252 -252
- package/src/components/view-cart-button/index.tsx +42 -42
- package/src/components/view-cart-button/types.ts +5 -5
- package/src/contentful/blocks/button/Button.stories.tsx +40 -40
- package/src/contentful/blocks/button/index.tsx +99 -99
- package/src/contentful/blocks/button/types.ts +31 -31
- package/src/contentful/blocks/callout/Callout.stories.tsx +23 -23
- package/src/contentful/blocks/callout/index.tsx +66 -66
- package/src/contentful/blocks/cards/Cards.stories.tsx +23 -23
- package/src/contentful/blocks/cards/index.tsx +13 -13
- package/src/contentful/blocks/cards/product-card/index.tsx +199 -199
- package/src/contentful/blocks/cards/product-card/types.ts +21 -20
- package/src/contentful/blocks/cards/simple-card/index.tsx +77 -77
- package/src/contentful/blocks/cards/simple-card/types.ts +31 -31
- package/src/contentful/blocks/cards/testimonial-card/index.tsx +88 -88
- package/src/contentful/blocks/cards/testimonial-card/types.tsx +12 -12
- package/src/contentful/blocks/cards/types.ts +1 -1
- package/src/contentful/blocks/carousel/Carousel.stories.tsx +23 -23
- package/src/contentful/blocks/carousel/helper.tsx +349 -314
- package/src/contentful/blocks/carousel/index.tsx +68 -52
- package/src/contentful/blocks/carousel/types.ts +140 -126
- package/src/contentful/blocks/cta-callout/CtaCallout.stories.tsx +46 -46
- package/src/contentful/blocks/cta-callout/index.tsx +54 -54
- package/src/contentful/blocks/cta-callout/types.ts +22 -22
- package/src/contentful/blocks/find-kinetic/index.tsx +124 -124
- package/src/contentful/blocks/floating-banner/FloatingBanner.stories.tsx +34 -34
- package/src/contentful/blocks/floating-banner/types.ts +22 -22
- package/src/contentful/blocks/footer/Footer.stories.tsx +30 -30
- package/src/contentful/blocks/image-promo-bar/ImagePromoBar.stories.tsx +23 -23
- package/src/contentful/blocks/image-promo-bar/helper.tsx +28 -0
- package/src/contentful/blocks/image-promo-bar/index.tsx +231 -154
- package/src/contentful/blocks/image-promo-bar/types.ts +44 -31
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.tsx +93 -0
- package/src/contentful/blocks/image-promo-bar/youtube-embed.tsx +46 -0
- package/src/contentful/blocks/modal/constants.ts +53 -53
- package/src/contentful/blocks/modal/index.tsx +91 -91
- package/src/contentful/blocks/modal/types.ts +12 -12
- package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.tsx +111 -111
- package/src/contentful/blocks/navigation/index.tsx +385 -385
- package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.tsx +80 -80
- package/src/contentful/blocks/navigation/types.ts +41 -41
- package/src/contentful/blocks/primary-hero/PrimaryHero.stories.tsx +23 -23
- package/src/contentful/blocks/primary-hero/index.tsx +228 -228
- package/src/contentful/blocks/primary-hero/types.ts +35 -35
- package/src/contentful/blocks/shape-background-wrapper/ShapeBackgroundWrapper.stories.tsx +26 -26
- package/src/contentful/blocks/shape-background-wrapper/index.tsx +124 -124
- package/src/contentful/blocks/shape-background-wrapper/types.ts +36 -36
- package/src/contentful/blocks/text/Text.stories.tsx +23 -23
- package/src/contentful/blocks/text/index.tsx +12 -12
- package/src/contentful/blocks/text/types.ts +1 -1
- package/src/contentful/index.ts +57 -57
- package/src/hooks/use-body-scroll-lock.ts +34 -34
- package/src/hooks/use-outside-click.ts +17 -17
- package/src/index.ts +96 -96
- package/src/next/index.ts +5 -5
- package/src/setupTests.ts +46 -46
- package/src/stories/DocsTemplate.tsx +24 -24
- package/src/styles/globals.css +307 -307
- package/src/types/global.d.ts +9 -9
- package/src/types/micro-components.ts +89 -89
- package/src/utils/index.ts +49 -49
|
@@ -1,154 +1,231 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Button } from "../button";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
</div>
|
|
145
|
-
)}
|
|
146
|
-
</div>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Button } from "../button";
|
|
3
|
+
import { PlayButton } from "./helper";
|
|
4
|
+
import { ImagePromoBarProps } from "./types";
|
|
5
|
+
import { VimeoEmbed } from "./vimeo-embed";
|
|
6
|
+
import { YoutubeEmbed } from "./youtube-embed";
|
|
7
|
+
|
|
8
|
+
import { Checklist } from "@shared/components/checklist";
|
|
9
|
+
import { Image } from "@shared/components/image";
|
|
10
|
+
import { Link } from "@shared/components/link";
|
|
11
|
+
import { NextImage } from "@shared/components/next-image";
|
|
12
|
+
import { Text } from "@shared/components/text";
|
|
13
|
+
import { cx } from "@shared/utils";
|
|
14
|
+
|
|
15
|
+
export const ImagePromoBar: React.FC<ImagePromoBarProps> = ({
|
|
16
|
+
brow,
|
|
17
|
+
enableHeading,
|
|
18
|
+
title,
|
|
19
|
+
subTitle,
|
|
20
|
+
ctaDisclaimer,
|
|
21
|
+
disclaimer,
|
|
22
|
+
description,
|
|
23
|
+
image,
|
|
24
|
+
imageLinks,
|
|
25
|
+
mediaPosition = true,
|
|
26
|
+
checklist,
|
|
27
|
+
secondaryCta,
|
|
28
|
+
cta,
|
|
29
|
+
videoLink,
|
|
30
|
+
maxWidth = true,
|
|
31
|
+
color = "light",
|
|
32
|
+
imageWidth = 660,
|
|
33
|
+
imageHeight = 660,
|
|
34
|
+
onModalButtonClick,
|
|
35
|
+
}) => {
|
|
36
|
+
const [activeVideo, setActiveVideo] = useState("");
|
|
37
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
38
|
+
|
|
39
|
+
const handlePlayClick = () => {
|
|
40
|
+
setActiveVideo(videoLink?.link ?? "");
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleCloseVideo = (e: React.MouseEvent) => {
|
|
44
|
+
e.stopPropagation();
|
|
45
|
+
setActiveVideo("");
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const videoHref = videoLink?.link ?? "";
|
|
49
|
+
const videoImage = videoLink?.image;
|
|
50
|
+
const videoPopup = videoLink?.videoPopup ?? false;
|
|
51
|
+
const isPlaying = Boolean(activeVideo && activeVideo === videoHref);
|
|
52
|
+
|
|
53
|
+
const embedSelector = () => {
|
|
54
|
+
if (videoHref.includes("vimeo")) {
|
|
55
|
+
return <VimeoEmbed link={videoHref} autoplay={isPlaying} />;
|
|
56
|
+
} else {
|
|
57
|
+
return <YoutubeEmbed link={videoHref} autoplay={isPlaying} />;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const contentVideo = videoLink && videoImage ? embedSelector() : null;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className="component-container">
|
|
64
|
+
<div
|
|
65
|
+
className={`image-promo-bar-content ${maxWidth ? "max-w-120 xl:mx-auto" : ""} mx-5 mb-8 mt-16`}
|
|
66
|
+
>
|
|
67
|
+
<div
|
|
68
|
+
className={`flex shrink-0 flex-col items-center gap-8 xl:items-start xl:gap-[126px] ${mediaPosition ? "xl:flex-row-reverse" : "xl:flex-row"}`}
|
|
69
|
+
>
|
|
70
|
+
<div
|
|
71
|
+
className={`flex flex-[1_0_0] flex-col items-start justify-center gap-8 xl:gap-10 ${color == "dark" ? "text-text" : "text-white"}`}
|
|
72
|
+
>
|
|
73
|
+
<div className="heading holder">
|
|
74
|
+
{brow && (
|
|
75
|
+
<Text
|
|
76
|
+
as="div"
|
|
77
|
+
className="subheading4 mb-4 text-text-brand xl:subheading2 xl:mb-3"
|
|
78
|
+
>
|
|
79
|
+
{brow}
|
|
80
|
+
</Text>
|
|
81
|
+
)}
|
|
82
|
+
{title && (
|
|
83
|
+
<Text
|
|
84
|
+
as={enableHeading ? "h1" : "h2"}
|
|
85
|
+
className="heading2 xl:heading1"
|
|
86
|
+
>
|
|
87
|
+
{title}
|
|
88
|
+
</Text>
|
|
89
|
+
)}
|
|
90
|
+
{subTitle && (
|
|
91
|
+
<Text
|
|
92
|
+
as={enableHeading ? "h2" : "h3"}
|
|
93
|
+
className="subheading1 mt-3"
|
|
94
|
+
>
|
|
95
|
+
{subTitle}
|
|
96
|
+
</Text>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
{/* Content Section */}
|
|
100
|
+
{description && (
|
|
101
|
+
<Text as="div" className="body1">
|
|
102
|
+
{description}
|
|
103
|
+
</Text>
|
|
104
|
+
)}
|
|
105
|
+
{/* Checklist Rendering */}
|
|
106
|
+
{checklist.length > 0 && (
|
|
107
|
+
<Checklist items={checklist} iconPosition="top" iconSize={24} />
|
|
108
|
+
)}
|
|
109
|
+
<div className="flex gap-4">
|
|
110
|
+
{/* Image Links Collection */}
|
|
111
|
+
{imageLinks?.map(
|
|
112
|
+
(link: { url: string; image: string }, index: number) => (
|
|
113
|
+
<div key={index} className="image-link w-[147px]">
|
|
114
|
+
<Link
|
|
115
|
+
variant="unstyled"
|
|
116
|
+
href={link.url}
|
|
117
|
+
target="_blank"
|
|
118
|
+
rel="noopener noreferrer"
|
|
119
|
+
>
|
|
120
|
+
<Image src={link.image} alt="icon-link" />
|
|
121
|
+
</Link>
|
|
122
|
+
</div>
|
|
123
|
+
)
|
|
124
|
+
)}
|
|
125
|
+
</div>
|
|
126
|
+
{/* CTAs and Disclaimers */}
|
|
127
|
+
<div className="flex w-full flex-col gap-8 xl:flex-row xl:gap-3">
|
|
128
|
+
{cta && (
|
|
129
|
+
<div className="primary-cta w-full xl:w-auto">
|
|
130
|
+
<Button
|
|
131
|
+
{...cta}
|
|
132
|
+
fullWidth={true}
|
|
133
|
+
onModalButtonClick={onModalButtonClick}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
{secondaryCta && (
|
|
138
|
+
<div className="secondary-cta">
|
|
139
|
+
<Button
|
|
140
|
+
{...secondaryCta}
|
|
141
|
+
fullWidth={true}
|
|
142
|
+
onModalButtonClick={onModalButtonClick}
|
|
143
|
+
/>
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
</div>
|
|
147
|
+
{ctaDisclaimer && <div>{ctaDisclaimer}</div>}
|
|
148
|
+
{disclaimer && <div>{disclaimer}</div>}
|
|
149
|
+
</div>
|
|
150
|
+
<aside className="flex w-full shrink-0 items-center justify-center xl:w-auto">
|
|
151
|
+
{/* Media Section */}
|
|
152
|
+
{image && (
|
|
153
|
+
<div className="relative aspect-[16/9] w-full xl:aspect-square xl:max-h-[486px] xl:w-[486px]">
|
|
154
|
+
<NextImage
|
|
155
|
+
src={image}
|
|
156
|
+
alt="section-image"
|
|
157
|
+
width={imageWidth}
|
|
158
|
+
height={imageHeight}
|
|
159
|
+
className="bottom-0 left-0 right-0 top-0 h-full rounded-[40px] object-cover"
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
)}
|
|
163
|
+
{/* Video Link Section */}
|
|
164
|
+
{videoLink?.link && (
|
|
165
|
+
<div
|
|
166
|
+
className={cx(
|
|
167
|
+
"video-section relative w-full cursor-pointer overflow-hidden rounded-[40px] transition-all duration-300 xl:w-[486px]",
|
|
168
|
+
!isPlaying && "hover:shadow-2xl"
|
|
169
|
+
)}
|
|
170
|
+
onClick={handlePlayClick}
|
|
171
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
172
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
173
|
+
>
|
|
174
|
+
{/* Preview Image & Play Button */}
|
|
175
|
+
<div
|
|
176
|
+
className={cx(
|
|
177
|
+
isPlaying && !videoPopup && "hidden",
|
|
178
|
+
isPlaying && !videoPopup ? "opacity-0" : "opacity-100",
|
|
179
|
+
"relative aspect-[16/9] w-full transition-opacity duration-300 xl:aspect-square"
|
|
180
|
+
)}
|
|
181
|
+
>
|
|
182
|
+
{videoLink.image && (
|
|
183
|
+
<NextImage
|
|
184
|
+
src={videoLink.image}
|
|
185
|
+
alt="Video preview"
|
|
186
|
+
width={486}
|
|
187
|
+
height={486}
|
|
188
|
+
className="absolute inset-0 h-full w-full rounded-[40px] object-cover"
|
|
189
|
+
/>
|
|
190
|
+
)}
|
|
191
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
192
|
+
<PlayButton isHovered={isHovered} />
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
{/* Inline Player (if not popup) */}
|
|
197
|
+
{!videoPopup && isPlaying && (
|
|
198
|
+
<div
|
|
199
|
+
className={cx(
|
|
200
|
+
"aspect-[16/9] w-full overflow-hidden rounded-[40px] transition-opacity duration-300",
|
|
201
|
+
isPlaying ? "opacity-100" : "opacity-0"
|
|
202
|
+
)}
|
|
203
|
+
>
|
|
204
|
+
{contentVideo}
|
|
205
|
+
</div>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
209
|
+
</aside>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
{/* Video Popup Overlay */}
|
|
214
|
+
{videoPopup && isPlaying && (
|
|
215
|
+
<div
|
|
216
|
+
className="fixed inset-0 top-20 z-[100] flex items-center justify-center bg-black/80 p-4 transition-all duration-300"
|
|
217
|
+
onClick={handleCloseVideo}
|
|
218
|
+
>
|
|
219
|
+
<div
|
|
220
|
+
className="max-w-6xl aspect-video w-full overflow-hidden rounded-3xl bg-black shadow-2xl md:w-4/6"
|
|
221
|
+
onClick={e => e.stopPropagation()}
|
|
222
|
+
>
|
|
223
|
+
{contentVideo}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export default ImagePromoBar;
|
|
@@ -1,31 +1,44 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import { CheckPlansProps } from "@shared/types/micro-components";
|
|
4
|
-
|
|
5
|
-
export type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { CheckPlansProps } from "@shared/types/micro-components";
|
|
4
|
+
|
|
5
|
+
export type VideoLinkProps = {
|
|
6
|
+
image?: string;
|
|
7
|
+
videoPopup?: boolean;
|
|
8
|
+
link?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type VideoEmbedProps = {
|
|
12
|
+
containerClassName?: string;
|
|
13
|
+
autoplay?: boolean;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
} & VideoLinkProps;
|
|
16
|
+
|
|
17
|
+
export type ImagePromoBarProps = {
|
|
18
|
+
brow: string;
|
|
19
|
+
enableHeading: boolean;
|
|
20
|
+
title: string;
|
|
21
|
+
subTitle: string;
|
|
22
|
+
image: string;
|
|
23
|
+
imageWidth: number;
|
|
24
|
+
imageHeight: number;
|
|
25
|
+
mediaPosition: boolean;
|
|
26
|
+
description: React.ReactNode;
|
|
27
|
+
openDescriptionLinksOnANewTab: boolean;
|
|
28
|
+
checklist: string[];
|
|
29
|
+
disclaimer: React.ReactNode;
|
|
30
|
+
imageLinks: { url: string; image: string }[];
|
|
31
|
+
cta: any;
|
|
32
|
+
secondaryCta: any;
|
|
33
|
+
ctaDisclaimer: React.ReactNode;
|
|
34
|
+
videoLink: VideoLinkProps;
|
|
35
|
+
maxWidth?: boolean;
|
|
36
|
+
color: "light" | "dark";
|
|
37
|
+
onModalButtonClick?: (id?: string) => void;
|
|
38
|
+
renderCheckPlans?: (overrides?: CheckPlansProps) => React.ReactNode;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type PlayButtonProps = {
|
|
42
|
+
isHovered?: boolean;
|
|
43
|
+
containerClassName?: string;
|
|
44
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { VideoEmbedProps } from "./types";
|
|
3
|
+
|
|
4
|
+
import { cx } from "@shared/utils";
|
|
5
|
+
|
|
6
|
+
const extractVimeoIdandHash = (href: string) => {
|
|
7
|
+
// Strip query parameters and fragments
|
|
8
|
+
const cleanHref = href.split(/[?#]/)[0].replace(/\/+$/, "");
|
|
9
|
+
const match =
|
|
10
|
+
cleanHref.match(/vimeo\.com\/(?:.*\/)?(\d{6,})/) ||
|
|
11
|
+
cleanHref.match(/player\.vimeo\.com\/video\/(\d{6,})/);
|
|
12
|
+
|
|
13
|
+
const parts = cleanHref.split("/");
|
|
14
|
+
const hash = parts[parts.length - 1];
|
|
15
|
+
|
|
16
|
+
if (!match?.[1]) return "";
|
|
17
|
+
if (match[1] === hash) return match[1];
|
|
18
|
+
return `${match[1]}/${hash}`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const VimeoEmbed: React.FC<VideoEmbedProps> = props => {
|
|
22
|
+
const { link, containerClassName, autoplay = false, debug = false } = props;
|
|
23
|
+
|
|
24
|
+
const { href, embedId } = useMemo(() => {
|
|
25
|
+
if (!link) return { href: "", embedId: "" };
|
|
26
|
+
const resolved = link.toString();
|
|
27
|
+
const id = extractVimeoIdandHash(resolved);
|
|
28
|
+
return { href: resolved, embedId: id };
|
|
29
|
+
}, [link]);
|
|
30
|
+
|
|
31
|
+
if (debug) {
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
33
|
+
console.log("[VimeoEmbed] href:", href, "id:", embedId);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!embedId) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const params = new URLSearchParams({
|
|
41
|
+
autoplay: autoplay ? "1" : "0",
|
|
42
|
+
muted: "0",
|
|
43
|
+
playsinline: "1",
|
|
44
|
+
dnt: "1",
|
|
45
|
+
title: "0",
|
|
46
|
+
byline: "0",
|
|
47
|
+
portrait: "0",
|
|
48
|
+
autopause: "1",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const o_src = `https://player.vimeo.com/video/${embedId}?${params.toString()}`;
|
|
52
|
+
const src = normalizeVimeoPlayerSrc(o_src);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
className={cx(
|
|
57
|
+
"relative h-0 w-full overflow-hidden pb-[56.25%]",
|
|
58
|
+
containerClassName
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
61
|
+
<iframe
|
|
62
|
+
className="absolute left-0 top-0 h-full w-full"
|
|
63
|
+
src={src}
|
|
64
|
+
allow="autoplay; fullscreen; picture-in-picture"
|
|
65
|
+
allowFullScreen={true}
|
|
66
|
+
referrerPolicy="strict-origin-when-cross-origin"
|
|
67
|
+
title="Embedded vimeo"
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function normalizeVimeoPlayerSrc(src: string): string {
|
|
74
|
+
try {
|
|
75
|
+
const u = new URL(src);
|
|
76
|
+
// Expect path like /video/{id}
|
|
77
|
+
const parts = u.pathname.split("/").filter(Boolean);
|
|
78
|
+
// Handle /video/{id}/{hash} -> move {hash} to ?h=...
|
|
79
|
+
if (parts[0] === "video" && parts.length >= 2) {
|
|
80
|
+
const id = parts[1];
|
|
81
|
+
const maybeHash = parts[2];
|
|
82
|
+
// Rebuild base
|
|
83
|
+
const base = `https://player.vimeo.com/video/${id}`;
|
|
84
|
+
if (maybeHash && /^[a-f0-9]+$/i.test(maybeHash)) {
|
|
85
|
+
u.searchParams.set("h", maybeHash);
|
|
86
|
+
}
|
|
87
|
+
return `${base}?${u.searchParams.toString()}`;
|
|
88
|
+
}
|
|
89
|
+
return src;
|
|
90
|
+
} catch {
|
|
91
|
+
return src;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { VideoEmbedProps } from "./types";
|
|
3
|
+
|
|
4
|
+
import { cx } from "@shared/utils";
|
|
5
|
+
|
|
6
|
+
// import styles from "./styles.module.scss";
|
|
7
|
+
|
|
8
|
+
export type Props = {
|
|
9
|
+
containerClassName?: string;
|
|
10
|
+
autoplay?: boolean; // Add the autoplay prop
|
|
11
|
+
} & VideoEmbedProps;
|
|
12
|
+
|
|
13
|
+
export const YoutubeEmbed: React.FC<Props> = props => {
|
|
14
|
+
const { link, containerClassName, autoplay = false } = props;
|
|
15
|
+
|
|
16
|
+
const embedId = useMemo(() => {
|
|
17
|
+
if (!link) return "";
|
|
18
|
+
|
|
19
|
+
const href = link.toString();
|
|
20
|
+
const regExp =
|
|
21
|
+
/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
|
|
22
|
+
const match = href.match(regExp);
|
|
23
|
+
|
|
24
|
+
return match && match[7].length === 11 ? match[7] : "";
|
|
25
|
+
}, [link]);
|
|
26
|
+
|
|
27
|
+
// Add autoplay parameter to the URL if autoplay is true
|
|
28
|
+
const autoplayParam = autoplay ? "?autoplay=1" : "";
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
className={cx(
|
|
33
|
+
"relative h-0 w-full overflow-hidden pb-[56.25%]",
|
|
34
|
+
containerClassName
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
<iframe
|
|
38
|
+
className="absolute left-0 top-0 h-full w-full"
|
|
39
|
+
src={`https://www.youtube.com/embed/${embedId}${autoplayParam}`}
|
|
40
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
41
|
+
allowFullScreen={true}
|
|
42
|
+
title="Embedded youtube"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
};
|