@roottale/cms-renderer-next 0.55.0 → 0.57.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 +59 -0
- package/dist/{blog-filter-BQNQL3Mk.d.ts → blog-filter-qE9Lj49C.d.ts} +7 -1
- package/dist/{chunk-FJANIAZN.js → chunk-GDP2VGJR.js} +38 -6
- package/dist/chunk-GDP2VGJR.js.map +1 -0
- package/dist/cms-public.css +25 -3
- package/dist/routes.d.ts +42 -8
- package/dist/routes.js +35 -16
- package/dist/routes.js.map +1 -1
- package/dist/server.d.ts +49 -4
- package/dist/server.js +394 -213
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-FJANIAZN.js.map +0 -1
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";
|
|
@@ -664,20 +666,22 @@ import {
|
|
|
664
666
|
resolvePostPath
|
|
665
667
|
} from "@roottale/cms-core";
|
|
666
668
|
function defaultPostHref(post) {
|
|
667
|
-
return `/blog/${post.slug}`;
|
|
669
|
+
return storedPostPath(post) ?? `/blog/${post.slug}`;
|
|
668
670
|
}
|
|
669
671
|
function defaultAuthorHref(slug) {
|
|
670
672
|
return `/blog/author/${slug}`;
|
|
671
673
|
}
|
|
672
674
|
function makeCollectionPostHref(collections) {
|
|
673
675
|
return (post) => {
|
|
676
|
+
const stored = storedPostPath(post);
|
|
677
|
+
if (stored) return stored;
|
|
674
678
|
const path = resolvePostPath(post, collections);
|
|
675
679
|
if (path) return path;
|
|
676
680
|
const collection = resolvePostCollection(post, collections);
|
|
677
681
|
if (collection?.detail === false && collection.basePath) {
|
|
678
682
|
return collection.basePath;
|
|
679
683
|
}
|
|
680
|
-
return
|
|
684
|
+
return `/blog/${post.slug}`;
|
|
681
685
|
};
|
|
682
686
|
}
|
|
683
687
|
|
|
@@ -853,115 +857,27 @@ async function RootTaleBlogCategories(props) {
|
|
|
853
857
|
|
|
854
858
|
// src/server/blog-post.tsx
|
|
855
859
|
import {
|
|
860
|
+
POST_FOOTER_PATTERN_SLOT as POST_FOOTER_PATTERN_SLOT2,
|
|
856
861
|
fetchPost,
|
|
857
862
|
fetchPostPreview,
|
|
858
|
-
fetchPosts as
|
|
863
|
+
fetchPosts as fetchPosts3,
|
|
859
864
|
isPreviewExpiredError,
|
|
860
865
|
resolvePostDisplay as resolvePostDisplay2,
|
|
861
866
|
selectRelatedPosts
|
|
862
867
|
} from "@roottale/cms-client/server";
|
|
863
868
|
|
|
864
|
-
// src/server/
|
|
865
|
-
import {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
"select",
|
|
872
|
-
"radio",
|
|
873
|
-
"button_group",
|
|
874
|
-
"number",
|
|
875
|
-
"range"
|
|
876
|
-
]);
|
|
877
|
-
function archiveGroupTitle(group) {
|
|
878
|
-
if (group.collectionKey === "conditions") {
|
|
879
|
-
return `\uC774 \uC99D\uC0C1\uACFC \uAD00\uB828\uB41C \uC9C8\uD658 ${group.items.length}`;
|
|
880
|
-
}
|
|
881
|
-
if (group.collectionKey === "treatments") {
|
|
882
|
-
return `\uAD00\uB828 \uCE58\uB8CC\uBC95 ${group.items.length}`;
|
|
883
|
-
}
|
|
884
|
-
if (group.collectionKey === "symptoms") {
|
|
885
|
-
return `\uAD00\uB828 \uC99D\uC0C1 ${group.items.length}`;
|
|
886
|
-
}
|
|
887
|
-
return `${group.label} ${group.items.length}`;
|
|
888
|
-
}
|
|
889
|
-
function defaultArchiveBasePath(collectionKey) {
|
|
890
|
-
if (collectionKey === "symptoms") return "/symptoms";
|
|
891
|
-
if (collectionKey === "conditions") return "/conditions";
|
|
892
|
-
if (collectionKey === "treatments") return "/treatments";
|
|
893
|
-
return "/blog";
|
|
894
|
-
}
|
|
895
|
-
function archivePostHref(collectionKey, slug, collections) {
|
|
896
|
-
const collection = collections?.find((item) => item.key === collectionKey);
|
|
897
|
-
const basePath = collection?.basePath || defaultArchiveBasePath(collectionKey);
|
|
898
|
-
const trimmedBase = basePath.replace(/\/+$/, "");
|
|
899
|
-
if (collection?.detail === false) return trimmedBase;
|
|
900
|
-
return `${trimmedBase}/${slug}`;
|
|
901
|
-
}
|
|
902
|
-
function renderArchiveRelated(groups, collections) {
|
|
903
|
-
const visibleGroups = groups.filter((group) => group.items.length > 0);
|
|
904
|
-
if (visibleGroups.length === 0) return null;
|
|
905
|
-
return /* @__PURE__ */ jsx9("aside", { className: "rt-archive-related", "aria-label": "\uC5F0\uAD00 \uC815\uBCF4", children: visibleGroups.map((group) => /* @__PURE__ */ jsxs8("section", { className: "rt-archive-related__group", children: [
|
|
906
|
-
/* @__PURE__ */ jsx9("h2", { className: "rt-archive-related__title", children: archiveGroupTitle(group) }),
|
|
907
|
-
/* @__PURE__ */ jsx9("ul", { className: "rt-archive-related__list", children: group.items.map((item) => /* @__PURE__ */ jsx9("li", { className: "rt-archive-related__item", children: /* @__PURE__ */ jsxs8(
|
|
908
|
-
"a",
|
|
909
|
-
{
|
|
910
|
-
className: "rt-archive-related__link",
|
|
911
|
-
href: archivePostHref(
|
|
912
|
-
item.collectionKey,
|
|
913
|
-
item.slug,
|
|
914
|
-
collections
|
|
915
|
-
),
|
|
916
|
-
children: [
|
|
917
|
-
/* @__PURE__ */ jsx9("span", { className: "rt-archive-related__item-title", children: item.title }),
|
|
918
|
-
item.excerpt ? /* @__PURE__ */ jsx9("span", { className: "rt-archive-related__item-excerpt", children: item.excerpt }) : null
|
|
919
|
-
]
|
|
920
|
-
}
|
|
921
|
-
) }, item.id)) })
|
|
922
|
-
] }, group.collectionKey)) });
|
|
923
|
-
}
|
|
924
|
-
function fieldFactValue(raw, meta) {
|
|
925
|
-
if (raw === null || raw === void 0) return null;
|
|
926
|
-
if (typeof raw === "number") return raw.toLocaleString("ko-KR");
|
|
927
|
-
if (typeof raw !== "string" || raw.trim() === "") return null;
|
|
928
|
-
if (!meta.choices) return raw;
|
|
929
|
-
const choice = meta.choices.find((item) => item.value === raw);
|
|
930
|
-
return choice ? choice.label : raw;
|
|
931
|
-
}
|
|
932
|
-
function renderFieldFacts(post) {
|
|
933
|
-
if (!post.fields) return null;
|
|
934
|
-
const rows = post.fieldsMeta.filter((meta) => FIELD_FACT_TYPES.has(meta.type)).flatMap((meta) => {
|
|
935
|
-
const value = fieldFactValue(post.fields?.[meta.name], meta);
|
|
936
|
-
return value === null ? [] : [{ meta, value }];
|
|
937
|
-
});
|
|
938
|
-
if (rows.length === 0) return null;
|
|
939
|
-
return /* @__PURE__ */ jsx9("aside", { className: "rt-archive-facts", "aria-label": "\uC0C1\uC138 \uC815\uBCF4", children: /* @__PURE__ */ jsx9("dl", { className: "rt-archive-facts__list", children: rows.map(({ meta, value }) => /* @__PURE__ */ jsxs8("div", { className: "rt-archive-facts__row", children: [
|
|
940
|
-
/* @__PURE__ */ jsx9("dt", { className: "rt-archive-facts__label", children: meta.label }),
|
|
941
|
-
/* @__PURE__ */ jsx9(
|
|
942
|
-
"dd",
|
|
943
|
-
{
|
|
944
|
-
className: meta.type === "textarea" ? "rt-archive-facts__value rt-archive-facts__value--multiline" : "rt-archive-facts__value",
|
|
945
|
-
children: value
|
|
946
|
-
}
|
|
947
|
-
)
|
|
948
|
-
] }, meta.name)) }) });
|
|
949
|
-
}
|
|
869
|
+
// src/server/site-patterns.tsx
|
|
870
|
+
import {
|
|
871
|
+
POST_FOOTER_PATTERN_SLOT,
|
|
872
|
+
SITE_PATTERNS_CACHE_TAG,
|
|
873
|
+
fetchSitePatterns,
|
|
874
|
+
selectSitePatternForSlot
|
|
875
|
+
} from "@roottale/cms-client/server";
|
|
950
876
|
|
|
951
|
-
// src/server/
|
|
952
|
-
import {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
return html.replace(/<[^>]*>/g, "").replace(/ /gi, " ").trim().length > 0;
|
|
956
|
-
}
|
|
957
|
-
function resolvePostBodySource(bodyHtml) {
|
|
958
|
-
if (typeof bodyHtml !== "string") return { kind: "json" };
|
|
959
|
-
const trimmed = bodyHtml.trim();
|
|
960
|
-
if (trimmed.length === 0) return { kind: "json" };
|
|
961
|
-
const sanitized = sanitizeHtml2(trimmed);
|
|
962
|
-
if (!hasVisibleContent(sanitized)) return { kind: "json" };
|
|
963
|
-
return { kind: "html", html: sanitized };
|
|
964
|
-
}
|
|
877
|
+
// src/server/render-tiptap.tsx
|
|
878
|
+
import {
|
|
879
|
+
internalContentLinkResolverFrom
|
|
880
|
+
} from "@roottale/cms-core";
|
|
965
881
|
|
|
966
882
|
// src/server/tiptap-node-renderer.tsx
|
|
967
883
|
import { Fragment as Fragment4 } from "react";
|
|
@@ -971,12 +887,13 @@ import {
|
|
|
971
887
|
boundFieldValue,
|
|
972
888
|
ensureImportedHtmlDocumentRoots,
|
|
973
889
|
normalizeImageAlt,
|
|
890
|
+
renderInternalContentLinksInHtml,
|
|
974
891
|
scopeImportedCss
|
|
975
892
|
} from "@roottale/cms-core";
|
|
976
893
|
|
|
977
894
|
// src/server/tiptap-embed-renderer.tsx
|
|
978
895
|
import { isAllowedEmbedSrc } from "@roottale/cms-core";
|
|
979
|
-
import { jsx as
|
|
896
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
980
897
|
function isSafeFallbackHref(value) {
|
|
981
898
|
if (typeof value !== "string") return false;
|
|
982
899
|
const href = value.trim();
|
|
@@ -990,13 +907,13 @@ function renderEmbedNode(node, key) {
|
|
|
990
907
|
const src = node.attrs?.src;
|
|
991
908
|
if (isAllowedEmbedSrc(src)) {
|
|
992
909
|
const provider = typeof node.attrs?.provider === "string" ? node.attrs.provider : void 0;
|
|
993
|
-
return /* @__PURE__ */
|
|
910
|
+
return /* @__PURE__ */ jsx9(
|
|
994
911
|
"div",
|
|
995
912
|
{
|
|
996
913
|
className: "rt-embed",
|
|
997
914
|
"data-provider": provider,
|
|
998
915
|
style: { aspectRatio: "16 / 9" },
|
|
999
|
-
children: /* @__PURE__ */
|
|
916
|
+
children: /* @__PURE__ */ jsx9(
|
|
1000
917
|
"iframe",
|
|
1001
918
|
{
|
|
1002
919
|
src,
|
|
@@ -1014,9 +931,17 @@ function renderEmbedNode(node, key) {
|
|
|
1014
931
|
}
|
|
1015
932
|
const originalUrl = node.attrs?.originalUrl;
|
|
1016
933
|
if (!isSafeFallbackHref(originalUrl)) return null;
|
|
1017
|
-
return /* @__PURE__ */
|
|
934
|
+
return /* @__PURE__ */ jsx9("p", { className: "rt-embed-fallback", children: /* @__PURE__ */ jsx9("a", { href: originalUrl, rel: "noopener noreferrer", target: "_blank", children: originalUrl }) }, key);
|
|
1018
935
|
}
|
|
1019
936
|
|
|
937
|
+
// src/server/tiptap-inline-renderer.tsx
|
|
938
|
+
import {
|
|
939
|
+
findInternalContentLinkTokens,
|
|
940
|
+
INTERNAL_CONTENT_LINK_CLASS,
|
|
941
|
+
INTERNAL_CONTENT_LINK_PENDING_ATTR,
|
|
942
|
+
INTERNAL_CONTENT_LINK_PENDING_CLASS
|
|
943
|
+
} from "@roottale/cms-core";
|
|
944
|
+
|
|
1020
945
|
// src/server/tiptap-types.ts
|
|
1021
946
|
function isRecord(value) {
|
|
1022
947
|
return typeof value === "object" && value !== null;
|
|
@@ -1040,7 +965,7 @@ function parseTiptapMark(value) {
|
|
|
1040
965
|
}
|
|
1041
966
|
|
|
1042
967
|
// src/server/tiptap-inline-renderer.tsx
|
|
1043
|
-
import { Fragment as Fragment3, jsx as
|
|
968
|
+
import { Fragment as Fragment3, jsx as jsx10 } from "react/jsx-runtime";
|
|
1044
969
|
function isSafeHref(value) {
|
|
1045
970
|
if (typeof value !== "string") return false;
|
|
1046
971
|
const href = value.trim();
|
|
@@ -1053,52 +978,86 @@ function isSafeHref(value) {
|
|
|
1053
978
|
function applyMark(mark, child) {
|
|
1054
979
|
switch (mark.type) {
|
|
1055
980
|
case "bold":
|
|
1056
|
-
return /* @__PURE__ */
|
|
981
|
+
return /* @__PURE__ */ jsx10("strong", { children: child });
|
|
1057
982
|
case "italic":
|
|
1058
|
-
return /* @__PURE__ */
|
|
983
|
+
return /* @__PURE__ */ jsx10("em", { children: child });
|
|
1059
984
|
case "underline":
|
|
1060
|
-
return /* @__PURE__ */
|
|
985
|
+
return /* @__PURE__ */ jsx10("u", { children: child });
|
|
1061
986
|
case "strike":
|
|
1062
|
-
return /* @__PURE__ */
|
|
987
|
+
return /* @__PURE__ */ jsx10("s", { children: child });
|
|
1063
988
|
case "code":
|
|
1064
|
-
return /* @__PURE__ */
|
|
989
|
+
return /* @__PURE__ */ jsx10("code", { children: child });
|
|
1065
990
|
case "highlight": {
|
|
1066
991
|
const color = mark.attrs?.color;
|
|
1067
992
|
const style = typeof color === "string" && color.length > 0 ? { background: color } : void 0;
|
|
1068
|
-
return /* @__PURE__ */
|
|
993
|
+
return /* @__PURE__ */ jsx10("mark", { style, children: child });
|
|
1069
994
|
}
|
|
1070
995
|
case "textStyle": {
|
|
1071
996
|
const color = mark.attrs?.color;
|
|
1072
997
|
if (typeof color !== "string" || color.length === 0) {
|
|
1073
|
-
return /* @__PURE__ */
|
|
998
|
+
return /* @__PURE__ */ jsx10(Fragment3, { children: child });
|
|
1074
999
|
}
|
|
1075
|
-
return /* @__PURE__ */
|
|
1000
|
+
return /* @__PURE__ */ jsx10("span", { style: { color }, children: child });
|
|
1076
1001
|
}
|
|
1077
1002
|
case "link": {
|
|
1078
1003
|
const rawHref = mark.attrs?.href;
|
|
1079
1004
|
const href = isSafeHref(rawHref) ? rawHref : "#";
|
|
1080
|
-
return /* @__PURE__ */
|
|
1005
|
+
return /* @__PURE__ */ jsx10("a", { href, rel: "noopener noreferrer", target: "_blank", children: child });
|
|
1081
1006
|
}
|
|
1082
1007
|
default:
|
|
1083
|
-
return /* @__PURE__ */
|
|
1008
|
+
return /* @__PURE__ */ jsx10("span", { children: child });
|
|
1084
1009
|
}
|
|
1085
1010
|
}
|
|
1086
|
-
function
|
|
1011
|
+
function isSafeInternalPath(path) {
|
|
1012
|
+
return typeof path === "string" && path.startsWith("/") && !path.startsWith("//");
|
|
1013
|
+
}
|
|
1014
|
+
function renderInternalLinkText(text, resolve) {
|
|
1015
|
+
const tokens = findInternalContentLinkTokens(text);
|
|
1016
|
+
if (tokens.length === 0) return text;
|
|
1017
|
+
const parts = [];
|
|
1018
|
+
let cursor = 0;
|
|
1019
|
+
tokens.forEach((token, index) => {
|
|
1020
|
+
if (token.index > cursor) parts.push(text.slice(cursor, token.index));
|
|
1021
|
+
const path = resolve(token.key);
|
|
1022
|
+
parts.push(
|
|
1023
|
+
isSafeInternalPath(path) ? /* @__PURE__ */ jsx10("a", { href: path, className: INTERNAL_CONTENT_LINK_CLASS, children: token.label }, index) : /* @__PURE__ */ jsx10(
|
|
1024
|
+
"span",
|
|
1025
|
+
{
|
|
1026
|
+
className: `${INTERNAL_CONTENT_LINK_CLASS} ${INTERNAL_CONTENT_LINK_PENDING_CLASS}`,
|
|
1027
|
+
...{ [INTERNAL_CONTENT_LINK_PENDING_ATTR]: token.key },
|
|
1028
|
+
children: token.label
|
|
1029
|
+
},
|
|
1030
|
+
index
|
|
1031
|
+
)
|
|
1032
|
+
);
|
|
1033
|
+
cursor = token.index + token.raw.length;
|
|
1034
|
+
});
|
|
1035
|
+
if (cursor < text.length) parts.push(text.slice(cursor));
|
|
1036
|
+
return /* @__PURE__ */ jsx10(Fragment3, { children: parts });
|
|
1037
|
+
}
|
|
1038
|
+
function renderTextNode(node, key, internalLinks = null) {
|
|
1087
1039
|
const text = node.text ?? "";
|
|
1088
1040
|
const marks = (node.marks ?? []).flatMap((value) => {
|
|
1089
1041
|
const mark = parseTiptapMark(value);
|
|
1090
1042
|
return mark ? [mark] : [];
|
|
1091
1043
|
});
|
|
1092
|
-
|
|
1093
|
-
|
|
1044
|
+
const canLink = internalLinks !== null && !marks.some((mark) => mark.type === "code" || mark.type === "link");
|
|
1045
|
+
const content = canLink && internalLinks ? renderInternalLinkText(text, internalLinks) : text;
|
|
1046
|
+
if (marks.length === 0) {
|
|
1047
|
+
return typeof content === "string" ? content : /* @__PURE__ */ jsx10("span", { children: content }, key);
|
|
1048
|
+
}
|
|
1049
|
+
let element = typeof content === "string" ? content : /* @__PURE__ */ jsx10(Fragment3, { children: content });
|
|
1094
1050
|
for (const mark of marks) {
|
|
1095
1051
|
element = applyMark(mark, element);
|
|
1096
1052
|
}
|
|
1097
|
-
return /* @__PURE__ */
|
|
1053
|
+
return /* @__PURE__ */ jsx10("span", { children: element }, key);
|
|
1098
1054
|
}
|
|
1099
1055
|
|
|
1100
1056
|
// src/server/tiptap-node-renderer.tsx
|
|
1101
|
-
import { jsx as
|
|
1057
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1058
|
+
function withInternalLinksInHtml(html, internalLinks) {
|
|
1059
|
+
return internalLinks ? renderInternalContentLinksInHtml(html, internalLinks).html : html;
|
|
1060
|
+
}
|
|
1102
1061
|
function boundContentText(node, fields) {
|
|
1103
1062
|
return bindingTextValue(
|
|
1104
1063
|
boundFieldValue(node.attrs?.bindings, "content", fields)
|
|
@@ -1131,7 +1090,7 @@ function renderTiptapNode(value, key, context) {
|
|
|
1131
1090
|
switch (node.type) {
|
|
1132
1091
|
case "paragraph": {
|
|
1133
1092
|
const bound = boundContentText(node, context.fields);
|
|
1134
|
-
return /* @__PURE__ */
|
|
1093
|
+
return /* @__PURE__ */ jsx11("p", { style: alignStyle(node), children: bound ?? children }, key);
|
|
1135
1094
|
}
|
|
1136
1095
|
case "heading": {
|
|
1137
1096
|
const rawLevel = Number(node.attrs?.level ?? 2);
|
|
@@ -1142,27 +1101,29 @@ function renderTiptapNode(value, key, context) {
|
|
|
1142
1101
|
const style = alignStyle(node);
|
|
1143
1102
|
const inner = boundContentText(node, context.fields) ?? children;
|
|
1144
1103
|
if (level === 2) {
|
|
1145
|
-
return /* @__PURE__ */
|
|
1104
|
+
return /* @__PURE__ */ jsx11("h2", { id, style, children: inner }, key);
|
|
1146
1105
|
}
|
|
1147
1106
|
if (level === 3) {
|
|
1148
|
-
return /* @__PURE__ */
|
|
1107
|
+
return /* @__PURE__ */ jsx11("h3", { id, style, children: inner }, key);
|
|
1149
1108
|
}
|
|
1150
|
-
return /* @__PURE__ */
|
|
1109
|
+
return /* @__PURE__ */ jsx11("h4", { id, style, children: inner }, key);
|
|
1151
1110
|
}
|
|
1152
1111
|
case "bulletList":
|
|
1153
|
-
return /* @__PURE__ */
|
|
1112
|
+
return /* @__PURE__ */ jsx11("ul", { children }, key);
|
|
1154
1113
|
case "orderedList":
|
|
1155
|
-
return /* @__PURE__ */
|
|
1114
|
+
return /* @__PURE__ */ jsx11("ol", { children }, key);
|
|
1156
1115
|
case "listItem":
|
|
1157
|
-
return /* @__PURE__ */
|
|
1116
|
+
return /* @__PURE__ */ jsx11("li", { children }, key);
|
|
1158
1117
|
case "blockquote":
|
|
1159
|
-
return /* @__PURE__ */
|
|
1118
|
+
return /* @__PURE__ */ jsx11("blockquote", { children }, key);
|
|
1160
1119
|
case "codeBlock":
|
|
1161
|
-
return /* @__PURE__ */
|
|
1120
|
+
return /* @__PURE__ */ jsx11("pre", { children: /* @__PURE__ */ jsx11("code", { children: node.content?.map(
|
|
1121
|
+
(child, index) => renderTiptapNode(child, index, { ...context, internalLinks: null })
|
|
1122
|
+
) }) }, key);
|
|
1162
1123
|
case "horizontalRule":
|
|
1163
|
-
return /* @__PURE__ */
|
|
1124
|
+
return /* @__PURE__ */ jsx11("hr", {}, key);
|
|
1164
1125
|
case "hardBreak":
|
|
1165
|
-
return /* @__PURE__ */
|
|
1126
|
+
return /* @__PURE__ */ jsx11("br", {}, key);
|
|
1166
1127
|
case "image": {
|
|
1167
1128
|
const boundSrc = bindingSrcValue(
|
|
1168
1129
|
boundFieldValue(node.attrs?.bindings, "src", context.fields)
|
|
@@ -1173,7 +1134,7 @@ function renderTiptapNode(value, key, context) {
|
|
|
1173
1134
|
const title = typeof node.attrs?.title === "string" ? node.attrs.title : void 0;
|
|
1174
1135
|
const width = typeof node.attrs?.width === "number" && node.attrs.width > 0 ? node.attrs.width : void 0;
|
|
1175
1136
|
const height = typeof node.attrs?.height === "number" && node.attrs.height > 0 ? node.attrs.height : void 0;
|
|
1176
|
-
return /* @__PURE__ */
|
|
1137
|
+
return /* @__PURE__ */ jsx11(
|
|
1177
1138
|
"img",
|
|
1178
1139
|
{
|
|
1179
1140
|
src,
|
|
@@ -1198,59 +1159,62 @@ function renderTiptapNode(value, key, context) {
|
|
|
1198
1159
|
scope,
|
|
1199
1160
|
assetUrls
|
|
1200
1161
|
);
|
|
1201
|
-
return /* @__PURE__ */
|
|
1202
|
-
scopedCss ? /* @__PURE__ */
|
|
1203
|
-
/* @__PURE__ */
|
|
1162
|
+
return /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
1163
|
+
scopedCss ? /* @__PURE__ */ jsx11("style", { "data-rt-imported-style": scope, children: scopedCss }) : null,
|
|
1164
|
+
/* @__PURE__ */ jsx11(
|
|
1204
1165
|
"div",
|
|
1205
1166
|
{
|
|
1206
1167
|
className: "rt-imported-html",
|
|
1207
1168
|
"data-rt-import-scope": scopedCss ? scope : void 0,
|
|
1208
1169
|
style: { position: "relative", isolation: "isolate" },
|
|
1209
1170
|
dangerouslySetInnerHTML: {
|
|
1210
|
-
__html:
|
|
1171
|
+
__html: withInternalLinksInHtml(
|
|
1172
|
+
ensureImportedHtmlDocumentRoots(rawHtml, assetUrls),
|
|
1173
|
+
context.internalLinks ?? null
|
|
1174
|
+
)
|
|
1211
1175
|
}
|
|
1212
1176
|
}
|
|
1213
1177
|
)
|
|
1214
1178
|
] }, key);
|
|
1215
1179
|
}
|
|
1216
1180
|
case "columns":
|
|
1217
|
-
return /* @__PURE__ */
|
|
1181
|
+
return /* @__PURE__ */ jsx11("div", { className: "rt-columns", children }, key);
|
|
1218
1182
|
case "column":
|
|
1219
|
-
return /* @__PURE__ */
|
|
1183
|
+
return /* @__PURE__ */ jsx11("div", { className: "rt-column", children }, key);
|
|
1220
1184
|
case "table":
|
|
1221
|
-
return /* @__PURE__ */
|
|
1185
|
+
return /* @__PURE__ */ jsx11("div", { className: "rt-table-wrap", children: /* @__PURE__ */ jsx11("table", { className: "rt-table", children: /* @__PURE__ */ jsx11("tbody", { children }) }) }, key);
|
|
1222
1186
|
case "tableRow":
|
|
1223
|
-
return /* @__PURE__ */
|
|
1187
|
+
return /* @__PURE__ */ jsx11("tr", { children }, key);
|
|
1224
1188
|
case "tableHeader": {
|
|
1225
1189
|
const { colSpan, rowSpan } = tableCellSpans(node);
|
|
1226
|
-
return /* @__PURE__ */
|
|
1190
|
+
return /* @__PURE__ */ jsx11("th", { colSpan, rowSpan, children }, key);
|
|
1227
1191
|
}
|
|
1228
1192
|
case "tableCell": {
|
|
1229
1193
|
const { colSpan, rowSpan } = tableCellSpans(node);
|
|
1230
|
-
return /* @__PURE__ */
|
|
1194
|
+
return /* @__PURE__ */ jsx11("td", { colSpan, rowSpan, children }, key);
|
|
1231
1195
|
}
|
|
1232
1196
|
case "embed":
|
|
1233
1197
|
return renderEmbedNode(node, key);
|
|
1234
1198
|
case "faq":
|
|
1235
|
-
return /* @__PURE__ */
|
|
1199
|
+
return /* @__PURE__ */ jsx11("div", { "data-roottale-cms": "faq", className: "rt-cms-faq", children }, key);
|
|
1236
1200
|
case "faqItem":
|
|
1237
|
-
return /* @__PURE__ */
|
|
1201
|
+
return /* @__PURE__ */ jsx11("details", { className: "rt-cms-faq-item", children }, key);
|
|
1238
1202
|
case "faqQuestion":
|
|
1239
|
-
return /* @__PURE__ */
|
|
1203
|
+
return /* @__PURE__ */ jsx11("summary", { className: "rt-cms-faq-q", children }, key);
|
|
1240
1204
|
case "faqAnswer":
|
|
1241
|
-
return /* @__PURE__ */
|
|
1205
|
+
return /* @__PURE__ */ jsx11("div", { className: "rt-cms-faq-a", children }, key);
|
|
1242
1206
|
case "references": {
|
|
1243
1207
|
const rawTitle = node.attrs?.title;
|
|
1244
1208
|
const title = typeof rawTitle === "string" && rawTitle.trim() ? rawTitle.trim() : "\uACF5\uC2DD \uCD9C\uCC98";
|
|
1245
1209
|
const titleId = `rt-cms-references-${key}`;
|
|
1246
|
-
return /* @__PURE__ */
|
|
1210
|
+
return /* @__PURE__ */ jsxs8(
|
|
1247
1211
|
"section",
|
|
1248
1212
|
{
|
|
1249
1213
|
"data-roottale-cms": "references",
|
|
1250
1214
|
className: "rt-cms-references",
|
|
1251
1215
|
"aria-labelledby": titleId,
|
|
1252
1216
|
children: [
|
|
1253
|
-
/* @__PURE__ */
|
|
1217
|
+
/* @__PURE__ */ jsx11("h2", { id: titleId, className: "rt-cms-references__title", children: title }),
|
|
1254
1218
|
children
|
|
1255
1219
|
]
|
|
1256
1220
|
},
|
|
@@ -1272,14 +1236,14 @@ function renderTiptapNode(value, key, context) {
|
|
|
1272
1236
|
return renderSection(node, key, context.section);
|
|
1273
1237
|
}
|
|
1274
1238
|
case "text":
|
|
1275
|
-
return renderTextNode(node, key);
|
|
1239
|
+
return renderTextNode(node, key, context.internalLinks ?? null);
|
|
1276
1240
|
default:
|
|
1277
|
-
return children ? /* @__PURE__ */
|
|
1241
|
+
return children ? /* @__PURE__ */ jsx11("span", { children }, key) : null;
|
|
1278
1242
|
}
|
|
1279
1243
|
}
|
|
1280
1244
|
|
|
1281
1245
|
// src/server/render-tiptap.tsx
|
|
1282
|
-
import { Fragment as Fragment5, jsx as
|
|
1246
|
+
import { Fragment as Fragment5, jsx as jsx12 } from "react/jsx-runtime";
|
|
1283
1247
|
function isDevelopmentRuntime() {
|
|
1284
1248
|
const processValue = Reflect.get(globalThis, "process");
|
|
1285
1249
|
if (!isRecord(processValue)) return true;
|
|
@@ -1292,7 +1256,7 @@ function createSectionContextWithBlogListNetworkFetch(apiKey, baseUrl) {
|
|
|
1292
1256
|
return {
|
|
1293
1257
|
cms,
|
|
1294
1258
|
isDev: isDevelopmentRuntime,
|
|
1295
|
-
renderBlogList: (props) => /* @__PURE__ */
|
|
1259
|
+
renderBlogList: (props) => /* @__PURE__ */ jsx12(RootTaleBlogList, { ...props })
|
|
1296
1260
|
};
|
|
1297
1261
|
}
|
|
1298
1262
|
function contentNodes(doc) {
|
|
@@ -1302,7 +1266,8 @@ function RenderTiptap({
|
|
|
1302
1266
|
doc,
|
|
1303
1267
|
fields,
|
|
1304
1268
|
apiKey,
|
|
1305
|
-
baseUrl
|
|
1269
|
+
baseUrl,
|
|
1270
|
+
internalLinks
|
|
1306
1271
|
}) {
|
|
1307
1272
|
const content = contentNodes(doc);
|
|
1308
1273
|
const hasTableOfContents = content.some(
|
|
@@ -1312,15 +1277,16 @@ function RenderTiptap({
|
|
|
1312
1277
|
const renderDoc = hasTableOfContents && entries.length > 0 ? attachHeadingIds(doc, entries) : doc;
|
|
1313
1278
|
const context = {
|
|
1314
1279
|
fields: fields ?? null,
|
|
1315
|
-
section: createSectionContextWithBlogListNetworkFetch(apiKey, baseUrl)
|
|
1280
|
+
section: createSectionContextWithBlogListNetworkFetch(apiKey, baseUrl),
|
|
1281
|
+
internalLinks: internalLinks ? internalContentLinkResolverFrom(internalLinks) : null
|
|
1316
1282
|
};
|
|
1317
|
-
return /* @__PURE__ */
|
|
1283
|
+
return /* @__PURE__ */ jsx12(Fragment5, { children: contentNodes(renderDoc).map((value, index) => {
|
|
1318
1284
|
const node = parseTiptapNode(value);
|
|
1319
1285
|
if (node?.type !== "tableOfContents") {
|
|
1320
1286
|
return renderTiptapNode(value, index, context);
|
|
1321
1287
|
}
|
|
1322
1288
|
const title = node.attrs?.title;
|
|
1323
|
-
return /* @__PURE__ */
|
|
1289
|
+
return /* @__PURE__ */ jsx12(
|
|
1324
1290
|
RootTaleTableOfContents,
|
|
1325
1291
|
{
|
|
1326
1292
|
entries,
|
|
@@ -1331,8 +1297,152 @@ function RenderTiptap({
|
|
|
1331
1297
|
}) });
|
|
1332
1298
|
}
|
|
1333
1299
|
|
|
1300
|
+
// src/server/site-patterns.tsx
|
|
1301
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1302
|
+
async function resolvePostPatternFailSoft(post, input, slot = POST_FOOTER_PATTERN_SLOT) {
|
|
1303
|
+
const key = post.patternSlots?.[slot] ?? null;
|
|
1304
|
+
if (!key) return null;
|
|
1305
|
+
try {
|
|
1306
|
+
const patterns = await fetchSitePatterns({
|
|
1307
|
+
apiKey: input.apiKey,
|
|
1308
|
+
baseUrl: input.baseUrl,
|
|
1309
|
+
tags: [SITE_PATTERNS_CACHE_TAG]
|
|
1310
|
+
});
|
|
1311
|
+
return selectSitePatternForSlot(post.patternSlots, patterns, slot);
|
|
1312
|
+
} catch {
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function renderPostPattern(pattern, slot, input) {
|
|
1317
|
+
if (!pattern) return null;
|
|
1318
|
+
return /* @__PURE__ */ jsx13(
|
|
1319
|
+
"aside",
|
|
1320
|
+
{
|
|
1321
|
+
"data-roottale-cms": "post-pattern",
|
|
1322
|
+
"data-pattern-slot": slot,
|
|
1323
|
+
"data-pattern-key": pattern.key,
|
|
1324
|
+
className: "rt-cms-post-pattern",
|
|
1325
|
+
"aria-label": pattern.name,
|
|
1326
|
+
children: /* @__PURE__ */ jsx13(RenderTiptap, { doc: pattern.bodyJson, apiKey: input.apiKey, baseUrl: input.baseUrl })
|
|
1327
|
+
}
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
async function RootTalePostPattern(props) {
|
|
1331
|
+
const slot = props.slot ?? POST_FOOTER_PATTERN_SLOT;
|
|
1332
|
+
const pattern = await resolvePostPatternFailSoft(props.post, props, slot);
|
|
1333
|
+
return renderPostPattern(pattern, slot, props);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// src/server/blog-post-archive.tsx
|
|
1337
|
+
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1338
|
+
var FIELD_FACT_TYPES = /* @__PURE__ */ new Set([
|
|
1339
|
+
"text",
|
|
1340
|
+
"textarea",
|
|
1341
|
+
"email",
|
|
1342
|
+
"url",
|
|
1343
|
+
"select",
|
|
1344
|
+
"radio",
|
|
1345
|
+
"button_group",
|
|
1346
|
+
"number",
|
|
1347
|
+
"range"
|
|
1348
|
+
]);
|
|
1349
|
+
function archiveGroupTitle(group) {
|
|
1350
|
+
if (group.collectionKey === "conditions") {
|
|
1351
|
+
return `\uC774 \uC99D\uC0C1\uACFC \uAD00\uB828\uB41C \uC9C8\uD658 ${group.items.length}`;
|
|
1352
|
+
}
|
|
1353
|
+
if (group.collectionKey === "treatments") {
|
|
1354
|
+
return `\uAD00\uB828 \uCE58\uB8CC\uBC95 ${group.items.length}`;
|
|
1355
|
+
}
|
|
1356
|
+
if (group.collectionKey === "symptoms") {
|
|
1357
|
+
return `\uAD00\uB828 \uC99D\uC0C1 ${group.items.length}`;
|
|
1358
|
+
}
|
|
1359
|
+
return `${group.label} ${group.items.length}`;
|
|
1360
|
+
}
|
|
1361
|
+
function defaultArchiveBasePath(collectionKey) {
|
|
1362
|
+
if (collectionKey === "symptoms") return "/symptoms";
|
|
1363
|
+
if (collectionKey === "conditions") return "/conditions";
|
|
1364
|
+
if (collectionKey === "treatments") return "/treatments";
|
|
1365
|
+
return "/blog";
|
|
1366
|
+
}
|
|
1367
|
+
function archivePostHref(collectionKey, slug, collections) {
|
|
1368
|
+
const collection = collections?.find((item) => item.key === collectionKey);
|
|
1369
|
+
const basePath = collection?.basePath || defaultArchiveBasePath(collectionKey);
|
|
1370
|
+
const trimmedBase = basePath.replace(/\/+$/, "");
|
|
1371
|
+
if (collection?.detail === false) return trimmedBase;
|
|
1372
|
+
return `${trimmedBase}/${slug}`;
|
|
1373
|
+
}
|
|
1374
|
+
function renderArchiveRelated(groups, collections) {
|
|
1375
|
+
const visibleGroups = groups.filter((group) => group.items.length > 0);
|
|
1376
|
+
if (visibleGroups.length === 0) return null;
|
|
1377
|
+
return /* @__PURE__ */ jsx14("aside", { className: "rt-archive-related", "aria-label": "\uC5F0\uAD00 \uC815\uBCF4", children: visibleGroups.map((group) => /* @__PURE__ */ jsxs9("section", { className: "rt-archive-related__group", children: [
|
|
1378
|
+
/* @__PURE__ */ jsx14("h2", { className: "rt-archive-related__title", children: archiveGroupTitle(group) }),
|
|
1379
|
+
/* @__PURE__ */ jsx14("ul", { className: "rt-archive-related__list", children: group.items.map((item) => /* @__PURE__ */ jsx14("li", { className: "rt-archive-related__item", children: /* @__PURE__ */ jsxs9(
|
|
1380
|
+
"a",
|
|
1381
|
+
{
|
|
1382
|
+
className: "rt-archive-related__link",
|
|
1383
|
+
href: archivePostHref(
|
|
1384
|
+
item.collectionKey,
|
|
1385
|
+
item.slug,
|
|
1386
|
+
collections
|
|
1387
|
+
),
|
|
1388
|
+
children: [
|
|
1389
|
+
/* @__PURE__ */ jsx14("span", { className: "rt-archive-related__item-title", children: item.title }),
|
|
1390
|
+
item.excerpt ? /* @__PURE__ */ jsx14("span", { className: "rt-archive-related__item-excerpt", children: item.excerpt }) : null
|
|
1391
|
+
]
|
|
1392
|
+
}
|
|
1393
|
+
) }, item.id)) })
|
|
1394
|
+
] }, group.collectionKey)) });
|
|
1395
|
+
}
|
|
1396
|
+
function fieldFactValue(raw, meta) {
|
|
1397
|
+
if (raw === null || raw === void 0) return null;
|
|
1398
|
+
if (typeof raw === "number") return raw.toLocaleString("ko-KR");
|
|
1399
|
+
if (typeof raw !== "string" || raw.trim() === "") return null;
|
|
1400
|
+
if (!meta.choices) return raw;
|
|
1401
|
+
const choice = meta.choices.find((item) => item.value === raw);
|
|
1402
|
+
return choice ? choice.label : raw;
|
|
1403
|
+
}
|
|
1404
|
+
function renderFieldFacts(post) {
|
|
1405
|
+
if (!post.fields) return null;
|
|
1406
|
+
const rows = post.fieldsMeta.filter((meta) => FIELD_FACT_TYPES.has(meta.type)).flatMap((meta) => {
|
|
1407
|
+
const value = fieldFactValue(post.fields?.[meta.name], meta);
|
|
1408
|
+
return value === null ? [] : [{ meta, value }];
|
|
1409
|
+
});
|
|
1410
|
+
if (rows.length === 0) return null;
|
|
1411
|
+
return /* @__PURE__ */ jsx14("aside", { className: "rt-archive-facts", "aria-label": "\uC0C1\uC138 \uC815\uBCF4", children: /* @__PURE__ */ jsx14("dl", { className: "rt-archive-facts__list", children: rows.map(({ meta, value }) => /* @__PURE__ */ jsxs9("div", { className: "rt-archive-facts__row", children: [
|
|
1412
|
+
/* @__PURE__ */ jsx14("dt", { className: "rt-archive-facts__label", children: meta.label }),
|
|
1413
|
+
/* @__PURE__ */ jsx14(
|
|
1414
|
+
"dd",
|
|
1415
|
+
{
|
|
1416
|
+
className: meta.type === "textarea" ? "rt-archive-facts__value rt-archive-facts__value--multiline" : "rt-archive-facts__value",
|
|
1417
|
+
children: value
|
|
1418
|
+
}
|
|
1419
|
+
)
|
|
1420
|
+
] }, meta.name)) }) });
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1334
1423
|
// src/server/blog-post-body.tsx
|
|
1335
|
-
import {
|
|
1424
|
+
import {
|
|
1425
|
+
internalContentLinkResolverFrom as internalContentLinkResolverFrom2,
|
|
1426
|
+
renderInternalContentLinksInHtml as renderInternalContentLinksInHtml2
|
|
1427
|
+
} from "@roottale/cms-core";
|
|
1428
|
+
|
|
1429
|
+
// src/server/post-body-source.ts
|
|
1430
|
+
import { sanitizeHtml as sanitizeHtml2 } from "@roottale/cms-core";
|
|
1431
|
+
function hasVisibleContent(html) {
|
|
1432
|
+
if (/<(?:img|hr|br|iframe|video|audio)\b/i.test(html)) return true;
|
|
1433
|
+
return html.replace(/<[^>]*>/g, "").replace(/ /gi, " ").trim().length > 0;
|
|
1434
|
+
}
|
|
1435
|
+
function resolvePostBodySource(bodyHtml) {
|
|
1436
|
+
if (typeof bodyHtml !== "string") return { kind: "json" };
|
|
1437
|
+
const trimmed = bodyHtml.trim();
|
|
1438
|
+
if (trimmed.length === 0) return { kind: "json" };
|
|
1439
|
+
const sanitized = sanitizeHtml2(trimmed);
|
|
1440
|
+
if (!hasVisibleContent(sanitized)) return { kind: "json" };
|
|
1441
|
+
return { kind: "html", html: sanitized };
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// src/server/blog-post-body.tsx
|
|
1445
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1336
1446
|
function BlogPostBody(props) {
|
|
1337
1447
|
const {
|
|
1338
1448
|
doc,
|
|
@@ -1342,28 +1452,34 @@ function BlogPostBody(props) {
|
|
|
1342
1452
|
toc,
|
|
1343
1453
|
tocTitle,
|
|
1344
1454
|
tocPosition,
|
|
1345
|
-
bodyHtml
|
|
1455
|
+
bodyHtml,
|
|
1456
|
+
internalLinks = null
|
|
1346
1457
|
} = props;
|
|
1347
|
-
const tableOfContents = toc.length > 0 ? /* @__PURE__ */
|
|
1458
|
+
const tableOfContents = toc.length > 0 ? /* @__PURE__ */ jsx15(RootTaleTableOfContents, { entries: toc, title: tocTitle }) : null;
|
|
1348
1459
|
const source = resolvePostBodySource(bodyHtml);
|
|
1349
|
-
const
|
|
1460
|
+
const sourceHtml = source.kind === "html" && internalLinks ? renderInternalContentLinksInHtml2(
|
|
1461
|
+
source.html,
|
|
1462
|
+
internalContentLinkResolverFrom2(internalLinks)
|
|
1463
|
+
).html : source.kind === "html" ? source.html : "";
|
|
1464
|
+
const body = /* @__PURE__ */ jsx15("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: source.kind === "html" ? (
|
|
1350
1465
|
// source.html 은 resolvePostBodySource 가 공용 sanitizeHtml 로 정제한 값이다
|
|
1351
1466
|
// (이 컴포넌트에서 한 번 더 정제하지 않는 이유 — sink 가 한 곳이어야 눈으로
|
|
1352
1467
|
// 추적 가능하고, 이중 정제는 안전을 더 만들지 않으면서 비용만 든다).
|
|
1353
|
-
/* @__PURE__ */
|
|
1354
|
-
) : /* @__PURE__ */
|
|
1468
|
+
/* @__PURE__ */ jsx15("div", { dangerouslySetInnerHTML: { __html: sourceHtml } })
|
|
1469
|
+
) : /* @__PURE__ */ jsx15(
|
|
1355
1470
|
RenderTiptap,
|
|
1356
1471
|
{
|
|
1357
1472
|
doc,
|
|
1358
1473
|
fields,
|
|
1359
1474
|
apiKey,
|
|
1360
|
-
baseUrl
|
|
1475
|
+
baseUrl,
|
|
1476
|
+
internalLinks
|
|
1361
1477
|
}
|
|
1362
1478
|
) });
|
|
1363
1479
|
if (tocPosition === "sidebar" && tableOfContents) {
|
|
1364
1480
|
return /* @__PURE__ */ jsxs10("div", { className: "rt-cms-layout rt-cms-layout--toc-side", children: [
|
|
1365
1481
|
body,
|
|
1366
|
-
/* @__PURE__ */
|
|
1482
|
+
/* @__PURE__ */ jsx15("aside", { className: "rt-cms-toc-side", children: tableOfContents })
|
|
1367
1483
|
] });
|
|
1368
1484
|
}
|
|
1369
1485
|
return /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
@@ -1380,7 +1496,7 @@ import {
|
|
|
1380
1496
|
import {
|
|
1381
1497
|
resolvePostCollection as resolvePostCollection2
|
|
1382
1498
|
} from "@roottale/cms-core";
|
|
1383
|
-
import { Fragment as Fragment7, jsx as
|
|
1499
|
+
import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1384
1500
|
function absoluteUrl(siteUrl, path) {
|
|
1385
1501
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1386
1502
|
return `${trimSlash(siteUrl)}${normalizedPath}`;
|
|
@@ -1416,10 +1532,10 @@ function renderBlogPostBreadcrumb(input) {
|
|
|
1416
1532
|
}))
|
|
1417
1533
|
) : null;
|
|
1418
1534
|
return /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
1419
|
-
/* @__PURE__ */
|
|
1420
|
-
(crumb, index) => index === crumbs.length - 1 ? /* @__PURE__ */
|
|
1535
|
+
/* @__PURE__ */ jsx16("nav", { "aria-label": "\uBE0C\uB808\uB4DC\uD06C\uB7FC", className: "rt-cms-breadcrumb", children: /* @__PURE__ */ jsx16("ol", { children: crumbs.map(
|
|
1536
|
+
(crumb, index) => index === crumbs.length - 1 ? /* @__PURE__ */ jsx16("li", { "aria-current": "page", children: crumb.label }, index) : /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsx16("a", { href: crumb.href, children: crumb.label }) }, index)
|
|
1421
1537
|
) }) }),
|
|
1422
|
-
jsonLd ? /* @__PURE__ */
|
|
1538
|
+
jsonLd ? /* @__PURE__ */ jsx16(
|
|
1423
1539
|
"script",
|
|
1424
1540
|
{
|
|
1425
1541
|
type: "application/ld+json",
|
|
@@ -1429,12 +1545,51 @@ function renderBlogPostBreadcrumb(input) {
|
|
|
1429
1545
|
] });
|
|
1430
1546
|
}
|
|
1431
1547
|
|
|
1548
|
+
// src/server/internal-links.ts
|
|
1549
|
+
import { internalContentPathIndex } from "@roottale/cms-core";
|
|
1550
|
+
import { fetchPosts as fetchPosts2 } from "@roottale/cms-client/server";
|
|
1551
|
+
async function fetchInternalContentPathIndex(options) {
|
|
1552
|
+
const entries = [];
|
|
1553
|
+
const maxPages = options.maxPages ?? 20;
|
|
1554
|
+
let cursor;
|
|
1555
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
1556
|
+
try {
|
|
1557
|
+
const result = await fetchPosts2({
|
|
1558
|
+
apiKey: options.apiKey,
|
|
1559
|
+
baseUrl: options.baseUrl,
|
|
1560
|
+
type: "post",
|
|
1561
|
+
limit: 100,
|
|
1562
|
+
cursor,
|
|
1563
|
+
...options.locale ? { locale: options.locale } : {},
|
|
1564
|
+
...options.revalidate !== void 0 ? { revalidate: options.revalidate } : {}
|
|
1565
|
+
});
|
|
1566
|
+
for (const post of result.items) {
|
|
1567
|
+
entries.push({ path: post.path, previousSlugs: post.previousSlugs });
|
|
1568
|
+
}
|
|
1569
|
+
if (!result.hasMore || !result.nextCursor) break;
|
|
1570
|
+
cursor = result.nextCursor;
|
|
1571
|
+
} catch {
|
|
1572
|
+
break;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
return internalContentPathIndex(entries);
|
|
1576
|
+
}
|
|
1577
|
+
function bodyHasInternalContentLinkTokens(doc, html) {
|
|
1578
|
+
if (html && html.includes("[[internal:")) return true;
|
|
1579
|
+
if (!doc) return false;
|
|
1580
|
+
try {
|
|
1581
|
+
return JSON.stringify(doc).includes("[[internal:");
|
|
1582
|
+
} catch {
|
|
1583
|
+
return false;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1432
1587
|
// src/server/blog-post-footer.tsx
|
|
1433
1588
|
import {
|
|
1434
1589
|
jsonLdJson as jsonLdJson2
|
|
1435
1590
|
} from "@roottale/cms-client/server";
|
|
1436
1591
|
import { extractFaqEntries, faqPageJsonLd } from "@roottale/cms-core";
|
|
1437
|
-
import { jsx as
|
|
1592
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1438
1593
|
function renderPostCta(cta) {
|
|
1439
1594
|
if (!cta) return null;
|
|
1440
1595
|
const href = cta.buttonHref.trim();
|
|
@@ -1442,9 +1597,9 @@ function renderPostCta(cta) {
|
|
|
1442
1597
|
if (!isSafeHref2) return null;
|
|
1443
1598
|
const isExternal = /^https?:/i.test(href);
|
|
1444
1599
|
return /* @__PURE__ */ jsxs12("aside", { "data-roottale-cms": "post-cta", className: "rt-cms-post-cta", children: [
|
|
1445
|
-
cta.title ? /* @__PURE__ */
|
|
1446
|
-
cta.description ? /* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1600
|
+
cta.title ? /* @__PURE__ */ jsx17("p", { className: "rt-cms-post-cta__title", children: cta.title }) : null,
|
|
1601
|
+
cta.description ? /* @__PURE__ */ jsx17("p", { className: "rt-cms-post-cta__desc", children: cta.description }) : null,
|
|
1602
|
+
/* @__PURE__ */ jsx17(
|
|
1448
1603
|
"a",
|
|
1449
1604
|
{
|
|
1450
1605
|
className: "rt-cms-post-cta__btn",
|
|
@@ -1459,9 +1614,9 @@ function renderPostCta(cta) {
|
|
|
1459
1614
|
function renderRelatedPosts(posts, href, title) {
|
|
1460
1615
|
if (posts.length === 0) return null;
|
|
1461
1616
|
return /* @__PURE__ */ jsxs12("nav", { "data-roottale-cms": "related", className: "rt-cms-related", "aria-label": title, children: [
|
|
1462
|
-
/* @__PURE__ */
|
|
1463
|
-
/* @__PURE__ */
|
|
1464
|
-
post.featuredImageUrl ? /* @__PURE__ */
|
|
1617
|
+
/* @__PURE__ */ jsx17("h2", { className: "rt-cms-related-title", children: title }),
|
|
1618
|
+
/* @__PURE__ */ jsx17("ul", { className: "rt-cms-related-list", children: posts.map((post) => /* @__PURE__ */ jsx17("li", { className: "rt-cms-related-item", children: /* @__PURE__ */ jsxs12("a", { className: "rt-cms-related-link", href: href(post), children: [
|
|
1619
|
+
post.featuredImageUrl ? /* @__PURE__ */ jsx17(
|
|
1465
1620
|
"img",
|
|
1466
1621
|
{
|
|
1467
1622
|
className: "rt-cms-related-thumb",
|
|
@@ -1470,14 +1625,14 @@ function renderRelatedPosts(posts, href, title) {
|
|
|
1470
1625
|
loading: "lazy"
|
|
1471
1626
|
}
|
|
1472
1627
|
) : null,
|
|
1473
|
-
/* @__PURE__ */
|
|
1628
|
+
/* @__PURE__ */ jsx17("span", { className: "rt-cms-related-post-title", children: post.title })
|
|
1474
1629
|
] }) }, post.id)) })
|
|
1475
1630
|
] });
|
|
1476
1631
|
}
|
|
1477
1632
|
function renderFaqJsonLd(doc) {
|
|
1478
1633
|
const jsonLd = faqPageJsonLd(extractFaqEntries(doc));
|
|
1479
1634
|
if (!jsonLd) return null;
|
|
1480
|
-
return /* @__PURE__ */
|
|
1635
|
+
return /* @__PURE__ */ jsx17(
|
|
1481
1636
|
"script",
|
|
1482
1637
|
{
|
|
1483
1638
|
type: "application/ld+json",
|
|
@@ -1492,10 +1647,10 @@ function RootTaleFaqJsonLd({
|
|
|
1492
1647
|
}
|
|
1493
1648
|
|
|
1494
1649
|
// src/server/blog-post.tsx
|
|
1495
|
-
import { jsx as
|
|
1650
|
+
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1496
1651
|
async function fetchRelatedPostsFailSoft(input) {
|
|
1497
1652
|
if (input.count <= 0) return [];
|
|
1498
|
-
const candidates = await
|
|
1653
|
+
const candidates = await fetchPosts3({
|
|
1499
1654
|
apiKey: input.apiKey,
|
|
1500
1655
|
baseUrl: input.baseUrl,
|
|
1501
1656
|
type: "post",
|
|
@@ -1567,6 +1722,16 @@ async function lookupPost(input) {
|
|
|
1567
1722
|
});
|
|
1568
1723
|
return post ? { kind: "post", post } : { kind: "missing" };
|
|
1569
1724
|
}
|
|
1725
|
+
async function resolveInternalLinksSource(source, input) {
|
|
1726
|
+
if (source === false) return null;
|
|
1727
|
+
if (source !== "auto" && source !== void 0) return source;
|
|
1728
|
+
if (!input.hasTokens) return null;
|
|
1729
|
+
return fetchInternalContentPathIndex({
|
|
1730
|
+
apiKey: input.apiKey,
|
|
1731
|
+
baseUrl: input.baseUrl,
|
|
1732
|
+
locale: input.locale
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1570
1735
|
async function RootTaleBlogPost(props) {
|
|
1571
1736
|
const {
|
|
1572
1737
|
apiKey,
|
|
@@ -1585,7 +1750,8 @@ async function RootTaleBlogPost(props) {
|
|
|
1585
1750
|
showFieldFacts = false,
|
|
1586
1751
|
theme: themeProp,
|
|
1587
1752
|
authorHref = defaultAuthorHref,
|
|
1588
|
-
breadcrumb
|
|
1753
|
+
breadcrumb,
|
|
1754
|
+
internalLinks = "auto"
|
|
1589
1755
|
} = props;
|
|
1590
1756
|
const [lookup, themeStyle, blogSettings] = await Promise.all([
|
|
1591
1757
|
lookupPost({ apiKey, baseUrl, slugOrId, previewToken, locale }),
|
|
@@ -1593,10 +1759,10 @@ async function RootTaleBlogPost(props) {
|
|
|
1593
1759
|
fetchBlogSettingsFailSoft({ apiKey, baseUrl })
|
|
1594
1760
|
]);
|
|
1595
1761
|
if (lookup.kind === "preview-expired") {
|
|
1596
|
-
return previewExpiredElement ?? /* @__PURE__ */
|
|
1762
|
+
return previewExpiredElement ?? /* @__PURE__ */ jsx18("div", { "data-roottale-cms": "post-preview-expired", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx18("p", { className: "rt-cms-empty", children: t(locale, "previewExpired") }) });
|
|
1597
1763
|
}
|
|
1598
1764
|
if (lookup.kind === "missing") {
|
|
1599
|
-
return notFoundElement ?? /* @__PURE__ */
|
|
1765
|
+
return notFoundElement ?? /* @__PURE__ */ jsx18("div", { "data-roottale-cms": "post-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx18("p", { className: "rt-cms-empty", children: t(locale, "postNotFound") }) });
|
|
1600
1766
|
}
|
|
1601
1767
|
const post = lookup.post;
|
|
1602
1768
|
const display = resolvePostDisplay2(post, blogSettings, {
|
|
@@ -1605,13 +1771,22 @@ async function RootTaleBlogPost(props) {
|
|
|
1605
1771
|
});
|
|
1606
1772
|
const toc = display.showTableOfContents ? extractToc(post.bodyJson) : [];
|
|
1607
1773
|
const renderDoc = toc.length > 0 ? attachHeadingIds(post.bodyJson, toc) : post.bodyJson;
|
|
1608
|
-
const related = await
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1774
|
+
const [related, internalLinkIndex, footerPattern] = await Promise.all([
|
|
1775
|
+
fetchRelatedPostsFailSoft({
|
|
1776
|
+
post,
|
|
1777
|
+
apiKey,
|
|
1778
|
+
baseUrl,
|
|
1779
|
+
count: relatedPostsCount,
|
|
1780
|
+
locale
|
|
1781
|
+
}),
|
|
1782
|
+
resolveInternalLinksSource(internalLinks, {
|
|
1783
|
+
apiKey,
|
|
1784
|
+
baseUrl,
|
|
1785
|
+
locale,
|
|
1786
|
+
hasTokens: bodyHasInternalContentLinkTokens(post.bodyJson, post.bodyHtml)
|
|
1787
|
+
}),
|
|
1788
|
+
resolvePostPatternFailSoft(post, { apiKey, baseUrl }, POST_FOOTER_PATTERN_SLOT2)
|
|
1789
|
+
]);
|
|
1615
1790
|
const relatedHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
|
|
1616
1791
|
const authorName = post.authorName;
|
|
1617
1792
|
const authorSlug = post.authorSlug;
|
|
@@ -1645,7 +1820,7 @@ async function RootTaleBlogPost(props) {
|
|
|
1645
1820
|
options: breadcrumb
|
|
1646
1821
|
}),
|
|
1647
1822
|
/* @__PURE__ */ jsxs13("header", { className: "rt-cms-post-header", children: [
|
|
1648
|
-
categories.length > 0 ? /* @__PURE__ */
|
|
1823
|
+
categories.length > 0 ? /* @__PURE__ */ jsx18("nav", { className: "rt-cms-post-categories", "aria-label": "\uAE00 \uCE74\uD14C\uACE0\uB9AC", children: categories.map((category) => /* @__PURE__ */ jsx18(
|
|
1649
1824
|
"a",
|
|
1650
1825
|
{
|
|
1651
1826
|
className: "rt-cms-post-category",
|
|
@@ -1654,8 +1829,8 @@ async function RootTaleBlogPost(props) {
|
|
|
1654
1829
|
},
|
|
1655
1830
|
category.id
|
|
1656
1831
|
)) }) : null,
|
|
1657
|
-
showTitle ? /* @__PURE__ */
|
|
1658
|
-
post.excerpt ? /* @__PURE__ */
|
|
1832
|
+
showTitle ? /* @__PURE__ */ jsx18("h1", { className: "rt-cms-title", children: post.title }) : null,
|
|
1833
|
+
post.excerpt ? /* @__PURE__ */ jsx18("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
|
|
1659
1834
|
publishedDate || modifiedDate || showTopAuthor || views !== null || reviewedDate ? /* @__PURE__ */ jsxs13("p", { className: "rt-cms-meta", children: [
|
|
1660
1835
|
publishedDate ? /* @__PURE__ */ jsxs13(
|
|
1661
1836
|
"time",
|
|
@@ -1684,7 +1859,7 @@ async function RootTaleBlogPost(props) {
|
|
|
1684
1859
|
showTopAuthor ? /* @__PURE__ */ jsxs13("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
|
|
1685
1860
|
"\uC791\uC131\uC790",
|
|
1686
1861
|
" ",
|
|
1687
|
-
authorSlug ? /* @__PURE__ */
|
|
1862
|
+
authorSlug ? /* @__PURE__ */ jsx18("a", { className: "rt-cms-author-link", href: authorHref(authorSlug), children: authorName }) : authorName
|
|
1688
1863
|
] }) : null,
|
|
1689
1864
|
editorialReview && reviewedDate ? /* @__PURE__ */ jsxs13("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "reviewed", children: [
|
|
1690
1865
|
"\uB0B4\uC6A9 \uAC80\uD1A0 ",
|
|
@@ -1700,7 +1875,7 @@ async function RootTaleBlogPost(props) {
|
|
|
1700
1875
|
] }),
|
|
1701
1876
|
renderArchiveRelated(post.archiveRelated, collections),
|
|
1702
1877
|
showFieldFacts ? renderFieldFacts(post) : null,
|
|
1703
|
-
/* @__PURE__ */
|
|
1878
|
+
/* @__PURE__ */ jsx18(
|
|
1704
1879
|
BlogPostBody,
|
|
1705
1880
|
{
|
|
1706
1881
|
doc: renderDoc,
|
|
@@ -1710,11 +1885,13 @@ async function RootTaleBlogPost(props) {
|
|
|
1710
1885
|
toc,
|
|
1711
1886
|
tocTitle: display.tocTitle,
|
|
1712
1887
|
tocPosition: display.tocPosition,
|
|
1713
|
-
bodyHtml: post.bodyHtml
|
|
1888
|
+
bodyHtml: post.bodyHtml,
|
|
1889
|
+
internalLinks: internalLinkIndex
|
|
1714
1890
|
}
|
|
1715
1891
|
),
|
|
1892
|
+
renderPostPattern(footerPattern, POST_FOOTER_PATTERN_SLOT2, { apiKey, baseUrl }),
|
|
1716
1893
|
showAuthorCard && authorName ? /* @__PURE__ */ jsxs13("section", { className: "rt-cms-author-card", "aria-label": "\uC791\uC131\uC790", children: [
|
|
1717
|
-
authorImageUrl ? /* @__PURE__ */
|
|
1894
|
+
authorImageUrl ? /* @__PURE__ */ jsx18(
|
|
1718
1895
|
"img",
|
|
1719
1896
|
{
|
|
1720
1897
|
className: "rt-cms-author-card__image",
|
|
@@ -1723,11 +1900,11 @@ async function RootTaleBlogPost(props) {
|
|
|
1723
1900
|
loading: "lazy",
|
|
1724
1901
|
style: authorImageStyle
|
|
1725
1902
|
}
|
|
1726
|
-
) : /* @__PURE__ */
|
|
1903
|
+
) : /* @__PURE__ */ jsx18("div", { className: "rt-cms-author-card__avatar", "aria-hidden": "true", children: authorInitials(authorName) }),
|
|
1727
1904
|
/* @__PURE__ */ jsxs13("div", { className: "rt-cms-author-card__body", children: [
|
|
1728
|
-
/* @__PURE__ */
|
|
1729
|
-
/* @__PURE__ */
|
|
1730
|
-
authorBio ? /* @__PURE__ */
|
|
1905
|
+
/* @__PURE__ */ jsx18("p", { className: "rt-cms-author-card__eyebrow", children: display.authorCardEyebrow }),
|
|
1906
|
+
/* @__PURE__ */ jsx18("p", { className: "rt-cms-author-card__name", children: authorSlug ? /* @__PURE__ */ jsx18("a", { className: "rt-cms-author-link", href: authorHref(authorSlug), children: authorName }) : authorName }),
|
|
1907
|
+
authorBio ? /* @__PURE__ */ jsx18("p", { className: "rt-cms-author-card__description", children: authorBio }) : null
|
|
1731
1908
|
] })
|
|
1732
1909
|
] }) : null,
|
|
1733
1910
|
renderRelatedPosts(related, relatedHref, relatedPostsTitle),
|
|
@@ -1739,7 +1916,7 @@ async function RootTaleBlogPost(props) {
|
|
|
1739
1916
|
}
|
|
1740
1917
|
|
|
1741
1918
|
// src/server/preview-notice.tsx
|
|
1742
|
-
import { jsx as
|
|
1919
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1743
1920
|
function formatExpiry(locale, iso) {
|
|
1744
1921
|
const date = new Date(iso);
|
|
1745
1922
|
if (Number.isNaN(date.getTime())) return null;
|
|
@@ -1756,14 +1933,14 @@ function RootTalePreviewNotice({
|
|
|
1756
1933
|
}) {
|
|
1757
1934
|
const expiry = expiresAt ? formatExpiry(locale, expiresAt) : null;
|
|
1758
1935
|
return /* @__PURE__ */ jsxs14("div", { "data-roottale-cms": "preview-notice", className: "rt-cms-preview-notice", role: "status", children: [
|
|
1759
|
-
/* @__PURE__ */
|
|
1760
|
-
expiry ? /* @__PURE__ */
|
|
1936
|
+
/* @__PURE__ */ jsx19("span", { children: message ?? t(locale, "previewNotice") }),
|
|
1937
|
+
expiry ? /* @__PURE__ */ jsx19("span", { className: "rt-cms-preview-notice__expiry", children: expiry }) : null
|
|
1761
1938
|
] });
|
|
1762
1939
|
}
|
|
1763
1940
|
|
|
1764
1941
|
// src/server/page.tsx
|
|
1765
1942
|
import { fetchPost as fetchPost2 } from "@roottale/cms-client/server";
|
|
1766
|
-
import { jsx as
|
|
1943
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1767
1944
|
async function RootTalePage(props) {
|
|
1768
1945
|
const {
|
|
1769
1946
|
apiKey,
|
|
@@ -1780,7 +1957,7 @@ async function RootTalePage(props) {
|
|
|
1780
1957
|
resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl })
|
|
1781
1958
|
]);
|
|
1782
1959
|
if (!post) {
|
|
1783
|
-
return notFoundElement ?? /* @__PURE__ */
|
|
1960
|
+
return notFoundElement ?? /* @__PURE__ */ jsx20("div", { "data-roottale-cms": "page-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx20("p", { className: "rt-cms-empty", children: t(locale, "pageNotFound") }) });
|
|
1784
1961
|
}
|
|
1785
1962
|
const pageBodySource = resolvePostBodySource(post.bodyHtml);
|
|
1786
1963
|
const bodyJson = pageBodySource.kind === "json" && prepareBody ? await prepareBody(post.bodyJson) : post.bodyJson;
|
|
@@ -1791,8 +1968,8 @@ async function RootTalePage(props) {
|
|
|
1791
1968
|
className: "rt-cms-article",
|
|
1792
1969
|
style: themeStyle ?? void 0,
|
|
1793
1970
|
children: [
|
|
1794
|
-
showTitle ? /* @__PURE__ */
|
|
1795
|
-
/* @__PURE__ */
|
|
1971
|
+
showTitle ? /* @__PURE__ */ jsx20("header", { className: "rt-cms-post-header", children: /* @__PURE__ */ jsx20("h1", { className: "rt-cms-title", children: post.title }) }) : null,
|
|
1972
|
+
/* @__PURE__ */ jsx20("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: pageBodySource.kind === "html" ? /* @__PURE__ */ jsx20("div", { dangerouslySetInnerHTML: { __html: pageBodySource.html } }) : /* @__PURE__ */ jsx20(
|
|
1796
1973
|
RenderTiptap,
|
|
1797
1974
|
{
|
|
1798
1975
|
doc: bodyJson,
|
|
@@ -1808,7 +1985,7 @@ async function RootTalePage(props) {
|
|
|
1808
1985
|
|
|
1809
1986
|
// src/server/exposure-slot.tsx
|
|
1810
1987
|
import { fetchExposure } from "@roottale/cms-client/server";
|
|
1811
|
-
import { jsx as
|
|
1988
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1812
1989
|
async function RootTaleExposureSlot(props) {
|
|
1813
1990
|
const campaign = await fetchExposure({
|
|
1814
1991
|
apiKey: props.apiKey,
|
|
@@ -1819,7 +1996,7 @@ async function RootTaleExposureSlot(props) {
|
|
|
1819
1996
|
revalidate: props.revalidate
|
|
1820
1997
|
});
|
|
1821
1998
|
if (!campaign || !props.allowedVariants.includes(campaign.content.variant)) return null;
|
|
1822
|
-
return /* @__PURE__ */
|
|
1999
|
+
return /* @__PURE__ */ jsx21(RootTaleExposure, { campaign, allowedVariants: props.allowedVariants });
|
|
1823
2000
|
}
|
|
1824
2001
|
export {
|
|
1825
2002
|
RenderTiptap,
|
|
@@ -1832,16 +2009,20 @@ export {
|
|
|
1832
2009
|
RootTaleLeadForm,
|
|
1833
2010
|
RootTalePage,
|
|
1834
2011
|
RootTalePostCard,
|
|
2012
|
+
RootTalePostPattern,
|
|
1835
2013
|
RootTalePreviewNotice,
|
|
1836
2014
|
RootTaleTableOfContents,
|
|
1837
2015
|
RootTaleThemeProvider,
|
|
1838
2016
|
attachHeadingIds,
|
|
2017
|
+
bodyHasInternalContentLinkTokens,
|
|
1839
2018
|
collectCategories,
|
|
1840
2019
|
collectCategoriesWithCounts,
|
|
1841
2020
|
defaultCategoryHref,
|
|
1842
2021
|
extractToc,
|
|
2022
|
+
fetchInternalContentPathIndex,
|
|
1843
2023
|
filterPostsByCategory,
|
|
1844
2024
|
headingToId,
|
|
2025
|
+
makeCategoryHref,
|
|
1845
2026
|
renderBlock,
|
|
1846
2027
|
renderBlocks,
|
|
1847
2028
|
renderBoundBlocks,
|