@druid-sh/sdk
Version:
Druid.sh SDK for rendering blog content with SSR support
149 lines (148 loc) • 9.58 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlogPost = BlogPost;
const html_react_parser_1 = __importStar(require("html-react-parser"));
const image_1 = __importDefault(require("next/image"));
const link_1 = __importDefault(require("next/link"));
const react_1 = __importDefault(require("react"));
const CopyButton_1 = __importDefault(require("./CopyButton"));
const isInternalLink = (href) => {
return (href.startsWith("/") ||
href.startsWith("#") ||
(!href.startsWith("http://") && !href.startsWith("https://")));
};
async function BlogPost({ data }) {
const { post, basePath } = data;
if (!post) {
return (react_1.default.createElement("div", { className: "flex h-screen items-center justify-center" }, "Post not found"));
}
const formattedDate = new Date(post.publishedAt).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
return (react_1.default.createElement("div", null,
react_1.default.createElement("div", { className: "max-w-6xl mx-auto mb-8" },
react_1.default.createElement(link_1.default, { href: basePath, className: "inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors" },
react_1.default.createElement("span", null, "\u2190 Back to Blog"))),
react_1.default.createElement("article", { className: "max-w-3xl mx-auto" },
react_1.default.createElement("header", { className: "mb-8 border-b pb-8" },
react_1.default.createElement("h1", { className: "text-3xl font-extrabold tracking-tight sm:text-4xl md:text-5xl text-foreground" }, post.title),
react_1.default.createElement("div", { className: "mt-6 flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-muted-foreground" },
react_1.default.createElement("div", { className: "flex items-center gap-2" },
post.author.avatar && (react_1.default.createElement(image_1.default, { src: post.author.avatar, alt: post.author.name, width: 28, height: 28, className: "rounded-full" })),
react_1.default.createElement("span", { className: "font-medium text-foreground" }, post.author.name)),
react_1.default.createElement("span", null, "\u2022"),
react_1.default.createElement("time", { dateTime: post.publishedAt }, formattedDate)),
react_1.default.createElement("div", { className: "mt-6 flex flex-wrap gap-2" }, post.tags.map((tag) => (react_1.default.createElement(link_1.default, { key: tag.slug, href: `${basePath}/tag/${tag.slug}`, className: "inline-block rounded-full bg-secondary px-3 py-1 text-xs font-semibold text-secondary-foreground transition-colors hover:bg-secondary/80" },
"#",
tag.name))))),
post.coverImage && (react_1.default.createElement("div", { className: "my-8" },
react_1.default.createElement(image_1.default, { src: post.coverImage, alt: post.title, width: 1200, height: 600, sizes: "(max-width: 800px) 100vw, 800px", className: "w-full h-auto object-cover rounded-lg border", priority: true }))),
react_1.default.createElement("div", { className: "prose prose-lg dark:prose-invert max-w-none \n prose-headings:font-bold prose-headings:tracking-tight \n prose-a:text-primary prose-a:no-underline hover:prose-a:underline\n prose-blockquote:border-l-primary\n prose-img:rounded-lg prose-img:border" }, (0, html_react_parser_1.default)(post.content, {
replace: (domNode) => {
var _a, _b;
// Only process element nodes, not text nodes or other types
if (domNode.type !== "tag") {
return;
}
if (domNode.name === "img") {
const { src, alt, width, height } = domNode.attribs || {};
return (react_1.default.createElement(image_1.default, { key: src, src: src, alt: alt || "", width: width ? parseInt(width) : 800, height: height ? parseInt(height) : 600, sizes: "(max-width: 768px) 100vw, 700px", className: "w-full h-auto object-cover rounded-lg border" }));
}
else if (domNode.name === "a") {
const _c = domNode.attribs || {}, { href, target, rel } = _c, otherAttribs = __rest(_c, ["href", "target", "rel"]);
if (!href) {
return;
}
const children = domNode.children
? (0, html_react_parser_1.domToReact)(domNode.children)
: null;
if (isInternalLink(href)) {
return (react_1.default.createElement(link_1.default, Object.assign({ key: href, href: href }, otherAttribs), children));
}
else {
return (react_1.default.createElement("a", Object.assign({ key: href, href: href, target: target || "_blank", rel: rel || "noopener noreferrer" }, otherAttribs), children));
}
}
else if (domNode.name === "pre") {
// const hasCodeBlock = domNode.children?.some(
// (child: any) =>
// child.type === "tag" &&
// child.name === "code" &&
// child.attribs?.class?.includes("language-")
// );
// if (hasCodeBlock) {
const codeElement = (_a = domNode.children) === null || _a === void 0 ? void 0 : _a.find((child) => child.type === "tag" && child.name === "code");
const getTextContent = (node) => {
if (node.type === "text") {
return node.data || "";
}
if (node.children) {
return node.children.map(getTextContent).join("");
}
return "";
};
const codeText = codeElement ? getTextContent(codeElement) : "";
const existingClass = ((_b = domNode.attribs) === null || _b === void 0 ? void 0 : _b.class) || "";
const newClass = existingClass.includes("hljs")
? existingClass
: `${existingClass} hljs border`.trim();
return (react_1.default.createElement("div", { className: "relative group" },
react_1.default.createElement("pre", Object.assign({}, domNode.attribs, { className: newClass }), (0, html_react_parser_1.domToReact)(domNode.children)),
react_1.default.createElement("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity" },
react_1.default.createElement(CopyButton_1.default, { text: codeText }))));
// }
}
// For all other elements, let html-react-parser handle them normally
return;
},
})))));
}