@contentgrowth/content-widget 1.3.1 → 1.3.3
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 +31 -0
- package/dist/astro/FeaturedCard.astro +188 -0
- package/dist/astro/FeaturedContent.astro +41 -37
- package/dist/react/FeaturedCard.d.ts +57 -0
- package/dist/react/FeaturedCard.d.ts.map +1 -0
- package/dist/react/FeaturedCard.js +78 -0
- package/dist/react/FeaturedContent.d.ts.map +1 -1
- package/dist/react/FeaturedContent.js +21 -16
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/styles.css +264 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/vue/FeaturedCard.vue +132 -0
- package/dist/vue/FeaturedContent.vue +42 -36
- package/dist/widget/widget.css +1 -1
- package/dist/widget/widget.dev.css +264 -3
- package/dist/widget/widget.dev.js +3 -3
- package/dist/widget/widget.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -268,6 +268,37 @@ const widget = new ContentGrowthWidget(container, {
|
|
|
268
268
|
/>
|
|
269
269
|
```
|
|
270
270
|
|
|
271
|
+
**FeaturedCard:**
|
|
272
|
+
|
|
273
|
+
A compact card displaying the Featured Summary with customizable styling. Perfect for landing pages.
|
|
274
|
+
|
|
275
|
+
```astro
|
|
276
|
+
<FeaturedCard
|
|
277
|
+
apiKey="pk_your_key_here"
|
|
278
|
+
category="announce"
|
|
279
|
+
linkPattern="/articles/{slug}"
|
|
280
|
+
layout="horizontal"
|
|
281
|
+
borderStyle="dashed"
|
|
282
|
+
itemsBackground="#f3f4f6"
|
|
283
|
+
ctaText="Read full story"
|
|
284
|
+
/>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
| Prop | Type | Default | Description |
|
|
288
|
+
|------|------|---------|-------------|
|
|
289
|
+
| `apiKey` | string | - | Your API key |
|
|
290
|
+
| `category` | string | - | Filter by category |
|
|
291
|
+
| `tags` | string[] | [] | Filter by tags |
|
|
292
|
+
| `layout` | 'vertical' \| 'horizontal' | auto | Card layout (auto uses article setting) |
|
|
293
|
+
| `borderStyle` | 'none' \| 'line' \| 'dashed' | 'none' | Card border style |
|
|
294
|
+
| `borderColor` | string | '#e5e7eb' | Border color (CSS value) |
|
|
295
|
+
| `cardBackground` | string | 'none' | Card background ('none' = transparent) |
|
|
296
|
+
| `itemsBackground` | string | '#f3f4f6' | Background for list/quote section |
|
|
297
|
+
| `ctaText` | string | 'Read full story' | Call-to-action text |
|
|
298
|
+
| `showAuthor` | boolean | false | Show author name |
|
|
299
|
+
| `showReadingTime` | boolean | false | Show reading time |
|
|
300
|
+
| `linkPattern` | string | '/articles/{slug}' | URL pattern for link |
|
|
301
|
+
|
|
271
302
|
## API Client
|
|
272
303
|
|
|
273
304
|
### ContentGrowthClient
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import { ContentGrowthClient } from '../core/client';
|
|
4
|
+
import type { FeaturedContentProps } from '../types';
|
|
5
|
+
|
|
6
|
+
interface FeaturedCardProps extends Omit<FeaturedContentProps, 'showBackButton' | 'backUrl'> {
|
|
7
|
+
/**
|
|
8
|
+
* URL pattern for the article link
|
|
9
|
+
* Supports placeholders: {uuid}, {slug}, {category}
|
|
10
|
+
* @default '/articles/{slug}'
|
|
11
|
+
*/
|
|
12
|
+
linkPattern?: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Show reading time
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
showReadingTime?: boolean;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Show author
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
showAuthor?: boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Text for the Call to Action link
|
|
28
|
+
* @default "Read full story"
|
|
29
|
+
*/
|
|
30
|
+
ctaText?: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Layout override (defaults to article settings)
|
|
34
|
+
*/
|
|
35
|
+
layout?: 'vertical' | 'horizontal';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Border style
|
|
39
|
+
* @default 'none'
|
|
40
|
+
*/
|
|
41
|
+
borderStyle?: 'none' | 'line' | 'dashed';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Border color (CSS color value)
|
|
45
|
+
* @default '#e5e7eb'
|
|
46
|
+
*/
|
|
47
|
+
borderColor?: string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Card background color (CSS color value, 'none' for transparent)
|
|
51
|
+
* @default 'none'
|
|
52
|
+
*/
|
|
53
|
+
cardBackground?: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Background color for list/quote section (the items area)
|
|
57
|
+
* @default '#f3f4f6'
|
|
58
|
+
*/
|
|
59
|
+
itemsBackground?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type Props = FeaturedCardProps & { class?: string };
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
apiKey,
|
|
66
|
+
baseUrl,
|
|
67
|
+
tags = [],
|
|
68
|
+
category,
|
|
69
|
+
excludeTags = [],
|
|
70
|
+
showCategory = true,
|
|
71
|
+
showReadingTime = false,
|
|
72
|
+
showAuthor = false,
|
|
73
|
+
ctaText = 'Read full story',
|
|
74
|
+
linkPattern = '/articles/{slug}',
|
|
75
|
+
layout: propLayout,
|
|
76
|
+
borderStyle = 'none',
|
|
77
|
+
borderColor = '#e5e7eb',
|
|
78
|
+
cardBackground = 'none',
|
|
79
|
+
itemsBackground = '#f3f4f6',
|
|
80
|
+
class: className = ''
|
|
81
|
+
} = Astro.props;
|
|
82
|
+
|
|
83
|
+
// Fetch featured article
|
|
84
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
85
|
+
let article = null;
|
|
86
|
+
let error = null;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
article = await client.getFeaturedArticle({
|
|
90
|
+
tags,
|
|
91
|
+
category,
|
|
92
|
+
excludeTags
|
|
93
|
+
});
|
|
94
|
+
} catch (e) {
|
|
95
|
+
// If 404, article remains null
|
|
96
|
+
console.error('Failed to fetch featured article:', e);
|
|
97
|
+
error = e instanceof Error ? e.message : 'Failed to load featured article';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Generate article URL
|
|
101
|
+
const getArticleUrl = (article: any) => {
|
|
102
|
+
if (!article) return '#';
|
|
103
|
+
return linkPattern
|
|
104
|
+
.replace('{uuid}', article.uuid || '')
|
|
105
|
+
.replace('{slug}', article.slug || article.uuid || '')
|
|
106
|
+
.replace('{category}', article.category || 'uncategorized');
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Render featured summary (or fallback to regular summary) as HTML
|
|
110
|
+
const getSummaryHtml = (article: any) => {
|
|
111
|
+
const summaryText = article.featuredSummary || article.summary;
|
|
112
|
+
if (!summaryText) return '';
|
|
113
|
+
return marked.parse(summaryText, { async: false }) as string;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const layout = propLayout || article?.featuredSummaryLayout || 'standard';
|
|
117
|
+
const layoutClass = layout !== 'standard' ? `cg-layout-${layout}` : '';
|
|
118
|
+
const borderClass = borderStyle !== 'none' ? `cg-border-${borderStyle}` : '';
|
|
119
|
+
|
|
120
|
+
// Custom CSS properties for styling
|
|
121
|
+
const customStyles = [
|
|
122
|
+
borderColor !== '#e5e7eb' ? `--cg-card-border-color: ${borderColor}` : '',
|
|
123
|
+
cardBackground !== 'none' ? `--cg-card-bg: ${cardBackground}` : '',
|
|
124
|
+
itemsBackground !== '#f3f4f6' ? `--cg-items-bg: ${itemsBackground}` : '',
|
|
125
|
+
].filter(Boolean).join('; ');
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
{article ? (
|
|
129
|
+
<a
|
|
130
|
+
href={getArticleUrl(article)}
|
|
131
|
+
class={`cg-widget cg-featured-card ${className} ${layoutClass} ${borderClass}`}
|
|
132
|
+
style={customStyles || undefined}
|
|
133
|
+
data-cg-widget="featured-card"
|
|
134
|
+
>
|
|
135
|
+
<article class="cg-featured-card-inner">
|
|
136
|
+
{/* Header with category badge */}
|
|
137
|
+
{showCategory && article.category && (
|
|
138
|
+
<div class="cg-featured-card-category">
|
|
139
|
+
<span class="cg-category-badge">{article.category}</span>
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
{/* Title */}
|
|
144
|
+
<h3 class="cg-featured-card-title">{article.title}</h3>
|
|
145
|
+
|
|
146
|
+
{/* Featured Summary */}
|
|
147
|
+
{(article.featuredSummary || article.summary) && (
|
|
148
|
+
<div
|
|
149
|
+
class="cg-featured-card-summary"
|
|
150
|
+
set:html={getSummaryHtml(article)}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
{/* Footer with meta info */}
|
|
155
|
+
{(showAuthor || showReadingTime) && (
|
|
156
|
+
<div class="cg-featured-card-footer">
|
|
157
|
+
{showAuthor && <span class="cg-featured-card-author">{article.authorName}</span>}
|
|
158
|
+
|
|
159
|
+
{showAuthor && showReadingTime && (
|
|
160
|
+
<span class="cg-featured-card-separator">•</span>
|
|
161
|
+
)}
|
|
162
|
+
|
|
163
|
+
{showReadingTime && (
|
|
164
|
+
<span class="cg-featured-card-reading-time">
|
|
165
|
+
{Math.ceil(article.wordCount / 200)} min read
|
|
166
|
+
</span>
|
|
167
|
+
)}
|
|
168
|
+
</div>
|
|
169
|
+
)}
|
|
170
|
+
|
|
171
|
+
{/* Read more indicator */}
|
|
172
|
+
<div class="cg-featured-card-cta">
|
|
173
|
+
<span>{ctaText}</span>
|
|
174
|
+
<svg class="cg-featured-card-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24" width="16" height="16">
|
|
175
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
176
|
+
</svg>
|
|
177
|
+
</div>
|
|
178
|
+
</article>
|
|
179
|
+
</a>
|
|
180
|
+
) : (
|
|
181
|
+
error ? (
|
|
182
|
+
<div class={`cg-widget cg-error ${className}`}>
|
|
183
|
+
{error}
|
|
184
|
+
</div>
|
|
185
|
+
) : null
|
|
186
|
+
)}
|
|
187
|
+
|
|
188
|
+
|
|
@@ -39,45 +39,49 @@ const contentHtml = article ? marked(article.content) : '';
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
41
|
{article ? (
|
|
42
|
-
<div class={`cg-
|
|
43
|
-
<article
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
42
|
+
<div class={`cg-content-viewer ${className}`} data-cg-widget="post">
|
|
43
|
+
<article>
|
|
44
|
+
<header class="cg-content-header">
|
|
45
|
+
{showCategory && article.category && (
|
|
46
|
+
<div class="cg-content-category">
|
|
47
|
+
<span class="cg-category-badge">{article.category}</span>
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
|
|
51
|
+
<h1 class="cg-content-title">{article.title}</h1>
|
|
52
|
+
|
|
53
|
+
{showAiSummary && article.summary && (
|
|
54
|
+
<div class="cg-ai-summary">
|
|
55
|
+
<div class="cg-ai-summary-header">
|
|
56
|
+
<svg class="cg-ai-summary-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
57
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
58
|
+
</svg>
|
|
59
|
+
<span class="cg-ai-summary-label">AI Generated Summary</span>
|
|
60
|
+
</div>
|
|
61
|
+
<p class="cg-ai-summary-text">{article.summary}</p>
|
|
62
|
+
</div>
|
|
63
|
+
)}
|
|
64
|
+
|
|
65
|
+
<div class="cg-content-meta">
|
|
66
|
+
<span class="cg-info-author">{article.authorName}</span>
|
|
67
|
+
<span class="cg-info-separator">•</span>
|
|
68
|
+
<time class="cg-info-date" datetime={new Date(article.publishedAt * 1000).toISOString()}>
|
|
69
|
+
{new Date(article.publishedAt * 1000).toLocaleDateString()}
|
|
70
|
+
</time>
|
|
71
|
+
<span class="cg-info-separator">•</span>
|
|
72
|
+
<span class="cg-info-reading-time">{Math.ceil(article.wordCount / 200)} min read</span>
|
|
64
73
|
</div>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
|
|
75
|
+
{showTags && article.tags && article.tags.length > 0 && (
|
|
76
|
+
<div class="cg-content-tags">
|
|
77
|
+
{article.tags.map((tag: string) => (
|
|
78
|
+
<span class="cg-tag">{tag}</span>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</header>
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
{showTags && article.tags && article.tags.length > 0 && (
|
|
75
|
-
<div class="cg-article-tags">
|
|
76
|
-
{article.tags.map((tag: string) => (
|
|
77
|
-
<span class="cg-tag">#{tag}</span>
|
|
78
|
-
))}
|
|
79
|
-
</div>
|
|
80
|
-
)}
|
|
84
|
+
<div class="cg-content-body" set:html={contentHtml} />
|
|
81
85
|
</article>
|
|
82
86
|
</div>
|
|
83
87
|
) : (
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { FeaturedContentProps } from '../types';
|
|
3
|
+
interface FeaturedCardProps extends Omit<FeaturedContentProps, 'showBackButton' | 'backUrl' | 'showAiSummary' | 'showTags'> {
|
|
4
|
+
/**
|
|
5
|
+
* URL pattern for the article link
|
|
6
|
+
* Supports placeholders: {uuid}, {slug}, {category}
|
|
7
|
+
* @default '/articles/{slug}'
|
|
8
|
+
*/
|
|
9
|
+
linkPattern?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Show reading time
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
showReadingTime?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Show author
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
showAuthor?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Text for the Call to Action link
|
|
22
|
+
* @default "Read full story"
|
|
23
|
+
*/
|
|
24
|
+
ctaText?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Link target attribute
|
|
27
|
+
* @default undefined (same tab)
|
|
28
|
+
*/
|
|
29
|
+
linkTarget?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Layout override
|
|
32
|
+
*/
|
|
33
|
+
layout?: 'vertical' | 'horizontal';
|
|
34
|
+
/**
|
|
35
|
+
* Border style
|
|
36
|
+
* @default 'none'
|
|
37
|
+
*/
|
|
38
|
+
borderStyle?: 'none' | 'line' | 'dashed';
|
|
39
|
+
/**
|
|
40
|
+
* Border color (CSS color value)
|
|
41
|
+
* @default '#e5e7eb'
|
|
42
|
+
*/
|
|
43
|
+
borderColor?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Card background color (CSS color value, 'none' for transparent)
|
|
46
|
+
* @default 'none'
|
|
47
|
+
*/
|
|
48
|
+
cardBackground?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Background color for list/quote section (the items area)
|
|
51
|
+
* @default '#f3f4f6'
|
|
52
|
+
*/
|
|
53
|
+
itemsBackground?: string;
|
|
54
|
+
}
|
|
55
|
+
export declare const FeaturedCard: React.FC<FeaturedCardProps>;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=FeaturedCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeaturedCard.d.ts","sourceRoot":"","sources":["../../src/react/FeaturedCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,UAAU,CAAC;AAEzE,UAAU,iBAAkB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,GAAG,SAAS,GAAG,eAAe,GAAG,UAAU,CAAC;IACvH;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IAEnC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAEzC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA2IpD,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import { ContentGrowthClient } from '../core/client';
|
|
4
|
+
export const FeaturedCard = ({ apiKey, baseUrl, tags = [], category, excludeTags = [], showCategory = true, showReadingTime = false, showAuthor = false, ctaText = 'Read full story', linkPattern = '/articles/{slug}', linkTarget, layout: propLayout, borderStyle = 'none', borderColor = '#e5e7eb', cardBackground = 'none', itemsBackground = '#f3f4f6', className = '' }) => {
|
|
5
|
+
const [article, setArticle] = useState(null);
|
|
6
|
+
const [loading, setLoading] = useState(true);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const fetchArticle = async () => {
|
|
10
|
+
setLoading(true);
|
|
11
|
+
try {
|
|
12
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
13
|
+
const fetchedArticle = await client.getFeaturedArticle({
|
|
14
|
+
tags,
|
|
15
|
+
category,
|
|
16
|
+
excludeTags
|
|
17
|
+
});
|
|
18
|
+
setArticle(fetchedArticle);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
setError(err instanceof Error ? err.message : 'Failed to load featured article');
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
setLoading(false);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
fetchArticle();
|
|
28
|
+
}, [apiKey, baseUrl, category, JSON.stringify(tags), JSON.stringify(excludeTags)]);
|
|
29
|
+
// Generate article URL
|
|
30
|
+
const getArticleUrl = (article) => {
|
|
31
|
+
return linkPattern
|
|
32
|
+
.replace('{uuid}', article.uuid || '')
|
|
33
|
+
.replace('{slug}', article.slug || article.uuid || '')
|
|
34
|
+
.replace('{category}', article.category || 'uncategorized');
|
|
35
|
+
};
|
|
36
|
+
// Render featured summary (or fallback to regular summary) as HTML
|
|
37
|
+
const getSummaryHtml = (article) => {
|
|
38
|
+
const summaryText = article.featuredSummary || article.summary;
|
|
39
|
+
if (!summaryText)
|
|
40
|
+
return '';
|
|
41
|
+
return marked.parse(summaryText, { async: false });
|
|
42
|
+
};
|
|
43
|
+
if (loading) {
|
|
44
|
+
return (React.createElement("div", { className: `cg-widget cg-loading ${className}` },
|
|
45
|
+
React.createElement("div", { className: "cg-spinner" })));
|
|
46
|
+
}
|
|
47
|
+
if (error || !article) {
|
|
48
|
+
return (React.createElement("div", { className: `cg-widget cg-error ${className}` }, error || 'No featured content found'));
|
|
49
|
+
}
|
|
50
|
+
const summaryHtml = getSummaryHtml(article);
|
|
51
|
+
// Explicitly use any to access dynamic properties until types are fully updated
|
|
52
|
+
const layout = propLayout || article.featuredSummaryLayout || 'standard';
|
|
53
|
+
const readingTime = Math.ceil(article.wordCount / 200);
|
|
54
|
+
const borderClass = borderStyle !== 'none' ? `cg-border-${borderStyle}` : '';
|
|
55
|
+
const customStyles = {};
|
|
56
|
+
if (borderColor !== '#e5e7eb')
|
|
57
|
+
customStyles['--cg-card-border-color'] = borderColor;
|
|
58
|
+
if (cardBackground !== 'none')
|
|
59
|
+
customStyles['--cg-card-bg'] = cardBackground;
|
|
60
|
+
if (itemsBackground !== '#f3f4f6')
|
|
61
|
+
customStyles['--cg-items-bg'] = itemsBackground;
|
|
62
|
+
return (React.createElement("a", { href: getArticleUrl(article), className: `cg-widget cg-featured-card ${className} ${layout !== 'standard' ? `cg-layout-${layout}` : ''} ${borderClass}`, style: Object.keys(customStyles).length > 0 ? customStyles : undefined, "data-cg-widget": "featured-card", target: linkTarget, rel: linkTarget === '_blank' ? 'noopener noreferrer' : undefined },
|
|
63
|
+
React.createElement("article", { className: "cg-featured-card-inner" },
|
|
64
|
+
showCategory && article.category && (React.createElement("div", { className: "cg-featured-card-category" },
|
|
65
|
+
React.createElement("span", { className: "cg-category-badge" }, article.category))),
|
|
66
|
+
React.createElement("h3", { className: "cg-featured-card-title" }, article.title),
|
|
67
|
+
summaryHtml && (React.createElement("div", { className: "cg-featured-card-summary", dangerouslySetInnerHTML: { __html: summaryHtml } })),
|
|
68
|
+
(showAuthor || showReadingTime) && (React.createElement("div", { className: "cg-featured-card-footer" },
|
|
69
|
+
showAuthor && React.createElement("span", { className: "cg-featured-card-author" }, article.authorName),
|
|
70
|
+
showAuthor && showReadingTime && (React.createElement("span", { className: "cg-featured-card-separator" }, "\u2022")),
|
|
71
|
+
showReadingTime && (React.createElement("span", { className: "cg-featured-card-reading-time" },
|
|
72
|
+
readingTime,
|
|
73
|
+
" min read")))),
|
|
74
|
+
React.createElement("div", { className: "cg-featured-card-cta" },
|
|
75
|
+
React.createElement("span", null, ctaText),
|
|
76
|
+
React.createElement("svg", { className: "cg-featured-card-arrow", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", width: "16", height: "16" },
|
|
77
|
+
React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 5l7 7-7 7" }))))));
|
|
78
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeaturedContent.d.ts","sourceRoot":"","sources":["../../src/react/FeaturedContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,UAAU,CAAC;AAEzE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"FeaturedContent.d.ts","sourceRoot":"","sources":["../../src/react/FeaturedContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,UAAU,CAAC;AAEzE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+G1D,CAAC"}
|
|
@@ -40,21 +40,26 @@ export const FeaturedContent = ({ apiKey, baseUrl, tags = [], category, excludeT
|
|
|
40
40
|
// For now render standard error container
|
|
41
41
|
return (React.createElement("div", { className: `cg-widget cg-error ${className}` }, error || 'No featured content found'));
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
React.createElement("span", { className: "cg-
|
|
50
|
-
|
|
51
|
-
Math.ceil(article.wordCount / 200),
|
|
52
|
-
" min read")),
|
|
43
|
+
const contentHtml = marked(article.content);
|
|
44
|
+
const publishedDate = new Date(article.publishedAt * 1000).toLocaleDateString();
|
|
45
|
+
const readingTime = `${Math.ceil(article.wordCount / 200)} min read`;
|
|
46
|
+
return (React.createElement("article", { className: `cg-content-viewer ${className}`, "data-cg-widget": "post" },
|
|
47
|
+
React.createElement("header", { className: "cg-content-header" },
|
|
48
|
+
showCategory && article.category && (React.createElement("div", { className: "cg-content-category" },
|
|
49
|
+
React.createElement("span", { className: "cg-category-badge" }, article.category))),
|
|
50
|
+
React.createElement("h1", { className: "cg-content-title" }, article.title),
|
|
53
51
|
showAiSummary && article.summary && (React.createElement("div", { className: "cg-ai-summary" },
|
|
54
|
-
React.createElement("div", { className: "cg-ai-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
52
|
+
React.createElement("div", { className: "cg-ai-summary-header" },
|
|
53
|
+
React.createElement("svg", { className: "cg-ai-summary-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
|
|
54
|
+
React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M13 10V3L4 14h7v7l9-11h-7z" })),
|
|
55
|
+
React.createElement("span", { className: "cg-ai-summary-label" }, "AI Generated Summary")),
|
|
56
|
+
React.createElement("p", { className: "cg-ai-summary-text" }, article.summary))),
|
|
57
|
+
React.createElement("div", { className: "cg-content-meta" },
|
|
58
|
+
React.createElement("span", { className: "cg-info-author" }, article.authorName),
|
|
59
|
+
React.createElement("span", { className: "cg-info-separator" }, "\u2022"),
|
|
60
|
+
React.createElement("time", { className: "cg-info-date", dateTime: new Date(article.publishedAt * 1000).toISOString() }, publishedDate),
|
|
61
|
+
React.createElement("span", { className: "cg-info-separator" }, "\u2022"),
|
|
62
|
+
React.createElement("span", { className: "cg-info-reading-time" }, readingTime)),
|
|
63
|
+
showTags && article.tags && article.tags.length > 0 && (React.createElement("div", { className: "cg-content-tags" }, article.tags.map(tag => (React.createElement("span", { key: tag, className: "cg-tag" }, tag)))))),
|
|
64
|
+
React.createElement("div", { className: "cg-content-body", dangerouslySetInnerHTML: { __html: contentHtml } })));
|
|
60
65
|
};
|
package/dist/react/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export { ContentList } from './ContentList.js';
|
|
5
5
|
export { ContentViewer } from './ContentViewer.js';
|
|
6
6
|
export { FeaturedContent } from './FeaturedContent.js';
|
|
7
|
+
export { FeaturedCard } from './FeaturedCard.js';
|
|
7
8
|
export * from './hooks.js';
|
|
8
9
|
export type { ReactContentListProps } from './ContentList.js';
|
|
9
10
|
export type { ReactContentViewerProps } from './ContentViewer.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,cAAc,YAAY,CAAC;AAE3B,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,cAAc,YAAY,CAAC;AAE3B,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/react/index.js
CHANGED