@windstream/react-shared-components 0.2.21 → 0.2.23
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/dist/contentful/index.d.ts +6 -3
- package/dist/contentful/index.esm.js +3 -3
- package/dist/contentful/index.esm.js.map +1 -1
- package/dist/contentful/index.js +2 -2
- package/dist/contentful/index.js.map +1 -1
- package/dist/core.d.ts +10 -5
- package/dist/index.d.ts +6 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.esm.js +1 -1
- package/dist/utils/index.esm.js.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/animation-wrapper/index.tsx +8 -2
- package/src/components/animation-wrapper/types.ts +6 -0
- package/src/components/brand-button/index.tsx +12 -3
- package/src/contentful/blocks/anchored-bottom-banner/AnchoredBottomBanner.stories.tsx +155 -0
- package/src/contentful/blocks/button/index.tsx +12 -3
- package/src/contentful/blocks/callout/Callout.stories.mocks.ts +327 -0
- package/src/contentful/blocks/callout/Callout.stories.tsx +315 -2
- package/src/contentful/blocks/callout/types.ts +1 -2
- package/src/contentful/blocks/email-input-block/index.tsx +41 -17
- package/src/contentful/blocks/email-input-block/types.ts +2 -1
- package/src/contentful/blocks/image-promo-bar/index.test.tsx +45 -4
- package/src/contentful/blocks/image-promo-bar/index.tsx +4 -1
- package/src/contentful/blocks/image-promo-bar/types.ts +1 -0
- package/src/contentful/blocks/primary-hero/index.test.tsx +63 -0
- package/src/contentful/blocks/primary-hero/index.tsx +66 -9
- package/src/hooks/contentful/use-contentful-rich-text.test.tsx +29 -0
- package/src/hooks/contentful/use-contentful-rich-text.tsx +20 -9
- package/src/index.ts +1 -0
- package/src/types/global.d.ts +5 -0
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
AnimationType,
|
|
6
|
+
AnimationWrapperProps,
|
|
7
|
+
DEFAULT_BUTTON_ANIMATION_TYPE,
|
|
8
|
+
} from "./types";
|
|
5
9
|
import { motion, useReducedMotion } from "framer-motion";
|
|
6
10
|
|
|
7
11
|
interface AnimationPreset {
|
|
@@ -66,7 +70,7 @@ function mergePresets(animationType?: AnimationType | AnimationType[]) {
|
|
|
66
70
|
|
|
67
71
|
export function AnimationWrapper({
|
|
68
72
|
children,
|
|
69
|
-
animationType,
|
|
73
|
+
animationType = DEFAULT_BUTTON_ANIMATION_TYPE,
|
|
70
74
|
// default to true for backward compatibility
|
|
71
75
|
disableAnimation = true,
|
|
72
76
|
whileHover,
|
|
@@ -84,6 +88,7 @@ export function AnimationWrapper({
|
|
|
84
88
|
return child;
|
|
85
89
|
}
|
|
86
90
|
|
|
91
|
+
// Use the provided animationType, falling back to the centralized default.
|
|
87
92
|
const preset = mergePresets(animationType);
|
|
88
93
|
|
|
89
94
|
const mergedWhileHover = preset
|
|
@@ -132,4 +137,5 @@ export function AnimationWrapper({
|
|
|
132
137
|
|
|
133
138
|
AnimationWrapper.displayName = "AnimationWrapper";
|
|
134
139
|
|
|
140
|
+
export { DEFAULT_BUTTON_ANIMATION_TYPE };
|
|
135
141
|
export type { AnimationWrapperProps, AnimationType };
|
|
@@ -9,6 +9,12 @@ export type AnimationType =
|
|
|
9
9
|
| "grow"
|
|
10
10
|
| "pop";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Single source of truth for the default button animation type.
|
|
14
|
+
* Change this value to update the default button animation across the app.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_BUTTON_ANIMATION_TYPE: AnimationType = "pop";
|
|
17
|
+
|
|
12
18
|
export interface AnimationWrapperProps
|
|
13
19
|
extends Omit<HTMLMotionProps<"div">, "children"> {
|
|
14
20
|
children: ReactElement;
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import React, { forwardRef } from "react";
|
|
4
4
|
import { getLabelSizeBasedOnButtonSize, sizeToClassNames } from "./helpers";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
AnimationWrapper,
|
|
8
|
+
DEFAULT_BUTTON_ANIMATION_TYPE,
|
|
9
|
+
} from "@shared/components/animation-wrapper";
|
|
7
10
|
import {
|
|
8
11
|
ButtonProps,
|
|
9
12
|
ButtonVariantsT,
|
|
@@ -29,9 +32,15 @@ export const BrandButton = forwardRef<
|
|
|
29
32
|
iconName,
|
|
30
33
|
iconSize = 24,
|
|
31
34
|
iconFill = 0,
|
|
35
|
+
// `disableAnimation` is intentionally NOT defaulted to `false` here.
|
|
36
|
+
// Animations are opt-in by design: when this prop is left undefined,
|
|
37
|
+
// AnimationWrapper falls back to its own default of `true` (animation
|
|
38
|
+
// disabled). This keeps behavior consistent with the CMS contract where
|
|
39
|
+
// an unset value means "no animation". Animation runs only when a caller
|
|
40
|
+
// (or Contentful) explicitly passes `disableAnimation={false}`.
|
|
41
|
+
disableAnimation,
|
|
42
|
+
animationType = DEFAULT_BUTTON_ANIMATION_TYPE,
|
|
32
43
|
as = "button",
|
|
33
|
-
disableAnimation = true,
|
|
34
|
-
animationType,
|
|
35
44
|
...props
|
|
36
45
|
},
|
|
37
46
|
ref
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { AnchoredBottomBanner } from "./index";
|
|
4
|
+
|
|
5
|
+
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
6
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof AnchoredBottomBanner> = {
|
|
9
|
+
title: "Contentful Blocks/AnchoredBottomBanner",
|
|
10
|
+
component: AnchoredBottomBanner,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: "fullscreen",
|
|
14
|
+
docs: {
|
|
15
|
+
page: DocsPage,
|
|
16
|
+
description: {
|
|
17
|
+
component:
|
|
18
|
+
"A fixed-position bottom banner with an optional countdown timer, icon, and CTA link.",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
decorators: [
|
|
23
|
+
Story => (
|
|
24
|
+
<>
|
|
25
|
+
<style>{`
|
|
26
|
+
#anchored-banner .fixed > a > div > div {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
gap: 0.5rem;
|
|
31
|
+
flex-wrap: nowrap;
|
|
32
|
+
}
|
|
33
|
+
#anchored-banner .material-symbols-rounded {
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
}
|
|
36
|
+
`}</style>
|
|
37
|
+
<Story />
|
|
38
|
+
</>
|
|
39
|
+
),
|
|
40
|
+
],
|
|
41
|
+
argTypes: {
|
|
42
|
+
ctaSuffixText: { control: "text" },
|
|
43
|
+
backgroundColor: {
|
|
44
|
+
control: "select",
|
|
45
|
+
options: ["navy", "yellow", "green", "purple", "blue", "white"],
|
|
46
|
+
},
|
|
47
|
+
iconName: { control: "text" },
|
|
48
|
+
boxShadow: { control: "boolean" },
|
|
49
|
+
ctaButtonLabel: { control: "text" },
|
|
50
|
+
ctaButtonLink: { control: "text" },
|
|
51
|
+
ctaButtonTarget: {
|
|
52
|
+
control: "select",
|
|
53
|
+
options: ["_self", "_blank"],
|
|
54
|
+
},
|
|
55
|
+
anchorId: { control: "text" },
|
|
56
|
+
enableCountdownTimer: { control: "boolean" },
|
|
57
|
+
countdownStartDateTime: {
|
|
58
|
+
control: "date",
|
|
59
|
+
description: "Timer becomes visible after this time",
|
|
60
|
+
},
|
|
61
|
+
countdownEndDateTime: {
|
|
62
|
+
control: "date",
|
|
63
|
+
description: "Timer counts down to this time",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
render: args => {
|
|
67
|
+
const { countdownStartDateTime, countdownEndDateTime, ...rest } = args;
|
|
68
|
+
return (
|
|
69
|
+
<AnchoredBottomBanner
|
|
70
|
+
{...rest}
|
|
71
|
+
countdownStartDateTime={
|
|
72
|
+
typeof countdownStartDateTime === "number" &&
|
|
73
|
+
Number.isFinite(countdownStartDateTime)
|
|
74
|
+
? new Date(countdownStartDateTime).toISOString()
|
|
75
|
+
: (countdownStartDateTime as string | undefined)
|
|
76
|
+
}
|
|
77
|
+
countdownEndDateTime={
|
|
78
|
+
typeof countdownEndDateTime === "number" &&
|
|
79
|
+
Number.isFinite(countdownEndDateTime)
|
|
80
|
+
? new Date(countdownEndDateTime).toISOString()
|
|
81
|
+
: (countdownEndDateTime as string | undefined)
|
|
82
|
+
}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
args: {
|
|
87
|
+
ctaSuffixText: "to order Kinetic today",
|
|
88
|
+
backgroundColor: "yellow",
|
|
89
|
+
iconName: "call",
|
|
90
|
+
boxShadow: true,
|
|
91
|
+
ctaButtonLabel: "call (866) 445-8084",
|
|
92
|
+
ctaButtonLink: "tel:+1-866-445-8084",
|
|
93
|
+
ctaButtonTarget: "_blank",
|
|
94
|
+
anchorId: "anchored-banner",
|
|
95
|
+
enableCountdownTimer: false,
|
|
96
|
+
countdownStartDateTime: "2026-07-10T00:00:00.000Z",
|
|
97
|
+
countdownEndDateTime: "2026-12-31T23:59:59.000Z",
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default meta;
|
|
102
|
+
type Story = StoryObj<typeof meta>;
|
|
103
|
+
|
|
104
|
+
export const Default: Story = {};
|
|
105
|
+
|
|
106
|
+
export const WithCountdownTimer: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
enableCountdownTimer: true,
|
|
109
|
+
countdownStartDateTime: new Date("2026-07-10T00:00:00.000Z").getTime() as unknown as string,
|
|
110
|
+
countdownEndDateTime: new Date("2026-12-31T23:59:59.000Z").getTime() as unknown as string,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const WithIcon: Story = {
|
|
115
|
+
args: {
|
|
116
|
+
iconName: "call",
|
|
117
|
+
ctaButtonLabel: "call (866) 445-8084",
|
|
118
|
+
ctaButtonLink: "tel:+1-866-445-8084",
|
|
119
|
+
backgroundColor: "green",
|
|
120
|
+
enableCountdownTimer: false,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const WithSuffixText: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
ctaSuffixText: "to order Kinetic today",
|
|
127
|
+
ctaButtonLabel: "call (866) 445-8084",
|
|
128
|
+
ctaButtonLink: "tel:+1-866-445-8084",
|
|
129
|
+
backgroundColor: "navy",
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const BackgroundNavy: Story = {
|
|
134
|
+
args: { backgroundColor: "navy" },
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const BackgroundYellow: Story = {
|
|
138
|
+
args: { backgroundColor: "yellow" },
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const BackgroundGreen: Story = {
|
|
142
|
+
args: { backgroundColor: "green" },
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const BackgroundPurple: Story = {
|
|
146
|
+
args: { backgroundColor: "purple" },
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const BackgroundBlue: Story = {
|
|
150
|
+
args: { backgroundColor: "blue" },
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const BackgroundWhite: Story = {
|
|
154
|
+
args: { backgroundColor: "white", boxShadow: true },
|
|
155
|
+
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ButtonProps } from "./types";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
AnimationWrapper,
|
|
6
|
+
DEFAULT_BUTTON_ANIMATION_TYPE,
|
|
7
|
+
} from "@shared/components/animation-wrapper";
|
|
5
8
|
import { BrandButton, ButtonVariantsT } from "@shared/components/brand-button";
|
|
6
9
|
import { Button as CoreButton } from "@shared/components/button";
|
|
7
10
|
import { Link } from "@shared/components/link";
|
|
@@ -35,8 +38,8 @@ export const Button: React.FC<ButtonProps> = props => {
|
|
|
35
38
|
size,
|
|
36
39
|
iconSize = 24,
|
|
37
40
|
preserveQueryParameters,
|
|
38
|
-
disableAnimation
|
|
39
|
-
animationType,
|
|
41
|
+
disableAnimation,
|
|
42
|
+
animationType = DEFAULT_BUTTON_ANIMATION_TYPE,
|
|
40
43
|
...rest
|
|
41
44
|
} = props;
|
|
42
45
|
|
|
@@ -51,6 +54,12 @@ export const Button: React.FC<ButtonProps> = props => {
|
|
|
51
54
|
cta: { ...props },
|
|
52
55
|
});
|
|
53
56
|
return React.isValidElement(checkPlansNode) ? (
|
|
57
|
+
// `disableAnimation` is passed through as-is (not defaulted to `false`).
|
|
58
|
+
// Animations are opt-in: when unset, AnimationWrapper falls back to its
|
|
59
|
+
// default of `true` (disabled), matching the CMS contract where an unset
|
|
60
|
+
// value means "no animation". This stays consistent with the other
|
|
61
|
+
// branches in this block. Animation runs only when a caller explicitly
|
|
62
|
+
// passes `disableAnimation={false}`.
|
|
54
63
|
<AnimationWrapper
|
|
55
64
|
disableAnimation={disableAnimation}
|
|
56
65
|
animationType={animationType}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import type { CalloutProps } from "./types";
|
|
2
|
+
|
|
3
|
+
/* Card Items */
|
|
4
|
+
|
|
5
|
+
export const defaultSimpleItems: CalloutProps["items"] = [
|
|
6
|
+
{
|
|
7
|
+
title: "ultra-fast fiber internet",
|
|
8
|
+
body: "Reliable high-speed internet for your home on our fiber-backed network.",
|
|
9
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/2tArpGyb6Pmog6tU972NRR/07761d8a230242e0e8e302dbc0345f5e/icon.svg",
|
|
10
|
+
imageAlt: "Purple speedometer",
|
|
11
|
+
imageWidth: 88,
|
|
12
|
+
imageHeight: 88,
|
|
13
|
+
iconAlignment: "left",
|
|
14
|
+
imageView: "standard",
|
|
15
|
+
cta: {
|
|
16
|
+
buttonLabel: "See options",
|
|
17
|
+
href: "/fiber-internet",
|
|
18
|
+
target: "_self",
|
|
19
|
+
showButtonAs: "text",
|
|
20
|
+
preserveQueryParameters: true,
|
|
21
|
+
},
|
|
22
|
+
ctaAlignment: "left",
|
|
23
|
+
showBackgroundImage: true,
|
|
24
|
+
// Blog-compatible fields
|
|
25
|
+
shortDescription: "Reliable high-speed internet for your home on our fiber-backed network.",
|
|
26
|
+
slug: "/fiber-internet",
|
|
27
|
+
blogCreationDate: "2026-01-15",
|
|
28
|
+
category: "Internet",
|
|
29
|
+
cover: { src: "https://images.ctfassets.net/8d4yn2ywtegc/17t6o3lIEE1OmyRtK2LSiN/7c00763e6afc39e97492c8aa3a3e5260/image_390.jpg", alt: "Fiber internet", width: 1920, height: 1281 },
|
|
30
|
+
// FullImage / FloatingImage-compatible fields
|
|
31
|
+
description: "Reliable high-speed internet for your home on our fiber-backed network.",
|
|
32
|
+
caption: "Fiber-backed network",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: "tv and entertainment",
|
|
36
|
+
body: "Start streaming with best-in-class live entertainment.",
|
|
37
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/2XHS5ndV3g8qq4GmDxdmai/911b3dcfe6ba2240dd09b4d4153390a5/icon-1.svg",
|
|
38
|
+
imageAlt: "Green streaming play",
|
|
39
|
+
imageWidth: 88,
|
|
40
|
+
imageHeight: 88,
|
|
41
|
+
iconAlignment: "left",
|
|
42
|
+
imageView: "standard",
|
|
43
|
+
cta: {
|
|
44
|
+
buttonLabel: "See options",
|
|
45
|
+
href: "/products",
|
|
46
|
+
target: "_self",
|
|
47
|
+
showButtonAs: "text",
|
|
48
|
+
preserveQueryParameters: true,
|
|
49
|
+
},
|
|
50
|
+
ctaAlignment: "left",
|
|
51
|
+
// Blog-compatible fields
|
|
52
|
+
shortDescription: "Start streaming with best-in-class live entertainment.",
|
|
53
|
+
slug: "/products",
|
|
54
|
+
blogCreationDate: "2026-02-20",
|
|
55
|
+
category: "Entertainment",
|
|
56
|
+
cover: { src: "https://images.ctfassets.net/8d4yn2ywtegc/2QoSoX9jUc6G8Tvg007MI0/7ae950e16d2ac83ff75b992dc9e24c37/image_388.jpg", alt: "TV entertainment", width: 1920, height: 1281 },
|
|
57
|
+
// FullImage / FloatingImage-compatible fields
|
|
58
|
+
description: "Start streaming with best-in-class live entertainment.",
|
|
59
|
+
caption: "Live entertainment",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
title: "voice services",
|
|
63
|
+
body: "Unlimited nationwide voice calling with Kinetic phone service.",
|
|
64
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/1JPpHXSe3WcQBOSTHhK3YD/9398907485bc13a90e46df73a4c6634c/icon-2.svg",
|
|
65
|
+
imageAlt: "Blue phone",
|
|
66
|
+
imageWidth: 88,
|
|
67
|
+
imageHeight: 88,
|
|
68
|
+
iconAlignment: "left",
|
|
69
|
+
imageView: "standard",
|
|
70
|
+
cta: {
|
|
71
|
+
buttonLabel: "See options",
|
|
72
|
+
href: "/home-phone",
|
|
73
|
+
target: "_self",
|
|
74
|
+
showButtonAs: "text",
|
|
75
|
+
preserveQueryParameters: true,
|
|
76
|
+
},
|
|
77
|
+
ctaAlignment: "left",
|
|
78
|
+
// Blog-compatible fields
|
|
79
|
+
shortDescription: "Unlimited nationwide voice calling with Kinetic phone service.",
|
|
80
|
+
slug: "/home-phone",
|
|
81
|
+
blogCreationDate: "2026-03-10",
|
|
82
|
+
category: "Phone",
|
|
83
|
+
cover: { src: "https://images.ctfassets.net/8d4yn2ywtegc/6CVKQrlrmcuNyefT6jM96d/8264de217e3822c0e7284c823c57314c/image_391.jpg", alt: "Voice services", width: 1920, height: 1280 },
|
|
84
|
+
// FullImage / FloatingImage-compatible fields
|
|
85
|
+
description: "Unlimited nationwide voice calling with Kinetic phone service.",
|
|
86
|
+
caption: "Nationwide calling",
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
/* Floating Image Card Items */
|
|
91
|
+
|
|
92
|
+
export const floatingImageItems: CalloutProps["items"] = [
|
|
93
|
+
{
|
|
94
|
+
cardType: "floatingImage",
|
|
95
|
+
title: "pick your favorite video conferencing spot",
|
|
96
|
+
body: "Our technicians can ensure Wi-Fi reaches your home office with optimal connectivity.",
|
|
97
|
+
image: {
|
|
98
|
+
href: "https://images.ctfassets.net/8d4yn2ywtegc/17t6o3lIEE1OmyRtK2LSiN/7c00763e6afc39e97492c8aa3a3e5260/image_390.jpg",
|
|
99
|
+
title: "Pick your favorite spot",
|
|
100
|
+
width: 1920,
|
|
101
|
+
height: 1281,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
cardType: "floatingImage",
|
|
106
|
+
title: "stream and game from anywhere",
|
|
107
|
+
body: "Strong Wi-Fi throughout your whole home means you can enjoy your favorite movies, sports, and video games from every room.",
|
|
108
|
+
image: {
|
|
109
|
+
href: "https://images.ctfassets.net/8d4yn2ywtegc/2QoSoX9jUc6G8Tvg007MI0/7ae950e16d2ac83ff75b992dc9e24c37/image_388.jpg",
|
|
110
|
+
title: "Stream and game from anywhere",
|
|
111
|
+
width: 1920,
|
|
112
|
+
height: 1281,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
cardType: "floatingImage",
|
|
117
|
+
title: "manage your smart home",
|
|
118
|
+
body: "Let our technicians know what smart devices you need connected during your Wi-Fi installation for seamless coverage.",
|
|
119
|
+
image: {
|
|
120
|
+
href: "https://images.ctfassets.net/8d4yn2ywtegc/6CVKQrlrmcuNyefT6jM96d/8264de217e3822c0e7284c823c57314c/image_391.jpg",
|
|
121
|
+
title: "Brother and sister smart home",
|
|
122
|
+
width: 1920,
|
|
123
|
+
height: 1280,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
/* Full Image Card Items */
|
|
129
|
+
|
|
130
|
+
export const fullImageItems: CalloutProps["items"] = [
|
|
131
|
+
{
|
|
132
|
+
cardType: "fullImage",
|
|
133
|
+
title: "Stream in 4K",
|
|
134
|
+
description: "Crystal clear entertainment on every device.",
|
|
135
|
+
caption: "Starting at $49/mo",
|
|
136
|
+
image: {
|
|
137
|
+
href: "https://images.ctfassets.net/8d4yn2ywtegc/2QoSoX9jUc6G8Tvg007MI0/7ae950e16d2ac83ff75b992dc9e24c37/image_388.jpg",
|
|
138
|
+
title: "Streaming",
|
|
139
|
+
width: 1920,
|
|
140
|
+
height: 1281,
|
|
141
|
+
},
|
|
142
|
+
cta: {
|
|
143
|
+
buttonLabel: "Learn more",
|
|
144
|
+
href: "/streaming",
|
|
145
|
+
showButtonAs: "solid",
|
|
146
|
+
buttonVariant: "primary_brand",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
cardType: "fullImage",
|
|
151
|
+
title: "Work From Home",
|
|
152
|
+
description: "Stay productive with reliable, fast internet.",
|
|
153
|
+
caption: "Starting at $59/mo",
|
|
154
|
+
image: {
|
|
155
|
+
href: "https://images.ctfassets.net/8d4yn2ywtegc/17t6o3lIEE1OmyRtK2LSiN/7c00763e6afc39e97492c8aa3a3e5260/image_390.jpg",
|
|
156
|
+
title: "Work from home",
|
|
157
|
+
width: 1920,
|
|
158
|
+
height: 1281,
|
|
159
|
+
},
|
|
160
|
+
cta: {
|
|
161
|
+
buttonLabel: "See plans",
|
|
162
|
+
href: "/plans",
|
|
163
|
+
showButtonAs: "solid",
|
|
164
|
+
buttonVariant: "primary_brand",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
cardType: "fullImage",
|
|
169
|
+
title: "Game Online",
|
|
170
|
+
description: "Low latency for competitive gaming.",
|
|
171
|
+
caption: "Starting at $69/mo",
|
|
172
|
+
image: {
|
|
173
|
+
href: "https://images.ctfassets.net/8d4yn2ywtegc/6CVKQrlrmcuNyefT6jM96d/8264de217e3822c0e7284c823c57314c/image_391.jpg",
|
|
174
|
+
title: "Gaming",
|
|
175
|
+
width: 1920,
|
|
176
|
+
height: 1280,
|
|
177
|
+
},
|
|
178
|
+
cta: {
|
|
179
|
+
buttonLabel: "Get started",
|
|
180
|
+
href: "/gaming",
|
|
181
|
+
showButtonAs: "solid",
|
|
182
|
+
buttonVariant: "primary_brand",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
/* Blog Card Items */
|
|
188
|
+
|
|
189
|
+
export const blogItems: CalloutProps["items"] = [
|
|
190
|
+
{
|
|
191
|
+
cardType: "blog",
|
|
192
|
+
title: "How to Choose the Right Internet Plan",
|
|
193
|
+
shortDescription: "A guide to picking the best plan for your needs.",
|
|
194
|
+
blogCreationDate: "2026-01-15",
|
|
195
|
+
category: "Guides",
|
|
196
|
+
slug: "/blog/choose-internet-plan",
|
|
197
|
+
cover: {
|
|
198
|
+
src: "https://images.ctfassets.net/8d4yn2ywtegc/17t6o3lIEE1OmyRtK2LSiN/7c00763e6afc39e97492c8aa3a3e5260/image_390.jpg",
|
|
199
|
+
alt: "Internet plan guide",
|
|
200
|
+
width: 1920,
|
|
201
|
+
height: 1281,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
cardType: "blog",
|
|
206
|
+
title: "Top 5 Tips for Faster Wi-Fi",
|
|
207
|
+
shortDescription: "Simple tricks to boost your home network speed.",
|
|
208
|
+
blogCreationDate: "2026-02-20",
|
|
209
|
+
category: "Tips",
|
|
210
|
+
slug: "/blog/faster-wifi-tips",
|
|
211
|
+
cover: {
|
|
212
|
+
src: "https://images.ctfassets.net/8d4yn2ywtegc/2QoSoX9jUc6G8Tvg007MI0/7ae950e16d2ac83ff75b992dc9e24c37/image_388.jpg",
|
|
213
|
+
alt: "Wi-Fi tips",
|
|
214
|
+
width: 1920,
|
|
215
|
+
height: 1281,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
cardType: "blog",
|
|
220
|
+
title: "Understanding Fiber Optic Internet",
|
|
221
|
+
shortDescription: "Everything you need to know about fiber technology.",
|
|
222
|
+
blogCreationDate: "2026-03-10",
|
|
223
|
+
category: "Technology",
|
|
224
|
+
slug: "/blog/fiber-optic-internet",
|
|
225
|
+
cover: {
|
|
226
|
+
src: "https://images.ctfassets.net/8d4yn2ywtegc/6CVKQrlrmcuNyefT6jM96d/8264de217e3822c0e7284c823c57314c/image_391.jpg",
|
|
227
|
+
alt: "Fiber optic technology",
|
|
228
|
+
width: 1920,
|
|
229
|
+
height: 1280,
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
/* Default Callout Args */
|
|
235
|
+
|
|
236
|
+
export const defaultCalloutArgs: Partial<CalloutProps> = {
|
|
237
|
+
title: "whatever you need, Kinetic can deliver",
|
|
238
|
+
subtitle:
|
|
239
|
+
"We're not just delivering high-speed internet. We're delivering it with local care, backed by people who live and work right here in your community. That means service you can count on and people you can trust.",
|
|
240
|
+
items: defaultSimpleItems,
|
|
241
|
+
cardType: "simple",
|
|
242
|
+
cardStackingMobile: true,
|
|
243
|
+
backgroundColor: "white",
|
|
244
|
+
textColor: "#00002d",
|
|
245
|
+
cardsWidth: true,
|
|
246
|
+
maxCardsPerRow: 3,
|
|
247
|
+
applyBoxShadow: false,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/* Floating Image Callout Args — mirrors martech */
|
|
251
|
+
|
|
252
|
+
export const withFloatingImageArgs: Partial<CalloutProps> = {
|
|
253
|
+
anchorId: "callout",
|
|
254
|
+
title: "we'll connect your devices, so you don't have to",
|
|
255
|
+
subtitle:
|
|
256
|
+
"With Kinetic's Whole Home Wi-Fi Set Up, our technicians ensure you can get online quickly from any device, anywhere in your home.",
|
|
257
|
+
items: floatingImageItems,
|
|
258
|
+
cardType: "floatingImage",
|
|
259
|
+
cardStackingMobile: true,
|
|
260
|
+
background: "#fff",
|
|
261
|
+
textColor: "#00002D",
|
|
262
|
+
maxCardsPerRow: 3,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/* Four Column Items */
|
|
266
|
+
|
|
267
|
+
export const fourColumnItems: CalloutProps["items"] = [
|
|
268
|
+
{
|
|
269
|
+
title: "1 Gig Internet",
|
|
270
|
+
body: "Download speeds up to 1 Gbps for the ultimate connected home.",
|
|
271
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/2tArpGyb6Pmog6tU972NRR/07761d8a230242e0e8e302dbc0345f5e/icon.svg",
|
|
272
|
+
imageAlt: "Purple speedometer",
|
|
273
|
+
imageWidth: 88,
|
|
274
|
+
imageHeight: 88,
|
|
275
|
+
iconAlignment: "center",
|
|
276
|
+
imageView: "icon",
|
|
277
|
+
cta: { buttonLabel: "View plan", href: "/plans/1gig", showButtonAs: "text" },
|
|
278
|
+
ctaAlignment: "center",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
title: "500 Mbps Internet",
|
|
282
|
+
body: "Fast enough for streaming, gaming, and video calls simultaneously.",
|
|
283
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/2XHS5ndV3g8qq4GmDxdmai/911b3dcfe6ba2240dd09b4d4153390a5/icon-1.svg",
|
|
284
|
+
imageAlt: "Green streaming play",
|
|
285
|
+
imageWidth: 88,
|
|
286
|
+
imageHeight: 88,
|
|
287
|
+
iconAlignment: "center",
|
|
288
|
+
imageView: "icon",
|
|
289
|
+
cta: { buttonLabel: "View plan", href: "/plans/500", showButtonAs: "text" },
|
|
290
|
+
ctaAlignment: "center",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
title: "300 Mbps Internet",
|
|
294
|
+
body: "Great for households with multiple connected devices.",
|
|
295
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/1JPpHXSe3WcQBOSTHhK3YD/9398907485bc13a90e46df73a4c6634c/icon-2.svg",
|
|
296
|
+
imageAlt: "Blue phone",
|
|
297
|
+
imageWidth: 88,
|
|
298
|
+
imageHeight: 88,
|
|
299
|
+
iconAlignment: "center",
|
|
300
|
+
imageView: "icon",
|
|
301
|
+
cta: { buttonLabel: "View plan", href: "/plans/300", showButtonAs: "text" },
|
|
302
|
+
ctaAlignment: "center",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
title: "100 Mbps Internet",
|
|
306
|
+
body: "Reliable everyday internet for browsing and email.",
|
|
307
|
+
image: "https://images.ctfassets.net/8d4yn2ywtegc/2tArpGyb6Pmog6tU972NRR/07761d8a230242e0e8e302dbc0345f5e/icon.svg",
|
|
308
|
+
imageAlt: "Purple speedometer",
|
|
309
|
+
imageWidth: 88,
|
|
310
|
+
imageHeight: 88,
|
|
311
|
+
iconAlignment: "center",
|
|
312
|
+
imageView: "icon",
|
|
313
|
+
cta: { buttonLabel: "View plan", href: "/plans/100", showButtonAs: "text" },
|
|
314
|
+
ctaAlignment: "center",
|
|
315
|
+
},
|
|
316
|
+
];
|
|
317
|
+
|
|
318
|
+
/* Six Column Items */
|
|
319
|
+
|
|
320
|
+
export const sixColumnItems: CalloutProps["items"] = [
|
|
321
|
+
{ title: "Speed", body: "Up to 1 Gbps fiber speeds." },
|
|
322
|
+
{ title: "Reliability", body: "99.9% uptime guaranteed." },
|
|
323
|
+
{ title: "Support", body: "24/7 local customer care." },
|
|
324
|
+
{ title: "Value", body: "No hidden fees or contracts." },
|
|
325
|
+
{ title: "Security", body: "Built-in network protection." },
|
|
326
|
+
{ title: "Flexibility", body: "Upgrade anytime, no penalty." },
|
|
327
|
+
];
|