@roottale/cms-renderer-next 0.53.1 → 0.56.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/CHANGELOG.md +60 -0
- package/dist/{blog-filter-BKCGM0qd.d.ts → blog-filter-qE9Lj49C.d.ts} +12 -1
- package/dist/{chunk-HM5VP7SR.js → chunk-GDP2VGJR.js} +38 -6
- package/dist/chunk-GDP2VGJR.js.map +1 -0
- package/dist/cms-public.css +36 -0
- package/dist/routes.d.ts +57 -8
- package/dist/routes.js +50 -17
- package/dist/routes.js.map +1 -1
- package/dist/server.d.ts +27 -3
- package/dist/server.js +77 -13
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-HM5VP7SR.js.map +0 -1
package/dist/server.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { CmsPostContent, RootTaleTheme, CmsPostType } from '@roottale/cms-client
|
|
|
3
3
|
export { RootTaleTheme } from '@roottale/cms-client/server';
|
|
4
4
|
import { RootTaleThemeStyle } from '@roottale/ui-react/theme';
|
|
5
5
|
import { Block, BindingResolver, RouteCollection } from '@roottale/cms-core';
|
|
6
|
-
export { a as BlogCategory, B as BlogCategoryWithCount, c as collectCategories, b as collectCategoriesWithCounts, d as defaultCategoryHref, f as filterPostsByCategory } from './blog-filter-
|
|
6
|
+
export { a as BlogCategory, B as BlogCategoryWithCount, c as collectCategories, b as collectCategoriesWithCounts, d as defaultCategoryHref, f as filterPostsByCategory, m as makeCategoryHref } from './blog-filter-qE9Lj49C.js';
|
|
7
7
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -238,7 +238,16 @@ declare function RootTaleBlogCategories(props: RootTaleBlogCategoriesProps): Pro
|
|
|
238
238
|
|
|
239
239
|
type RootTaleBlogPostProps = {
|
|
240
240
|
apiKey: string;
|
|
241
|
-
|
|
241
|
+
/** 발행 글 slug 또는 id. `previewToken` 을 줄 때는 생략할 수 있다. */
|
|
242
|
+
slugOrId?: string;
|
|
243
|
+
/**
|
|
244
|
+
* 어드민 편집기가 발급한 미리보기 토큰(URL `?token=`). 주면 `slugOrId` 대신
|
|
245
|
+
* `fetchPostPreview` 로 초안을 받아 **같은 템플릿**으로 그린다 — 미리보기 = 결과물.
|
|
246
|
+
* 만료(410)면 `previewExpiredElement`, 없으면(404) `notFoundElement`.
|
|
247
|
+
*/
|
|
248
|
+
previewToken?: string;
|
|
249
|
+
/** 미리보기 토큰이 만료됐을 때 대신 그릴 요소(기본: 만료 안내 문구). */
|
|
250
|
+
previewExpiredElement?: ReactElement;
|
|
242
251
|
baseUrl?: string;
|
|
243
252
|
notFoundElement?: ReactElement;
|
|
244
253
|
showTitle?: boolean;
|
|
@@ -270,6 +279,21 @@ declare function RootTaleFaqJsonLd({ doc, }: {
|
|
|
270
279
|
readonly doc: unknown;
|
|
271
280
|
}): ReactElement | null;
|
|
272
281
|
|
|
282
|
+
interface RootTalePreviewNoticeProps {
|
|
283
|
+
/** `ko`(기본) · `en`. */
|
|
284
|
+
locale?: string;
|
|
285
|
+
/** 기본 안내 문구를 바꾸고 싶을 때. */
|
|
286
|
+
message?: string;
|
|
287
|
+
/** 토큰 만료 시각(ISO) — 주면 "HH:MM까지" 를 덧붙인다. */
|
|
288
|
+
expiresAt?: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 미리보기 화면 상단 안내 띠. 본문 템플릿은 발행 화면과 완전히 같게 두고, "이건
|
|
292
|
+
* 미리보기다" 라는 신호만 이 띠 하나로 준다. 검색엔진 색인 차단은 metadata
|
|
293
|
+
* (`buildPreviewMetadata`) 몫이며, 이 컴포넌트는 사람용 안내다.
|
|
294
|
+
*/
|
|
295
|
+
declare function RootTalePreviewNotice({ locale, message, expiresAt, }: RootTalePreviewNoticeProps): ReactElement;
|
|
296
|
+
|
|
273
297
|
type RootTalePageProps = {
|
|
274
298
|
apiKey: string;
|
|
275
299
|
slugOrId: string;
|
|
@@ -332,4 +356,4 @@ type PostBodySource = {
|
|
|
332
356
|
*/
|
|
333
357
|
declare function resolvePostBodySource(bodyHtml: string | null | undefined): PostBodySource;
|
|
334
358
|
|
|
335
|
-
export { type BlogPostBreadcrumbOptions, type CtaButton, type CtaButtonType, type FloatingCtaPosition, type LeadFormVertical, type PostBodySource, RenderTiptap, RootTaleBlogCategories, type RootTaleBlogCategoriesProps, RootTaleBlogList, type RootTaleBlogListProps, RootTaleBlogPost, type RootTaleBlogPostProps, type RootTaleCssVars, RootTaleExposureSlot, type RootTaleExposureSlotProps, RootTaleFaqJsonLd, RootTaleFloatingCta, type RootTaleFloatingCtaProps, RootTaleLeadForm, type RootTaleLeadFormProps, RootTalePage, type RootTalePageProps, RootTalePostCard, type RootTalePostCardProps, RootTaleTableOfContents, type RootTaleTableOfContentsProps, type RootTaleThemeInput, RootTaleThemeProvider, type TocEntry, attachHeadingIds, extractToc, headingToId, renderBlock, renderBlocks, renderBoundBlocks, resolvePostBodySource, themeToCssVars };
|
|
359
|
+
export { type BlogPostBreadcrumbOptions, type CtaButton, type CtaButtonType, type FloatingCtaPosition, type LeadFormVertical, type PostBodySource, RenderTiptap, RootTaleBlogCategories, type RootTaleBlogCategoriesProps, RootTaleBlogList, type RootTaleBlogListProps, RootTaleBlogPost, type RootTaleBlogPostProps, type RootTaleCssVars, RootTaleExposureSlot, type RootTaleExposureSlotProps, RootTaleFaqJsonLd, RootTaleFloatingCta, type RootTaleFloatingCtaProps, RootTaleLeadForm, type RootTaleLeadFormProps, RootTalePage, type RootTalePageProps, RootTalePostCard, type RootTalePostCardProps, RootTalePreviewNotice, type RootTalePreviewNoticeProps, RootTaleTableOfContents, type RootTaleTableOfContentsProps, type RootTaleThemeInput, RootTaleThemeProvider, type TocEntry, attachHeadingIds, extractToc, headingToId, renderBlock, renderBlocks, renderBoundBlocks, resolvePostBodySource, themeToCssVars };
|
package/dist/server.js
CHANGED
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
collectCollectionCategories,
|
|
5
5
|
defaultCategoryHref,
|
|
6
6
|
filterPostsByCategory,
|
|
7
|
+
makeCategoryHref,
|
|
8
|
+
storedPostPath,
|
|
7
9
|
trimSlash
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GDP2VGJR.js";
|
|
9
11
|
import {
|
|
10
12
|
getSectionNodeRenderer
|
|
11
13
|
} from "./chunk-KSPPYX22.js";
|
|
@@ -84,6 +86,8 @@ var DICTS = {
|
|
|
84
86
|
relatedPostsTitle: "\uAD00\uB828 \uAE00",
|
|
85
87
|
postNotFound: "\uAE00\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
86
88
|
pageNotFound: "\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
89
|
+
previewExpired: "\uBBF8\uB9AC\uBCF4\uAE30 \uB9C1\uD06C\uAC00 \uB9CC\uB8CC\uB410\uC5B4\uC694. \uAD00\uB9AC\uC790 \uD3B8\uC9D1\uAE30\uC5D0\uC11C \uBBF8\uB9AC\uBCF4\uAE30\uB97C \uB2E4\uC2DC \uC5F4\uC5B4 \uC8FC\uC138\uC694.",
|
|
90
|
+
previewNotice: "\uBBF8\uB9AC\uBCF4\uAE30 \u2014 \uC544\uC9C1 \uACF5\uAC1C\uB418\uC9C0 \uC54A\uC740 \uB0B4\uC6A9\uC774\uBA70 \uAC80\uC0C9\uC5D0 \uB178\uCD9C\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
87
91
|
tableOfContentsTitle: "\uBAA9\uCC28"
|
|
88
92
|
},
|
|
89
93
|
en: {
|
|
@@ -93,6 +97,8 @@ var DICTS = {
|
|
|
93
97
|
relatedPostsTitle: "Related posts",
|
|
94
98
|
postNotFound: "Post not found.",
|
|
95
99
|
pageNotFound: "Page not found.",
|
|
100
|
+
previewExpired: "This preview link has expired. Open the preview again from the admin editor.",
|
|
101
|
+
previewNotice: "Preview \u2014 this content is not public and is hidden from search engines.",
|
|
96
102
|
tableOfContentsTitle: "Table of contents"
|
|
97
103
|
}
|
|
98
104
|
};
|
|
@@ -660,20 +666,22 @@ import {
|
|
|
660
666
|
resolvePostPath
|
|
661
667
|
} from "@roottale/cms-core";
|
|
662
668
|
function defaultPostHref(post) {
|
|
663
|
-
return `/blog/${post.slug}`;
|
|
669
|
+
return storedPostPath(post) ?? `/blog/${post.slug}`;
|
|
664
670
|
}
|
|
665
671
|
function defaultAuthorHref(slug) {
|
|
666
672
|
return `/blog/author/${slug}`;
|
|
667
673
|
}
|
|
668
674
|
function makeCollectionPostHref(collections) {
|
|
669
675
|
return (post) => {
|
|
676
|
+
const stored = storedPostPath(post);
|
|
677
|
+
if (stored) return stored;
|
|
670
678
|
const path = resolvePostPath(post, collections);
|
|
671
679
|
if (path) return path;
|
|
672
680
|
const collection = resolvePostCollection(post, collections);
|
|
673
681
|
if (collection?.detail === false && collection.basePath) {
|
|
674
682
|
return collection.basePath;
|
|
675
683
|
}
|
|
676
|
-
return
|
|
684
|
+
return `/blog/${post.slug}`;
|
|
677
685
|
};
|
|
678
686
|
}
|
|
679
687
|
|
|
@@ -850,7 +858,9 @@ async function RootTaleBlogCategories(props) {
|
|
|
850
858
|
// src/server/blog-post.tsx
|
|
851
859
|
import {
|
|
852
860
|
fetchPost,
|
|
861
|
+
fetchPostPreview,
|
|
853
862
|
fetchPosts as fetchPosts2,
|
|
863
|
+
isPreviewExpiredError,
|
|
854
864
|
resolvePostDisplay as resolvePostDisplay2,
|
|
855
865
|
selectRelatedPosts
|
|
856
866
|
} from "@roottale/cms-client/server";
|
|
@@ -1538,10 +1548,35 @@ function authorImageRadiusCss(radius) {
|
|
|
1538
1548
|
if (radius === "rounded") return "0.875rem";
|
|
1539
1549
|
return "0";
|
|
1540
1550
|
}
|
|
1551
|
+
async function lookupPost(input) {
|
|
1552
|
+
if (input.previewToken) {
|
|
1553
|
+
try {
|
|
1554
|
+
const preview = await fetchPostPreview({
|
|
1555
|
+
apiKey: input.apiKey,
|
|
1556
|
+
baseUrl: input.baseUrl,
|
|
1557
|
+
token: input.previewToken
|
|
1558
|
+
});
|
|
1559
|
+
return preview ? { kind: "post", post: preview } : { kind: "missing" };
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
if (isPreviewExpiredError(error)) return { kind: "preview-expired" };
|
|
1562
|
+
throw error;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
if (!input.slugOrId) return { kind: "missing" };
|
|
1566
|
+
const post = await fetchPost({
|
|
1567
|
+
apiKey: input.apiKey,
|
|
1568
|
+
slugOrId: input.slugOrId,
|
|
1569
|
+
baseUrl: input.baseUrl,
|
|
1570
|
+
...input.locale ? { locale: input.locale } : {}
|
|
1571
|
+
});
|
|
1572
|
+
return post ? { kind: "post", post } : { kind: "missing" };
|
|
1573
|
+
}
|
|
1541
1574
|
async function RootTaleBlogPost(props) {
|
|
1542
1575
|
const {
|
|
1543
1576
|
apiKey,
|
|
1544
1577
|
slugOrId,
|
|
1578
|
+
previewToken,
|
|
1579
|
+
previewExpiredElement,
|
|
1545
1580
|
baseUrl,
|
|
1546
1581
|
notFoundElement,
|
|
1547
1582
|
showTitle = true,
|
|
@@ -1556,14 +1591,18 @@ async function RootTaleBlogPost(props) {
|
|
|
1556
1591
|
authorHref = defaultAuthorHref,
|
|
1557
1592
|
breadcrumb
|
|
1558
1593
|
} = props;
|
|
1559
|
-
const [
|
|
1560
|
-
|
|
1594
|
+
const [lookup, themeStyle, blogSettings] = await Promise.all([
|
|
1595
|
+
lookupPost({ apiKey, baseUrl, slugOrId, previewToken, locale }),
|
|
1561
1596
|
resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl }),
|
|
1562
1597
|
fetchBlogSettingsFailSoft({ apiKey, baseUrl })
|
|
1563
1598
|
]);
|
|
1564
|
-
if (
|
|
1599
|
+
if (lookup.kind === "preview-expired") {
|
|
1600
|
+
return previewExpiredElement ?? /* @__PURE__ */ jsx17("div", { "data-roottale-cms": "post-preview-expired", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx17("p", { className: "rt-cms-empty", children: t(locale, "previewExpired") }) });
|
|
1601
|
+
}
|
|
1602
|
+
if (lookup.kind === "missing") {
|
|
1565
1603
|
return notFoundElement ?? /* @__PURE__ */ jsx17("div", { "data-roottale-cms": "post-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx17("p", { className: "rt-cms-empty", children: t(locale, "postNotFound") }) });
|
|
1566
1604
|
}
|
|
1605
|
+
const post = lookup.post;
|
|
1567
1606
|
const display = resolvePostDisplay2(post, blogSettings, {
|
|
1568
1607
|
showTableOfContents,
|
|
1569
1608
|
tableOfContentsTitle
|
|
@@ -1703,9 +1742,32 @@ async function RootTaleBlogPost(props) {
|
|
|
1703
1742
|
);
|
|
1704
1743
|
}
|
|
1705
1744
|
|
|
1745
|
+
// src/server/preview-notice.tsx
|
|
1746
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1747
|
+
function formatExpiry(locale, iso) {
|
|
1748
|
+
const date = new Date(iso);
|
|
1749
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
1750
|
+
const time = new Intl.DateTimeFormat(locale === "en" ? "en-US" : "ko-KR", {
|
|
1751
|
+
hour: "2-digit",
|
|
1752
|
+
minute: "2-digit"
|
|
1753
|
+
}).format(date);
|
|
1754
|
+
return locale === "en" ? `Valid until ${time}.` : `${time}\uAE4C\uC9C0 \uBCFC \uC218 \uC788\uC5B4\uC694.`;
|
|
1755
|
+
}
|
|
1756
|
+
function RootTalePreviewNotice({
|
|
1757
|
+
locale,
|
|
1758
|
+
message,
|
|
1759
|
+
expiresAt
|
|
1760
|
+
}) {
|
|
1761
|
+
const expiry = expiresAt ? formatExpiry(locale, expiresAt) : null;
|
|
1762
|
+
return /* @__PURE__ */ jsxs14("div", { "data-roottale-cms": "preview-notice", className: "rt-cms-preview-notice", role: "status", children: [
|
|
1763
|
+
/* @__PURE__ */ jsx18("span", { children: message ?? t(locale, "previewNotice") }),
|
|
1764
|
+
expiry ? /* @__PURE__ */ jsx18("span", { className: "rt-cms-preview-notice__expiry", children: expiry }) : null
|
|
1765
|
+
] });
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1706
1768
|
// src/server/page.tsx
|
|
1707
1769
|
import { fetchPost as fetchPost2 } from "@roottale/cms-client/server";
|
|
1708
|
-
import { jsx as
|
|
1770
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1709
1771
|
async function RootTalePage(props) {
|
|
1710
1772
|
const {
|
|
1711
1773
|
apiKey,
|
|
@@ -1722,19 +1784,19 @@ async function RootTalePage(props) {
|
|
|
1722
1784
|
resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl })
|
|
1723
1785
|
]);
|
|
1724
1786
|
if (!post) {
|
|
1725
|
-
return notFoundElement ?? /* @__PURE__ */
|
|
1787
|
+
return notFoundElement ?? /* @__PURE__ */ jsx19("div", { "data-roottale-cms": "page-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx19("p", { className: "rt-cms-empty", children: t(locale, "pageNotFound") }) });
|
|
1726
1788
|
}
|
|
1727
1789
|
const pageBodySource = resolvePostBodySource(post.bodyHtml);
|
|
1728
1790
|
const bodyJson = pageBodySource.kind === "json" && prepareBody ? await prepareBody(post.bodyJson) : post.bodyJson;
|
|
1729
|
-
return /* @__PURE__ */
|
|
1791
|
+
return /* @__PURE__ */ jsxs15(
|
|
1730
1792
|
"article",
|
|
1731
1793
|
{
|
|
1732
1794
|
"data-roottale-cms": "page",
|
|
1733
1795
|
className: "rt-cms-article",
|
|
1734
1796
|
style: themeStyle ?? void 0,
|
|
1735
1797
|
children: [
|
|
1736
|
-
showTitle ? /* @__PURE__ */
|
|
1737
|
-
/* @__PURE__ */
|
|
1798
|
+
showTitle ? /* @__PURE__ */ jsx19("header", { className: "rt-cms-post-header", children: /* @__PURE__ */ jsx19("h1", { className: "rt-cms-title", children: post.title }) }) : null,
|
|
1799
|
+
/* @__PURE__ */ jsx19("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: pageBodySource.kind === "html" ? /* @__PURE__ */ jsx19("div", { dangerouslySetInnerHTML: { __html: pageBodySource.html } }) : /* @__PURE__ */ jsx19(
|
|
1738
1800
|
RenderTiptap,
|
|
1739
1801
|
{
|
|
1740
1802
|
doc: bodyJson,
|
|
@@ -1750,7 +1812,7 @@ async function RootTalePage(props) {
|
|
|
1750
1812
|
|
|
1751
1813
|
// src/server/exposure-slot.tsx
|
|
1752
1814
|
import { fetchExposure } from "@roottale/cms-client/server";
|
|
1753
|
-
import { jsx as
|
|
1815
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1754
1816
|
async function RootTaleExposureSlot(props) {
|
|
1755
1817
|
const campaign = await fetchExposure({
|
|
1756
1818
|
apiKey: props.apiKey,
|
|
@@ -1761,7 +1823,7 @@ async function RootTaleExposureSlot(props) {
|
|
|
1761
1823
|
revalidate: props.revalidate
|
|
1762
1824
|
});
|
|
1763
1825
|
if (!campaign || !props.allowedVariants.includes(campaign.content.variant)) return null;
|
|
1764
|
-
return /* @__PURE__ */
|
|
1826
|
+
return /* @__PURE__ */ jsx20(RootTaleExposure, { campaign, allowedVariants: props.allowedVariants });
|
|
1765
1827
|
}
|
|
1766
1828
|
export {
|
|
1767
1829
|
RenderTiptap,
|
|
@@ -1774,6 +1836,7 @@ export {
|
|
|
1774
1836
|
RootTaleLeadForm,
|
|
1775
1837
|
RootTalePage,
|
|
1776
1838
|
RootTalePostCard,
|
|
1839
|
+
RootTalePreviewNotice,
|
|
1777
1840
|
RootTaleTableOfContents,
|
|
1778
1841
|
RootTaleThemeProvider,
|
|
1779
1842
|
attachHeadingIds,
|
|
@@ -1783,6 +1846,7 @@ export {
|
|
|
1783
1846
|
extractToc,
|
|
1784
1847
|
filterPostsByCategory,
|
|
1785
1848
|
headingToId,
|
|
1849
|
+
makeCategoryHref,
|
|
1786
1850
|
renderBlock,
|
|
1787
1851
|
renderBlocks,
|
|
1788
1852
|
renderBoundBlocks,
|