@contentgrowth/content-widget 1.3.5 → 1.3.7

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
@@ -320,6 +320,8 @@ A compact card displaying the Featured Summary with customizable styling. Perfec
320
320
  linkPattern="/articles/{slug}"
321
321
  layout="horizontal"
322
322
  borderStyle="dashed"
323
+ borderColor="#e5e7eb"
324
+ padding="20px"
323
325
  ctaText="Read full story"
324
326
  />
325
327
 
@@ -350,11 +352,23 @@ A compact card displaying the Featured Summary with customizable styling. Perfec
350
352
  | `borderColor` | string | '#e5e7eb' | Border color (CSS value) |
351
353
  | `cardBackground` | string | 'none' | Card background ('none' = transparent) |
352
354
  | `itemsBackground` | string | '#f3f4f6' | Background for list/quote section |
355
+ | `padding` | string | - | Custom padding (e.g., '10px', '2rem 3rem') |
353
356
  | `ctaText` | string | 'Read full story' | Call-to-action text |
354
357
  | `showAuthor` | boolean | false | Show author name |
355
358
  | `showReadingTime` | boolean | false | Show reading time |
356
359
  | `linkPattern` | string | '/articles/{slug}' | URL pattern for link |
357
360
 
361
+ **Featured Summary Types:**
362
+
363
+ FeaturedCard supports structured JSON summaries generated via the portal wizard:
364
+
365
+ | Type | Description |
366
+ |------|-------------|
367
+ | `list` | Intro text on left, bulleted key points on right |
368
+ | `steps` | Intro text on left, numbered action steps on right |
369
+ | `quote` | Intro text on left, styled pullquote on right |
370
+ | `classic` | Simple text summary (legacy) |
371
+
358
372
  **Featured Cards List:**
359
373
 
360
374
  Display all articles as FeaturedCards in a grid using `displayAs`:
@@ -1,6 +1,6 @@
1
1
  ---
2
- import { marked } from 'marked';
3
2
  import { ContentGrowthClient } from '../core/client';
3
+ import { renderInlineMarkdownJS } from '../core/inline-markdown';
4
4
  import type { FeaturedContentProps, Article, ArticleWithContent } from '../types';
5
5
 
6
6
  interface FeaturedCardProps extends Omit<FeaturedContentProps, 'showBackButton' | 'backUrl'> {
@@ -78,6 +78,12 @@ interface FeaturedCardProps extends Omit<FeaturedContentProps, 'showBackButton'
78
78
  * @default undefined (same tab)
79
79
  */
80
80
  linkTarget?: string;
81
+
82
+ /**
83
+ * Custom padding for the card content
84
+ * @example "20px" or "0"
85
+ */
86
+ padding?: string;
81
87
  }
82
88
 
83
89
  type Props = FeaturedCardProps & { class?: string };
@@ -102,6 +108,7 @@ const {
102
108
  borderColor = '#e5e7eb',
103
109
  cardBackground = 'none',
104
110
  itemsBackground = '#f3f4f6',
111
+ padding,
105
112
  class: className = ''
106
113
  } = Astro.props;
107
114
 
@@ -146,13 +153,39 @@ const getArticleUrl = (article: any) => {
146
153
  .replace('{category}', article.category || 'uncategorized');
147
154
  };
148
155
 
149
- // Render featured summary (or fallback to regular summary) as HTML
150
- const getSummaryHtml = (article: any) => {
156
+ // Parse featured summary - supports both JSON (new) and plain text (legacy)
157
+ interface SummaryData {
158
+ type: 'classic' | 'list' | 'steps' | 'quote' | 'legacy';
159
+ text?: string;
160
+ intro?: string;
161
+ items?: Array<{ title: string; description: string }>;
162
+ quote?: string;
163
+ highlight?: string;
164
+ }
165
+
166
+ const parseSummary = (article: any): SummaryData | null => {
151
167
  const summaryText = article.featuredSummary || article.summary;
152
- if (!summaryText) return '';
153
- return marked.parse(summaryText, { async: false }) as string;
168
+ if (!summaryText) return null;
169
+
170
+ // Try to parse as JSON
171
+ try {
172
+ const parsed = JSON.parse(summaryText);
173
+ if (parsed.type) {
174
+ return parsed as SummaryData;
175
+ }
176
+ } catch (e) {
177
+ // Not JSON, treat as legacy markdown/plain text
178
+ }
179
+
180
+ // Legacy fallback - render as plain text
181
+ return {
182
+ type: 'legacy',
183
+ text: summaryText
184
+ };
154
185
  };
155
186
 
187
+ const summaryData = article ? parseSummary(article) : null;
188
+
156
189
  const layout = propLayout || (article as any)?.featuredSummaryLayout || 'vertical';
157
190
  const layoutClass = layout !== 'vertical' ? `cg-layout-${layout}` : '';
158
191
  const borderClass = borderStyle !== 'none' ? `cg-border-${borderStyle}` : '';
@@ -165,6 +198,7 @@ const customStyles = [
165
198
  borderColor !== '#e5e7eb' ? `--cg-card-border-color: ${borderColor}` : '',
166
199
  cardBackground !== 'none' ? `--cg-card-bg: ${cardBackground}` : '',
167
200
  itemsBackground !== '#f3f4f6' ? `--cg-items-bg: ${itemsBackground}` : '',
201
+ padding ? `--cg-card-padding: ${padding}` : '',
168
202
  ].filter(Boolean).join('; ');
169
203
  ---
170
204
 
@@ -178,42 +212,81 @@ const customStyles = [
178
212
  rel={linkTarget === '_blank' ? 'noopener noreferrer' : undefined}
179
213
  >
180
214
  <article class="cg-featured-card-inner">
181
- {/* Header with category badge */}
182
- {showCategory && article.category && (
183
- <div class="cg-featured-card-category">
184
- <span class="cg-category-badge">{article.category}</span>
185
- </div>
186
- )}
187
-
188
- {/* Title */}
189
- <h3 class="cg-featured-card-title">{article.title}</h3>
190
-
191
- {/* Featured Summary */}
192
- {(article.featuredSummary || article.summary) && (
193
- <div
194
- class="cg-featured-card-summary"
195
- set:html={getSummaryHtml(article)}
196
- />
197
- )}
198
-
199
- {/* Footer with meta info */}
200
- {(showAuthor || showReadingTime) && (
201
- <div class="cg-featured-card-footer">
202
- {showAuthor && <span class="cg-featured-card-author">{article.authorName}</span>}
203
-
204
- {showAuthor && showReadingTime && (
205
- <span class="cg-featured-card-separator">•</span>
215
+ <div class="cg-card-primary">
216
+ {/* Header with category badge */}
217
+ {showCategory && article.category && (
218
+ <div class="cg-featured-card-category">
219
+ <span class="cg-category-badge">{article.category}</span>
220
+ </div>
221
+ )}
222
+
223
+ {/* Title */}
224
+ <h3 class="cg-featured-card-title">{article.title}</h3>
225
+
226
+ {/* Featured Summary - Intro / Text Part */}
227
+ {summaryData && (
228
+ <div class="cg-featured-card-summary">
229
+ {/* Intro for structured types */}
230
+ {(summaryData.type === 'list' || summaryData.type === 'steps' || summaryData.type === 'quote') && summaryData.intro && (
231
+ <p set:html={renderInlineMarkdownJS(summaryData.intro)} />
232
+ )}
233
+
234
+ {/* Classic type - just text */}
235
+ {summaryData.type === 'classic' && (
236
+ <p set:html={renderInlineMarkdownJS(summaryData.text || '')} />
237
+ )}
238
+
239
+ {/* Legacy markdown - render as plain text */}
240
+ {summaryData.type === 'legacy' && (
241
+ <p>{summaryData.text}</p>
242
+ )}
243
+ </div>
244
+ )}
245
+
246
+ {/* Footer with meta info */}
247
+ {(showAuthor || showReadingTime) && (
248
+ <div class="cg-featured-card-footer">
249
+ {showAuthor && <span class="cg-featured-card-author">{article.authorName}</span>}
250
+
251
+ {showAuthor && showReadingTime && (
252
+ <span class="cg-featured-card-separator">•</span>
253
+ )}
254
+
255
+ {showReadingTime && (
256
+ <span class="cg-featured-card-reading-time">
257
+ {Math.ceil(article.wordCount / 200)} min read
258
+ </span>
259
+ )}
260
+ </div>
261
+ )}
262
+
263
+ {/* Read more indicator */}
264
+ </div>
265
+
266
+ {/* Right Panel - Structured Visual Items (List/Quote) */}
267
+ {summaryData && (summaryData.type === 'list' || summaryData.type === 'steps' || summaryData.type === 'quote') && (
268
+ <div class="cg-card-secondary">
269
+ {(summaryData.type === 'list' || summaryData.type === 'steps') && (
270
+ <ul class="cg-summary-items">
271
+ {summaryData.items?.map((item, index) => (
272
+ <li>
273
+ <span class="cg-item-number">{index + 1}</span>
274
+ <div class="cg-item-content">
275
+ <strong class="cg-item-title" set:html={renderInlineMarkdownJS(item.title)} />
276
+ <span class="cg-item-description" set:html={renderInlineMarkdownJS(item.description)} />
277
+ </div>
278
+ </li>
279
+ ))}
280
+ </ul>
206
281
  )}
207
282
 
208
- {showReadingTime && (
209
- <span class="cg-featured-card-reading-time">
210
- {Math.ceil(article.wordCount / 200)} min read
211
- </span>
283
+ {summaryData.type === 'quote' && (
284
+ <blockquote set:html={renderInlineMarkdownJS(summaryData.quote || '')} />
212
285
  )}
213
286
  </div>
214
287
  )}
215
-
216
- {/* Read more indicator */}
288
+
289
+ {/* Read more indicator - Now at bottom */}
217
290
  <div class="cg-featured-card-cta">
218
291
  <span>{ctaText}</span>
219
292
  <svg class="cg-featured-card-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24" width="16" height="16">
@@ -4,5 +4,6 @@
4
4
  */
5
5
  export { ContentGrowthClient } from './client.js';
6
6
  export * from './utils.js';
7
+ export * from './inline-markdown.js';
7
8
  export * from '../types/index.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
@@ -4,4 +4,5 @@
4
4
  */
5
5
  export { ContentGrowthClient } from './client.js';
6
6
  export * from './utils.js';
7
+ export * from './inline-markdown.js';
7
8
  export * from '../types/index.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Renders inline markdown syntax (bold and italic only) to HTML.
3
+ * Supports: **bold**, *italic*, ***bold italic***
4
+ *
5
+ * @param text - The text to parse
6
+ * @returns HTML string with <strong> and <em> tags
7
+ */
8
+ export declare function renderInlineMarkdown(text: string): string;
9
+ /**
10
+ * Plain JavaScript version for use in Astro components
11
+ */
12
+ export declare function renderInlineMarkdownJS(text: string): string;
13
+ //# sourceMappingURL=inline-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-markdown.d.ts","sourceRoot":"","sources":["../../src/core/inline-markdown.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUzD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO3D"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Renders inline markdown syntax (bold and italic only) to HTML.
3
+ * Supports: **bold**, *italic*, ***bold italic***
4
+ *
5
+ * @param text - The text to parse
6
+ * @returns HTML string with <strong> and <em> tags
7
+ */
8
+ export function renderInlineMarkdown(text) {
9
+ if (!text)
10
+ return '';
11
+ return text
12
+ // Bold + Italic: ***text*** -> <strong><em>text</em></strong>
13
+ .replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>')
14
+ // Bold: **text** -> <strong>text</strong>
15
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
16
+ // Italic: *text* -> <em>text</em>
17
+ .replace(/\*(.+?)\*/g, '<em>$1</em>');
18
+ }
19
+ /**
20
+ * Plain JavaScript version for use in Astro components
21
+ */
22
+ export function renderInlineMarkdownJS(text) {
23
+ if (!text)
24
+ return '';
25
+ return text
26
+ .replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>')
27
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
28
+ .replace(/\*(.+?)\*/g, '<em>$1</em>');
29
+ }
@@ -58,11 +58,20 @@ interface FeaturedCardProps extends Partial<Omit<FeaturedContentProps, 'showBack
58
58
  * @default 'none'
59
59
  */
60
60
  cardBackground?: string;
61
+ /**
62
+ * Background color for list/quote section (the items area)
63
+ * @default '#f3f4f6'
64
+ */
61
65
  /**
62
66
  * Background color for list/quote section (the items area)
63
67
  * @default '#f3f4f6'
64
68
  */
65
69
  itemsBackground?: string;
70
+ /**
71
+ * Custom padding for the card content
72
+ * @example "20px" or "0"
73
+ */
74
+ padding?: string;
66
75
  }
67
76
  export declare const FeaturedCard: React.FC<FeaturedCardProps>;
68
77
  export {};
@@ -1 +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,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAElF,UAAU,iBAAkB,SAAQ,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,GAAG,SAAS,GAAG,eAAe,GAAG,UAAU,CAAC,CAAC;IAChI;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAEvC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;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,CA0KpD,CAAC"}
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,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAkClF,UAAU,iBAAkB,SAAQ,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,GAAG,SAAS,GAAG,eAAe,GAAG,UAAU,CAAC,CAAC;IAChI;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAEvC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;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;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4NpD,CAAC"}
@@ -1,7 +1,28 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { marked } from 'marked';
3
2
  import { ContentGrowthClient } from '../core/client';
4
- export const FeaturedCard = ({ apiKey, baseUrl, article: providedArticle, slug, uuid, tags = [], category, excludeTags = [], showCategory = true, showReadingTime = false, showAuthor = false, ctaText: propCtaText, linkPattern = '/articles/{slug}', linkTarget, layout: propLayout, borderStyle = 'none', borderColor = '#e5e7eb', cardBackground = 'none', itemsBackground = '#f3f4f6', className = '' }) => {
3
+ import { renderInlineMarkdown } from '../core/inline-markdown';
4
+ // Parse featured summary - supports both JSON (new) and plain text (legacy)
5
+ const parseSummary = (article) => {
6
+ const summaryText = article.featuredSummary || article.summary;
7
+ if (!summaryText)
8
+ return null;
9
+ // Try to parse as JSON
10
+ try {
11
+ const parsed = JSON.parse(summaryText);
12
+ if (parsed.type) {
13
+ return parsed;
14
+ }
15
+ }
16
+ catch (e) {
17
+ // Not JSON, treat as legacy markdown/plain text
18
+ }
19
+ // Legacy fallback - render as plain text
20
+ return {
21
+ type: 'legacy',
22
+ text: summaryText
23
+ };
24
+ };
25
+ export const FeaturedCard = ({ apiKey, baseUrl, article: providedArticle, slug, uuid, tags = [], category, excludeTags = [], showCategory = true, showReadingTime = false, showAuthor = false, ctaText: propCtaText, linkPattern = '/articles/{slug}', linkTarget, layout: propLayout, borderStyle = 'none', borderColor = '#e5e7eb', cardBackground = 'none', itemsBackground = '#f3f4f6', padding, className = '' }) => {
5
26
  const [article, setArticle] = useState(providedArticle || null);
6
27
  const [loading, setLoading] = useState(!providedArticle);
7
28
  const [error, setError] = useState(null);
@@ -56,13 +77,6 @@ export const FeaturedCard = ({ apiKey, baseUrl, article: providedArticle, slug,
56
77
  .replace('{slug}', article.slug || article.uuid || '')
57
78
  .replace('{category}', article.category || 'uncategorized');
58
79
  };
59
- // Render featured summary (or fallback to regular summary) as HTML
60
- const getSummaryHtml = (article) => {
61
- const summaryText = article.featuredSummary || article.summary;
62
- if (!summaryText)
63
- return '';
64
- return marked.parse(summaryText, { async: false });
65
- };
66
80
  if (loading) {
67
81
  return (React.createElement("div", { className: `cg-widget cg-loading ${className}` },
68
82
  React.createElement("div", { className: "cg-spinner" })));
@@ -70,7 +84,6 @@ export const FeaturedCard = ({ apiKey, baseUrl, article: providedArticle, slug,
70
84
  if (error || !article) {
71
85
  return (React.createElement("div", { className: `cg-widget cg-error ${className}` }, error || 'No featured content found'));
72
86
  }
73
- const summaryHtml = getSummaryHtml(article);
74
87
  const layout = propLayout || article.featuredSummaryLayout || 'vertical';
75
88
  const readingTime = Math.ceil(article.wordCount / 200);
76
89
  const borderClass = borderStyle !== 'none' ? `cg-border-${borderStyle}` : '';
@@ -84,18 +97,52 @@ export const FeaturedCard = ({ apiKey, baseUrl, article: providedArticle, slug,
84
97
  customStyles['--cg-card-bg'] = cardBackground;
85
98
  if (itemsBackground !== '#f3f4f6')
86
99
  customStyles['--cg-items-bg'] = itemsBackground;
100
+ if (padding)
101
+ customStyles['--cg-card-padding'] = padding;
87
102
  return (React.createElement("a", { href: getArticleUrl(article), className: `cg-widget cg-featured-card ${className} ${layoutClass} ${borderClass}`, style: Object.keys(customStyles).length > 0 ? customStyles : undefined, "data-cg-widget": "featured-card", target: linkTarget, rel: linkTarget === '_blank' ? 'noopener noreferrer' : undefined },
88
103
  React.createElement("article", { className: "cg-featured-card-inner" },
89
- showCategory && article.category && (React.createElement("div", { className: "cg-featured-card-category" },
90
- React.createElement("span", { className: "cg-category-badge" }, article.category))),
91
- React.createElement("h3", { className: "cg-featured-card-title" }, article.title),
92
- summaryHtml && (React.createElement("div", { className: "cg-featured-card-summary", dangerouslySetInnerHTML: { __html: summaryHtml } })),
93
- (showAuthor || showReadingTime) && (React.createElement("div", { className: "cg-featured-card-footer" },
94
- showAuthor && React.createElement("span", { className: "cg-featured-card-author" }, article.authorName),
95
- showAuthor && showReadingTime && (React.createElement("span", { className: "cg-featured-card-separator" }, "\u2022")),
96
- showReadingTime && (React.createElement("span", { className: "cg-featured-card-reading-time" },
97
- readingTime,
98
- " min read")))),
104
+ React.createElement("div", { className: "cg-card-primary" },
105
+ showCategory && article.category && (React.createElement("div", { className: "cg-featured-card-category" },
106
+ React.createElement("span", { className: "cg-category-badge" }, article.category))),
107
+ React.createElement("h3", { className: "cg-featured-card-title" }, article.title),
108
+ parseSummary(article) && (React.createElement("div", { className: "cg-featured-card-summary" }, (() => {
109
+ const summaryData = parseSummary(article);
110
+ if (summaryData.type === 'classic') {
111
+ return React.createElement("p", { dangerouslySetInnerHTML: { __html: renderInlineMarkdown(summaryData.text || '') } });
112
+ }
113
+ if ((summaryData.type === 'list' || summaryData.type === 'steps') && summaryData.intro) {
114
+ return React.createElement("p", { dangerouslySetInnerHTML: { __html: renderInlineMarkdown(summaryData.intro) } });
115
+ }
116
+ if (summaryData.type === 'quote' && summaryData.quote) {
117
+ return React.createElement("p", { dangerouslySetInnerHTML: { __html: renderInlineMarkdown(summaryData.intro || '') } });
118
+ }
119
+ // Legacy
120
+ return React.createElement("p", null, summaryData.text);
121
+ })())),
122
+ (showAuthor || showReadingTime) && (React.createElement("div", { className: "cg-featured-card-footer" },
123
+ showAuthor && React.createElement("span", { className: "cg-featured-card-author" }, article.authorName),
124
+ showAuthor && showReadingTime && (React.createElement("span", { className: "cg-featured-card-separator" }, "\u2022")),
125
+ showReadingTime && (React.createElement("span", { className: "cg-featured-card-reading-time" },
126
+ readingTime,
127
+ " min read"))))),
128
+ (() => {
129
+ const summaryData = parseSummary(article);
130
+ if (!summaryData)
131
+ return null;
132
+ if ((summaryData.type === 'list' || summaryData.type === 'steps') && summaryData.items) {
133
+ return (React.createElement("div", { className: "cg-card-secondary" },
134
+ React.createElement("ul", { className: "cg-summary-items" }, summaryData.items.map((item, index) => (React.createElement("li", { key: index },
135
+ React.createElement("span", { className: "cg-item-number" }, index + 1),
136
+ React.createElement("div", { className: "cg-item-content" },
137
+ React.createElement("strong", { className: "cg-item-title", dangerouslySetInnerHTML: { __html: renderInlineMarkdown(item.title) } }),
138
+ React.createElement("span", { className: "cg-item-description", dangerouslySetInnerHTML: { __html: renderInlineMarkdown(item.description) } }))))))));
139
+ }
140
+ if (summaryData.type === 'quote' && summaryData.quote) {
141
+ return (React.createElement("div", { className: "cg-card-secondary" },
142
+ React.createElement("blockquote", { dangerouslySetInnerHTML: { __html: renderInlineMarkdown(summaryData.quote) } })));
143
+ }
144
+ return null;
145
+ })(),
99
146
  React.createElement("div", { className: "cg-featured-card-cta" },
100
147
  React.createElement("span", null, ctaText),
101
148
  React.createElement("svg", { className: "cg-featured-card-arrow", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", width: "16", height: "16" },