@contentgrowth/content-widget 1.1.0
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/LICENSE +21 -0
- package/README.md +442 -0
- package/dist/astro/ContentList.astro +177 -0
- package/dist/astro/ContentViewer.astro +252 -0
- package/dist/astro/index.d.ts +9 -0
- package/dist/astro/index.d.ts.map +1 -0
- package/dist/astro/index.js +8 -0
- package/dist/core/client.d.ts +67 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +217 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/utils.d.ts +32 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +70 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/react/ContentList.d.ts +12 -0
- package/dist/react/ContentList.d.ts.map +1 -0
- package/dist/react/ContentList.js +106 -0
- package/dist/react/ContentViewer.d.ts +12 -0
- package/dist/react/ContentViewer.d.ts.map +1 -0
- package/dist/react/ContentViewer.js +97 -0
- package/dist/react/hooks.d.ts +63 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +140 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/styles.css +970 -0
- package/dist/types/index.d.ts +271 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/vue/ContentList.vue +166 -0
- package/dist/vue/ContentViewer.vue +137 -0
- package/dist/vue/composables.d.ts +64 -0
- package/dist/vue/composables.d.ts.map +1 -0
- package/dist/vue/composables.js +165 -0
- package/dist/vue/index.d.ts +10 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +8 -0
- package/dist/widget/content-card.js +190 -0
- package/dist/widget/content-list.js +289 -0
- package/dist/widget/content-viewer.js +230 -0
- package/dist/widget/index.js +40 -0
- package/dist/widget/utils/api-client.js +154 -0
- package/dist/widget/utils/helpers.js +71 -0
- package/dist/widget/widget-js/content-card.js +190 -0
- package/dist/widget/widget-js/content-list.js +289 -0
- package/dist/widget/widget-js/content-viewer.js +230 -0
- package/dist/widget/widget-js/index.js +40 -0
- package/dist/widget/widget-js/utils/api-client.js +154 -0
- package/dist/widget/widget-js/utils/helpers.js +71 -0
- package/dist/widget/widget-js/widget.d.ts +24 -0
- package/dist/widget/widget-js/widget.js +240 -0
- package/dist/widget/widget.d.ts +24 -0
- package/dist/widget/widget.js +240 -0
- package/package.json +99 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,iBAAiB,CAAC;AAGhC,mBAAmB,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React ContentList Component
|
|
3
|
+
* Displays a list of articles with pagination
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { ContentListProps } from '../types/index.js';
|
|
7
|
+
export interface ReactContentListProps extends Omit<ContentListProps, 'class'> {
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const ContentList: React.FC<ReactContentListProps>;
|
|
11
|
+
export default ContentList;
|
|
12
|
+
//# sourceMappingURL=ContentList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContentList.d.ts","sourceRoot":"","sources":["../../src/react/ContentList.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,gBAAgB,EAAW,MAAM,mBAAmB,CAAC;AAEnE,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAgLvD,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React ContentList Component
|
|
3
|
+
* Displays a list of articles with pagination
|
|
4
|
+
*/
|
|
5
|
+
import React, { useEffect, useState } from 'react';
|
|
6
|
+
import { ContentGrowthClient } from '../core/client.js';
|
|
7
|
+
import { formatDate, calculateReadingTime } from '../core/utils.js';
|
|
8
|
+
export const ContentList = ({ apiKey, baseUrl, layout = 'cards', displayMode = 'comfortable', theme = 'light', pageSize = 12, tags = [], category, showPagination = true, linkPattern = '/articles/{uuid}', showTags = false, showAiSummary = true, summaryMaxLength, linkTarget, className = '' }) => {
|
|
9
|
+
const [articles, setArticles] = useState([]);
|
|
10
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
11
|
+
const [totalPages, setTotalPages] = useState(1);
|
|
12
|
+
const [loading, setLoading] = useState(true);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const fetchArticles = async () => {
|
|
15
|
+
setLoading(true);
|
|
16
|
+
try {
|
|
17
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
18
|
+
// Process tags
|
|
19
|
+
let processedTags;
|
|
20
|
+
const tagsProp = tags;
|
|
21
|
+
if (tagsProp) {
|
|
22
|
+
if (Array.isArray(tagsProp)) {
|
|
23
|
+
processedTags = tagsProp;
|
|
24
|
+
}
|
|
25
|
+
else if (typeof tagsProp === 'string') {
|
|
26
|
+
processedTags = tagsProp.split(',').map((t) => t.trim()).filter(Boolean);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const result = await client.listArticles({
|
|
30
|
+
page: currentPage,
|
|
31
|
+
limit: pageSize,
|
|
32
|
+
tags: processedTags,
|
|
33
|
+
category
|
|
34
|
+
});
|
|
35
|
+
setArticles(result.articles);
|
|
36
|
+
setTotalPages(result.pagination.totalPages);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error('Error fetching articles:', error);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
setLoading(false);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
fetchArticles();
|
|
46
|
+
}, [apiKey, baseUrl, currentPage, pageSize, tags, category]);
|
|
47
|
+
// Truncate summary text
|
|
48
|
+
const truncateSummary = (text, maxLength) => {
|
|
49
|
+
if (!text)
|
|
50
|
+
return '';
|
|
51
|
+
if (!maxLength || text.length <= maxLength)
|
|
52
|
+
return text;
|
|
53
|
+
return text.substring(0, maxLength).trim() + '...';
|
|
54
|
+
};
|
|
55
|
+
// Build article URL from pattern
|
|
56
|
+
const buildArticleUrl = (article) => {
|
|
57
|
+
return linkPattern
|
|
58
|
+
.replace('{uuid}', article.uuid)
|
|
59
|
+
.replace('{slug}', article.slug)
|
|
60
|
+
.replace('{category}', article.category || '');
|
|
61
|
+
};
|
|
62
|
+
// Build link target from pattern
|
|
63
|
+
const buildLinkTarget = (article) => {
|
|
64
|
+
if (!linkTarget)
|
|
65
|
+
return undefined;
|
|
66
|
+
return linkTarget
|
|
67
|
+
.replace('{uuid}', article.uuid)
|
|
68
|
+
.replace('{id}', article.uuid);
|
|
69
|
+
};
|
|
70
|
+
if (loading) {
|
|
71
|
+
return (React.createElement("div", { className: `cg-content-list cg-layout-${layout} cg-display-${displayMode} cg-theme-${theme} ${className}` },
|
|
72
|
+
React.createElement("div", { className: "cg-empty-state" },
|
|
73
|
+
React.createElement("p", null, "Loading..."))));
|
|
74
|
+
}
|
|
75
|
+
return (React.createElement("div", { className: `cg-content-list cg-layout-${layout} cg-display-${displayMode} cg-theme-${theme} ${className}`, "data-cg-widget": "list" }, articles.length === 0 ? (React.createElement("div", { className: "cg-empty-state" },
|
|
76
|
+
React.createElement("p", null, "No articles found."))) : (React.createElement(React.Fragment, null,
|
|
77
|
+
React.createElement("div", { className: `cg-articles-grid ${layout === 'cards' ? 'cg-grid' : 'cg-list'}` }, articles.map((article) => {
|
|
78
|
+
const articleUrl = buildArticleUrl(article);
|
|
79
|
+
const articleTarget = buildLinkTarget(article);
|
|
80
|
+
const readingTime = calculateReadingTime(article.wordCount);
|
|
81
|
+
const publishedDate = formatDate(article.publishedAt);
|
|
82
|
+
return (React.createElement("article", { key: article.uuid, className: "cg-article-card" },
|
|
83
|
+
React.createElement("a", { href: articleUrl, target: articleTarget, className: "cg-card-link" },
|
|
84
|
+
React.createElement("div", { className: "cg-card-content" },
|
|
85
|
+
article.category && (React.createElement("div", { className: "cg-card-category" },
|
|
86
|
+
React.createElement("span", { className: "cg-category-badge" }, article.category))),
|
|
87
|
+
React.createElement("h2", { className: "cg-card-title" }, article.title),
|
|
88
|
+
showAiSummary && article.summary && (React.createElement("p", { className: "cg-card-summary" }, truncateSummary(article.summary, summaryMaxLength))),
|
|
89
|
+
React.createElement("div", { className: "cg-card-meta" },
|
|
90
|
+
React.createElement("span", { className: "cg-meta-author" }, article.authorName),
|
|
91
|
+
React.createElement("span", { className: "cg-meta-separator" }, "\u2022"),
|
|
92
|
+
React.createElement("time", { className: "cg-meta-date", dateTime: new Date(article.publishedAt * 1000).toISOString() }, publishedDate),
|
|
93
|
+
React.createElement("span", { className: "cg-meta-separator" }, "\u2022"),
|
|
94
|
+
React.createElement("span", { className: "cg-meta-reading-time" }, readingTime)),
|
|
95
|
+
showTags && article.tags && article.tags.length > 0 && (React.createElement("div", { className: "cg-card-tags" }, article.tags.map((tag) => (React.createElement("span", { key: tag, className: "cg-tag" }, tag)))))))));
|
|
96
|
+
})),
|
|
97
|
+
showPagination && totalPages > 1 && (React.createElement("div", { className: "cg-pagination" },
|
|
98
|
+
React.createElement("button", { className: "cg-pagination-btn", onClick: () => setCurrentPage(p => Math.max(1, p - 1)), disabled: currentPage === 1 }, "Previous"),
|
|
99
|
+
React.createElement("span", { className: "cg-pagination-info" },
|
|
100
|
+
"Page ",
|
|
101
|
+
currentPage,
|
|
102
|
+
" of ",
|
|
103
|
+
totalPages),
|
|
104
|
+
React.createElement("button", { className: "cg-pagination-btn", onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), disabled: currentPage === totalPages }, "Next")))))));
|
|
105
|
+
};
|
|
106
|
+
export default ContentList;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React ContentViewer Component
|
|
3
|
+
* Displays a single article with full content
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { ContentViewerProps } from '../types/index.js';
|
|
7
|
+
export interface ReactContentViewerProps extends Omit<ContentViewerProps, 'class'> {
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const ContentViewer: React.FC<ReactContentViewerProps>;
|
|
11
|
+
export default ContentViewer;
|
|
12
|
+
//# sourceMappingURL=ContentViewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContentViewer.d.ts","sourceRoot":"","sources":["../../src/react/ContentViewer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,mBAAmB,CAAC;AAEhF,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAsJ3D,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React ContentViewer Component
|
|
3
|
+
* Displays a single article with full content
|
|
4
|
+
*/
|
|
5
|
+
import React, { useEffect, useState } from 'react';
|
|
6
|
+
import { ContentGrowthClient } from '../core/client.js';
|
|
7
|
+
import { formatDate, calculateReadingTime } from '../core/utils.js';
|
|
8
|
+
import { marked } from 'marked';
|
|
9
|
+
export const ContentViewer = ({ apiKey, uuid, slug, baseUrl, theme = 'light', showBackButton = false, backUrl = '/articles', showAiSummary = true, className = '' }) => {
|
|
10
|
+
const [article, setArticle] = useState(null);
|
|
11
|
+
const [loading, setLoading] = useState(true);
|
|
12
|
+
const [error, setError] = useState(null);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const fetchArticle = async () => {
|
|
15
|
+
if (!uuid && !slug) {
|
|
16
|
+
setError('Either uuid or slug must be provided');
|
|
17
|
+
setLoading(false);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
setLoading(true);
|
|
21
|
+
try {
|
|
22
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
23
|
+
const fetchedArticle = slug
|
|
24
|
+
? await client.getArticleBySlug(slug)
|
|
25
|
+
: await client.getArticle(uuid);
|
|
26
|
+
setArticle(fetchedArticle);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
setError(err instanceof Error ? err.message : 'Failed to load article');
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
setLoading(false);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
fetchArticle();
|
|
36
|
+
}, [apiKey, baseUrl, uuid, slug]);
|
|
37
|
+
// Process markdown content to handle custom image syntax
|
|
38
|
+
const processImageSyntax = (markdown) => {
|
|
39
|
+
// Match: 
|
|
40
|
+
return markdown.replace(/!\[([^\]]*)\]\(([^\s)]+)\s+=(\d+)x(\d+)\)/g, (match, alt, url, width, height) => {
|
|
41
|
+
return `{width="${width}" height="${height}"}`;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
// Configure marked to handle image attributes
|
|
45
|
+
marked.use({
|
|
46
|
+
renderer: {
|
|
47
|
+
image(href, title, text) {
|
|
48
|
+
// Extract width/height from {width="x" height="y"} syntax
|
|
49
|
+
const attrMatch = text.match(/\{width="(\d+)"\s+height="(\d+)"\}/);
|
|
50
|
+
if (attrMatch) {
|
|
51
|
+
const cleanText = text.replace(/\{[^}]+\}/, '').trim();
|
|
52
|
+
return `<img src="${href}" alt="${cleanText}" width="${attrMatch[1]}" height="${attrMatch[2]}" ${title ? `title="${title}"` : ''} />`;
|
|
53
|
+
}
|
|
54
|
+
return `<img src="${href}" alt="${text}" ${title ? `title="${title}"` : ''} />`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
if (loading) {
|
|
59
|
+
return (React.createElement("div", { className: `cg-content-viewer cg-theme-${theme} ${className}` },
|
|
60
|
+
React.createElement("div", { className: "cg-empty-state" },
|
|
61
|
+
React.createElement("p", null, "Loading..."))));
|
|
62
|
+
}
|
|
63
|
+
if (error || !article) {
|
|
64
|
+
return (React.createElement("div", { className: `cg-content-viewer cg-theme-${theme} ${className}` },
|
|
65
|
+
React.createElement("div", { className: "cg-empty-state" },
|
|
66
|
+
React.createElement("p", null, error || 'Article not found'))));
|
|
67
|
+
}
|
|
68
|
+
const processedContent = processImageSyntax(article.content);
|
|
69
|
+
const contentHtml = marked(processedContent);
|
|
70
|
+
const publishedDate = formatDate(article.publishedAt);
|
|
71
|
+
const readingTime = calculateReadingTime(article.wordCount);
|
|
72
|
+
return (React.createElement("article", { className: `cg-content-viewer cg-theme-${theme} ${className}`, "data-cg-widget": "post" },
|
|
73
|
+
showBackButton && (React.createElement("div", { className: "cg-post-header" },
|
|
74
|
+
React.createElement("a", { href: backUrl, className: "cg-back-btn" },
|
|
75
|
+
React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none" },
|
|
76
|
+
React.createElement("path", { d: "M12 16L6 10L12 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })),
|
|
77
|
+
"Back to articles"))),
|
|
78
|
+
React.createElement("header", { className: "cg-post-meta" },
|
|
79
|
+
article.category && (React.createElement("div", { className: "cg-post-category" },
|
|
80
|
+
React.createElement("span", { className: "cg-category-badge" }, article.category))),
|
|
81
|
+
React.createElement("h1", { className: "cg-post-title" }, article.title),
|
|
82
|
+
showAiSummary && article.summary && (React.createElement("div", { className: "cg-ai-summary" },
|
|
83
|
+
React.createElement("div", { className: "cg-ai-summary-header" },
|
|
84
|
+
React.createElement("svg", { className: "cg-ai-summary-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
|
|
85
|
+
React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M13 10V3L4 14h7v7l9-11h-7z" })),
|
|
86
|
+
React.createElement("span", { className: "cg-ai-summary-label" }, "AI Generated Summary")),
|
|
87
|
+
React.createElement("p", { className: "cg-ai-summary-text" }, article.summary))),
|
|
88
|
+
React.createElement("div", { className: "cg-post-info" },
|
|
89
|
+
React.createElement("span", { className: "cg-info-author" }, article.authorName),
|
|
90
|
+
React.createElement("span", { className: "cg-info-separator" }, "\u2022"),
|
|
91
|
+
React.createElement("time", { className: "cg-info-date", dateTime: new Date(article.publishedAt * 1000).toISOString() }, publishedDate),
|
|
92
|
+
React.createElement("span", { className: "cg-info-separator" }, "\u2022"),
|
|
93
|
+
React.createElement("span", { className: "cg-info-reading-time" }, readingTime)),
|
|
94
|
+
article.tags.length > 0 && (React.createElement("div", { className: "cg-post-tags" }, article.tags.map((tag) => (React.createElement("span", { key: tag, className: "cg-tag" }, tag)))))),
|
|
95
|
+
React.createElement("div", { className: "cg-post-content", dangerouslySetInnerHTML: { __html: contentHtml } })));
|
|
96
|
+
};
|
|
97
|
+
export default ContentViewer;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Hooks for Content Growth API
|
|
3
|
+
*/
|
|
4
|
+
import type { Article, ArticleWithContent, Pagination, Category, Tag, ListArticlesOptions } from '../types/index.js';
|
|
5
|
+
export interface UseArticlesOptions extends ListArticlesOptions {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface UseArticlesResult {
|
|
10
|
+
articles: Article[];
|
|
11
|
+
pagination: Pagination | null;
|
|
12
|
+
loading: boolean;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
refetch: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Hook to fetch articles list
|
|
18
|
+
*/
|
|
19
|
+
export declare function useArticles(options: UseArticlesOptions): UseArticlesResult;
|
|
20
|
+
export interface UseArticleOptions {
|
|
21
|
+
apiKey: string;
|
|
22
|
+
uuid: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface UseArticleResult {
|
|
26
|
+
article: ArticleWithContent | null;
|
|
27
|
+
loading: boolean;
|
|
28
|
+
error: Error | null;
|
|
29
|
+
refetch: () => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Hook to fetch a single article
|
|
33
|
+
*/
|
|
34
|
+
export declare function useArticle(options: UseArticleOptions): UseArticleResult;
|
|
35
|
+
export interface UseCategoriesOptions {
|
|
36
|
+
apiKey: string;
|
|
37
|
+
baseUrl?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface UseCategoriesResult {
|
|
40
|
+
categories: Category[];
|
|
41
|
+
loading: boolean;
|
|
42
|
+
error: Error | null;
|
|
43
|
+
refetch: () => Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Hook to fetch categories
|
|
47
|
+
*/
|
|
48
|
+
export declare function useCategories(options: UseCategoriesOptions): UseCategoriesResult;
|
|
49
|
+
export interface UseTagsOptions {
|
|
50
|
+
apiKey: string;
|
|
51
|
+
baseUrl?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface UseTagsResult {
|
|
54
|
+
tags: Tag[];
|
|
55
|
+
loading: boolean;
|
|
56
|
+
error: Error | null;
|
|
57
|
+
refetch: () => Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Hook to fetch tags
|
|
61
|
+
*/
|
|
62
|
+
export declare function useTags(options: UseTagsOptions): UseTagsResult;
|
|
63
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/react/hooks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,OAAO,EACP,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,GAAG,EACH,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAkC1E;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CA+BvE;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CA+BhF;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,CA+B9D"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Hooks for Content Growth API
|
|
3
|
+
*/
|
|
4
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
5
|
+
import { ContentGrowthClient } from '../core/client.js';
|
|
6
|
+
/**
|
|
7
|
+
* Hook to fetch articles list
|
|
8
|
+
*/
|
|
9
|
+
export function useArticles(options) {
|
|
10
|
+
const { apiKey, baseUrl, ...listOptions } = options;
|
|
11
|
+
const [articles, setArticles] = useState([]);
|
|
12
|
+
const [pagination, setPagination] = useState(null);
|
|
13
|
+
const [loading, setLoading] = useState(true);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const fetchArticles = useCallback(async () => {
|
|
16
|
+
setLoading(true);
|
|
17
|
+
setError(null);
|
|
18
|
+
try {
|
|
19
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
20
|
+
const result = await client.listArticles(listOptions);
|
|
21
|
+
setArticles(result.articles);
|
|
22
|
+
setPagination(result.pagination);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
setError(err);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
setLoading(false);
|
|
29
|
+
}
|
|
30
|
+
}, [apiKey, baseUrl, JSON.stringify(listOptions)]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
fetchArticles();
|
|
33
|
+
}, [fetchArticles]);
|
|
34
|
+
return {
|
|
35
|
+
articles,
|
|
36
|
+
pagination,
|
|
37
|
+
loading,
|
|
38
|
+
error,
|
|
39
|
+
refetch: fetchArticles
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Hook to fetch a single article
|
|
44
|
+
*/
|
|
45
|
+
export function useArticle(options) {
|
|
46
|
+
const { apiKey, uuid, baseUrl } = options;
|
|
47
|
+
const [article, setArticle] = useState(null);
|
|
48
|
+
const [loading, setLoading] = useState(true);
|
|
49
|
+
const [error, setError] = useState(null);
|
|
50
|
+
const fetchArticle = useCallback(async () => {
|
|
51
|
+
setLoading(true);
|
|
52
|
+
setError(null);
|
|
53
|
+
try {
|
|
54
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
55
|
+
const result = await client.getArticle(uuid);
|
|
56
|
+
setArticle(result);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
setError(err);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
setLoading(false);
|
|
63
|
+
}
|
|
64
|
+
}, [apiKey, uuid, baseUrl]);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
fetchArticle();
|
|
67
|
+
}, [fetchArticle]);
|
|
68
|
+
return {
|
|
69
|
+
article,
|
|
70
|
+
loading,
|
|
71
|
+
error,
|
|
72
|
+
refetch: fetchArticle
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Hook to fetch categories
|
|
77
|
+
*/
|
|
78
|
+
export function useCategories(options) {
|
|
79
|
+
const { apiKey, baseUrl } = options;
|
|
80
|
+
const [categories, setCategories] = useState([]);
|
|
81
|
+
const [loading, setLoading] = useState(true);
|
|
82
|
+
const [error, setError] = useState(null);
|
|
83
|
+
const fetchCategories = useCallback(async () => {
|
|
84
|
+
setLoading(true);
|
|
85
|
+
setError(null);
|
|
86
|
+
try {
|
|
87
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
88
|
+
const result = await client.getCategories();
|
|
89
|
+
setCategories(result.categories);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
setError(err);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
setLoading(false);
|
|
96
|
+
}
|
|
97
|
+
}, [apiKey, baseUrl]);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
fetchCategories();
|
|
100
|
+
}, [fetchCategories]);
|
|
101
|
+
return {
|
|
102
|
+
categories,
|
|
103
|
+
loading,
|
|
104
|
+
error,
|
|
105
|
+
refetch: fetchCategories
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Hook to fetch tags
|
|
110
|
+
*/
|
|
111
|
+
export function useTags(options) {
|
|
112
|
+
const { apiKey, baseUrl } = options;
|
|
113
|
+
const [tags, setTags] = useState([]);
|
|
114
|
+
const [loading, setLoading] = useState(true);
|
|
115
|
+
const [error, setError] = useState(null);
|
|
116
|
+
const fetchTags = useCallback(async () => {
|
|
117
|
+
setLoading(true);
|
|
118
|
+
setError(null);
|
|
119
|
+
try {
|
|
120
|
+
const client = new ContentGrowthClient({ apiKey, baseUrl });
|
|
121
|
+
const result = await client.getTags();
|
|
122
|
+
setTags(result.tags);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
setError(err);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
setLoading(false);
|
|
129
|
+
}
|
|
130
|
+
}, [apiKey, baseUrl]);
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
fetchTags();
|
|
133
|
+
}, [fetchTags]);
|
|
134
|
+
return {
|
|
135
|
+
tags,
|
|
136
|
+
loading,
|
|
137
|
+
error,
|
|
138
|
+
refetch: fetchTags
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Growth Content Widget - React Components
|
|
3
|
+
*/
|
|
4
|
+
export { ContentList } from './ContentList.js';
|
|
5
|
+
export { ContentViewer } from './ContentViewer.js';
|
|
6
|
+
export * from './hooks.js';
|
|
7
|
+
export type { ReactContentListProps } from './ContentList.js';
|
|
8
|
+
export type { ReactContentViewerProps } from './ContentViewer.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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,cAAc,YAAY,CAAC;AAE3B,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC"}
|