@windstream/react-shared-components 0.2.31 → 0.2.33
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 +4 -1
- package/dist/contentful/index.esm.js +2 -2
- 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/index.esm.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/next/index.esm.js.map +1 -1
- package/dist/next/index.js.map +1 -1
- package/dist/styles.css +1 -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/contentful/blocks/blogs-grid-base/index.tsx +16 -3
- package/src/contentful/blocks/blogs-grid-base/types.ts +3 -0
- package/src/contentful/blocks/cards/blog-card/index.tsx +64 -53
- package/src/hooks/contentful/use-contentful-rich-text.tsx +6 -2
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import { BlogCard } from "@shared/contentful/blocks/cards/blog-card";
|
|
|
7
7
|
|
|
8
8
|
export function BlogGridBase({
|
|
9
9
|
title = "recent articles",
|
|
10
|
+
description,
|
|
10
11
|
paginatedArticles,
|
|
11
12
|
totalArticles,
|
|
12
13
|
currentPage,
|
|
@@ -16,6 +17,7 @@ export function BlogGridBase({
|
|
|
16
17
|
onCategoryChange,
|
|
17
18
|
onPageChange,
|
|
18
19
|
getPageHref,
|
|
20
|
+
asList = false,
|
|
19
21
|
imageComponent,
|
|
20
22
|
}: BlogGridBaseProps) {
|
|
21
23
|
function handleCategoryChange(value: unknown) {
|
|
@@ -36,10 +38,14 @@ export function BlogGridBase({
|
|
|
36
38
|
>
|
|
37
39
|
{/* Controls bar */}
|
|
38
40
|
<div className="mx-auto flex max-w-[1200px] flex-wrap items-center justify-between gap-3 px-6 pb-6">
|
|
41
|
+
{description && (
|
|
42
|
+
<Text as="p" className="body1 mb-4 text-center md:mb-6">
|
|
43
|
+
{description}
|
|
44
|
+
</Text>
|
|
45
|
+
)}
|
|
39
46
|
<Text className="w-full text-center text-heading5 font-black lowercase text-text-secondary md:w-auto md:text-left">
|
|
40
47
|
{title}
|
|
41
48
|
</Text>
|
|
42
|
-
|
|
43
49
|
{categoryOptions.length > 0 && (
|
|
44
50
|
<div className="flex w-full flex-col-reverse gap-3 md:w-auto md:flex-row md:items-center md:gap-6">
|
|
45
51
|
{/* Showing count */}
|
|
@@ -66,9 +72,15 @@ export function BlogGridBase({
|
|
|
66
72
|
)}
|
|
67
73
|
</div>
|
|
68
74
|
|
|
69
|
-
{/* Articles grid */}
|
|
75
|
+
{/* Articles grid / list */}
|
|
70
76
|
{paginatedArticles.length > 0 ? (
|
|
71
|
-
<div
|
|
77
|
+
<div
|
|
78
|
+
className={
|
|
79
|
+
asList
|
|
80
|
+
? "mx-auto flex max-w-[1200px] flex-col gap-1 px-5 pb-16"
|
|
81
|
+
: "mx-auto grid max-w-[1200px] grid-cols-1 gap-6 px-5 pb-16 sm:grid-cols-2 lg:grid-cols-3"
|
|
82
|
+
}
|
|
83
|
+
>
|
|
72
84
|
{paginatedArticles.map((article, index) => {
|
|
73
85
|
const href = article.slug.startsWith("/")
|
|
74
86
|
? article.slug
|
|
@@ -95,6 +107,7 @@ export function BlogGridBase({
|
|
|
95
107
|
category={article.category}
|
|
96
108
|
image={coverImage}
|
|
97
109
|
imageComponent={imageComponent}
|
|
110
|
+
asGrid={!asList}
|
|
98
111
|
index={index}
|
|
99
112
|
/>
|
|
100
113
|
);
|
|
@@ -18,6 +18,7 @@ export interface BlogCardProps {
|
|
|
18
18
|
|
|
19
19
|
export interface BlogGridBaseProps {
|
|
20
20
|
title?: string;
|
|
21
|
+
description?: string;
|
|
21
22
|
paginatedArticles: BlogCardProps[];
|
|
22
23
|
totalArticles: number;
|
|
23
24
|
currentPage: number;
|
|
@@ -27,6 +28,8 @@ export interface BlogGridBaseProps {
|
|
|
27
28
|
onCategoryChange?: (category: BlogCategoryOption) => void;
|
|
28
29
|
onPageChange?: (page: number) => void;
|
|
29
30
|
getPageHref?: (page: number) => string;
|
|
31
|
+
/** When true, render cards in a single-column list instead of a grid. */
|
|
32
|
+
asList?: boolean;
|
|
30
33
|
/** Pass next/image's Image component here to enable image optimization */
|
|
31
34
|
imageComponent?: React.ComponentType<BlogCardImageProps>;
|
|
32
35
|
}
|
|
@@ -27,57 +27,66 @@ export const BlogCard: React.FC<BlogCardProps> = ({
|
|
|
27
27
|
}: BlogCardProps) => {
|
|
28
28
|
const parentClassName = asGrid
|
|
29
29
|
? "flex h-full flex-col overflow-hidden rounded-card-lg bg-white shadow-drop transition-all duration-200 hover:-translate-y-0.5 hover:shadow-cardDrop"
|
|
30
|
-
: `callout-card w-full flex h-full flex-col overflow-hidden
|
|
30
|
+
: `callout-card w-full flex h-full flex-col overflow-hidden`;
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<article
|
|
34
34
|
className={parentClassName}
|
|
35
35
|
data-section-type={"blog-card"}
|
|
36
36
|
data-section-index={index}
|
|
37
|
+
data-view-mode={asGrid ? "grid" : "list"}
|
|
37
38
|
>
|
|
38
|
-
{/* Image */}
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
{/* Image (hidden in list view) */}
|
|
40
|
+
{asGrid && (
|
|
41
|
+
<Link href={href} tabIndex={-1} aria-hidden="true" className="block">
|
|
42
|
+
<div className="h-[232px] w-full flex-shrink-0 overflow-hidden bg-gray-100">
|
|
43
|
+
{image ? (
|
|
44
|
+
ImageComponent ? (
|
|
45
|
+
<ImageComponent
|
|
46
|
+
src={image.src}
|
|
47
|
+
alt={image.alt}
|
|
48
|
+
width={image.width}
|
|
49
|
+
height={image.height}
|
|
50
|
+
className="h-full w-full object-cover transition-transform duration-300 hover:scale-[1.03]"
|
|
51
|
+
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
|
52
|
+
/>
|
|
53
|
+
) : (
|
|
54
|
+
<img
|
|
55
|
+
src={image.src}
|
|
56
|
+
alt={image.alt}
|
|
57
|
+
width={image.width}
|
|
58
|
+
height={image.height}
|
|
59
|
+
loading="lazy"
|
|
60
|
+
decoding="async"
|
|
61
|
+
className="h-full w-full object-cover transition-transform duration-300 hover:scale-[1.03]"
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
51
64
|
) : (
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
width={image.width}
|
|
56
|
-
height={image.height}
|
|
57
|
-
loading="lazy"
|
|
58
|
-
decoding="async"
|
|
59
|
-
className="h-full w-full object-cover transition-transform duration-300 hover:scale-[1.03]"
|
|
65
|
+
<div
|
|
66
|
+
className="h-full w-full bg-gradient-to-br from-gray-200 to-gray-100"
|
|
67
|
+
aria-hidden="true"
|
|
60
68
|
/>
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
aria-hidden="true"
|
|
66
|
-
/>
|
|
67
|
-
)}
|
|
68
|
-
</div>
|
|
69
|
-
</Link>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
</Link>
|
|
72
|
+
)}
|
|
70
73
|
|
|
71
74
|
{/* Body */}
|
|
72
|
-
<div
|
|
75
|
+
<div
|
|
76
|
+
className={`flex flex-1 flex-col ${
|
|
77
|
+
asGrid ? "gap-5 p-6 md:p-8" : "gap-1 border-b p-3 md:p-4"
|
|
78
|
+
}`}
|
|
79
|
+
>
|
|
73
80
|
{/* Meta: category + date */}
|
|
74
81
|
<div className="flex items-center gap-2 text-[13px]">
|
|
75
|
-
<span className="body2 text-text-brand">{category}</span>
|
|
82
|
+
{asGrid && <span className="body2 text-text-brand">{category}</span>}
|
|
76
83
|
{date && (
|
|
77
84
|
<>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
{asGrid && (
|
|
86
|
+
<span className="footnote text-text" aria-hidden="true">
|
|
87
|
+
•
|
|
88
|
+
</span>
|
|
89
|
+
)}
|
|
81
90
|
<time className="body2 text-text">{date}</time>
|
|
82
91
|
</>
|
|
83
92
|
)}
|
|
@@ -100,25 +109,27 @@ export const BlogCard: React.FC<BlogCardProps> = ({
|
|
|
100
109
|
</Text>
|
|
101
110
|
)}
|
|
102
111
|
|
|
103
|
-
{/* Read more */}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
>
|
|
109
|
-
<Text
|
|
112
|
+
{/* Read more (hidden in list view) */}
|
|
113
|
+
{asGrid && (
|
|
114
|
+
<Link
|
|
115
|
+
href={href}
|
|
116
|
+
className="group mt-auto inline-flex items-center justify-start gap-2 pt-3 text-sm text-text-brand no-underline"
|
|
110
117
|
aria-label={`${readMoreText} about ${title || "this article"}`}
|
|
111
|
-
className="label1 text-nowrap"
|
|
112
118
|
>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
<Text
|
|
120
|
+
aria-label={`${readMoreText} about ${title || "this article"}`}
|
|
121
|
+
className="label1 text-nowrap"
|
|
122
|
+
>
|
|
123
|
+
{readMoreText}
|
|
124
|
+
</Text>
|
|
125
|
+
<MaterialIcon
|
|
126
|
+
name="expand_circle_right"
|
|
127
|
+
fill={1}
|
|
128
|
+
size={24}
|
|
129
|
+
weight="200"
|
|
130
|
+
/>
|
|
131
|
+
</Link>
|
|
132
|
+
)}
|
|
122
133
|
</div>
|
|
123
134
|
</article>
|
|
124
135
|
);
|
|
@@ -33,7 +33,9 @@ const defaultOptions: Options = {
|
|
|
33
33
|
},
|
|
34
34
|
renderNode: {
|
|
35
35
|
[BLOCKS.PARAGRAPH]: (node, children) => (
|
|
36
|
-
<div className="body3 mb-4
|
|
36
|
+
<div className="body3 mb-4 whitespace-pre-line">
|
|
37
|
+
{isEmptyParagraph(node) ? "\n" : children}
|
|
38
|
+
</div>
|
|
37
39
|
),
|
|
38
40
|
[BLOCKS.HEADING_1]: (node, children) => {
|
|
39
41
|
return (
|
|
@@ -165,7 +167,9 @@ export function renderContentfulRichText(
|
|
|
165
167
|
...options?.renderNode,
|
|
166
168
|
// Logic for links based on the isTargetBlank flag
|
|
167
169
|
[BLOCKS.PARAGRAPH]: (node, children) => (
|
|
168
|
-
<div className={className
|
|
170
|
+
<div className={[className, "whitespace-pre-line"].filter(Boolean).join(" ")}>
|
|
171
|
+
{isEmptyParagraph(node) ? "\n" : children}
|
|
172
|
+
</div>
|
|
169
173
|
),
|
|
170
174
|
[INLINES.HYPERLINK]: (node, children) => {
|
|
171
175
|
const url = (node as any)?.data?.uri as string;
|