@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 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-widget cg-content-viewer ${className}`}>
43
- <article class="cg-article">
44
- {showCategory && article.category && (
45
- <div class="cg-article-category">{article.category}</div>
46
- )}
47
-
48
- <h1 class="cg-article-title">{article.title}</h1>
49
-
50
- <div class="cg-article-meta">
51
- <span class="cg-author">{article.authorName}</span>
52
- <span class="cg-date">
53
- {new Date(article.publishedAt * 1000).toLocaleDateString()}
54
- </span>
55
- <span class="cg-read-time">
56
- {Math.ceil(article.wordCount / 200)} min read
57
- </span>
58
- </div>
59
-
60
- {showAiSummary && article.summary && (
61
- <div class="cg-ai-summary">
62
- <div class="cg-ai-label">AI Summary</div>
63
- <p>{article.summary}</p>
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
- {/* Content */}
68
- <div
69
- class="cg-article-content"
70
- set:html={contentHtml}
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
- {/* Tags */}
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,CAsG1D,CAAC"}
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
- return (React.createElement("div", { className: `cg-widget cg-content-viewer ${className}` },
44
- React.createElement("article", { className: "cg-article" },
45
- showCategory && article.category && (React.createElement("div", { className: "cg-article-category" }, article.category)),
46
- React.createElement("h1", { className: "cg-article-title" }, article.title),
47
- React.createElement("div", { className: "cg-article-meta" },
48
- React.createElement("span", { className: "cg-author" }, article.authorName),
49
- React.createElement("span", { className: "cg-date" }, new Date(article.publishedAt * 1000).toLocaleDateString()),
50
- React.createElement("span", { className: "cg-read-time" },
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-label" }, "AI Summary"),
55
- React.createElement("p", null, article.summary))),
56
- React.createElement("div", { className: "cg-article-content", dangerouslySetInnerHTML: { __html: marked(article.content) } }),
57
- showTags && article.tags && article.tags.length > 0 && (React.createElement("div", { className: "cg-article-tags" }, article.tags.map(tag => (React.createElement("span", { key: tag, className: "cg-tag" },
58
- "#",
59
- tag))))))));
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
  };
@@ -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"}
@@ -4,4 +4,5 @@
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';