embed-dlsurf-blogs 1.0.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/dist/index.js ADDED
@@ -0,0 +1,649 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ var __export = (target, all) => {
24
+ for (var name in all)
25
+ __defProp(target, name, { get: all[name], enumerable: true });
26
+ };
27
+ var __copyProps = (to, from, except, desc) => {
28
+ if (from && typeof from === "object" || typeof from === "function") {
29
+ for (let key of __getOwnPropNames(from))
30
+ if (!__hasOwnProp.call(to, key) && key !== except)
31
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32
+ }
33
+ return to;
34
+ };
35
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
+
37
+ // src/index.ts
38
+ var index_exports = {};
39
+ __export(index_exports, {
40
+ BlogRenderer: () => BlogRenderer,
41
+ default: () => BlogRenderer,
42
+ renderText: () => renderText
43
+ });
44
+ module.exports = __toCommonJS(index_exports);
45
+
46
+ // src/BlogRenderer.tsx
47
+ var import_react = require("react");
48
+
49
+ // #style-inject:#style-inject
50
+ function styleInject(css, { insertAt } = {}) {
51
+ if (!css || typeof document === "undefined") return;
52
+ const head = document.head || document.getElementsByTagName("head")[0];
53
+ const style = document.createElement("style");
54
+ style.type = "text/css";
55
+ if (insertAt === "top") {
56
+ if (head.firstChild) {
57
+ head.insertBefore(style, head.firstChild);
58
+ } else {
59
+ head.appendChild(style);
60
+ }
61
+ } else {
62
+ head.appendChild(style);
63
+ }
64
+ if (style.styleSheet) {
65
+ style.styleSheet.cssText = css;
66
+ } else {
67
+ style.appendChild(document.createTextNode(css));
68
+ }
69
+ }
70
+
71
+ // src/BlogRenderer.css
72
+ styleInject('.edlsb-wrapper {\n background-color: #f8fafc;\n font-family:\n var(--font-merriweather),\n "Merriweather",\n Georgia,\n serif;\n}\n.edlsb-progressBar {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 4px;\n background-color: #4f46e5;\n transform-origin: left center;\n z-index: 100;\n}\n.edlsb-main {\n position: relative;\n}\n.edlsb-headerSection {\n padding-top: 2rem;\n padding-bottom: 5rem;\n position: relative;\n overflow: hidden;\n}\n.edlsb-headerContainer {\n width: 100%;\n max-width: 56rem;\n margin: 0 auto;\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n position: relative;\n z-index: 10;\n}\n.edlsb-headerContent {\n text-align: center;\n}\n.edlsb-headerContent > * + * {\n margin-top: 2rem;\n}\n@media (min-width: 768px) {\n .edlsb-headerContent {\n text-align: left;\n }\n}\n.edlsb-metaRow {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 1rem;\n color: #94a3b8;\n font-weight: 700;\n font-size: 0.75rem;\n line-height: 1rem;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n justify-content: center;\n}\n@media (min-width: 768px) {\n .edlsb-metaRow {\n justify-content: flex-start;\n }\n}\n.edlsb-articleBadge {\n padding: 0.25rem 0.75rem;\n background-color: #ffffff;\n border-radius: 0.5rem;\n border: 1px solid #e2e8f0;\n color: #4f46e5;\n}\n.edlsb-dot {\n width: 0.25rem;\n height: 0.25rem;\n background-color: #cbd5e1;\n border-radius: 9999px;\n}\n.edlsb-metaItem {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.edlsb-icon {\n width: 1rem;\n height: 1rem;\n}\n.edlsb-postTitle {\n font-size: 2.25rem;\n line-height: 0.95;\n font-weight: 1000;\n color: #0f172a;\n letter-spacing: -0.04em;\n}\n@media (min-width: 768px) {\n .edlsb-postTitle {\n font-size: 3.75rem;\n }\n}\n@media (min-width: 1024px) {\n .edlsb-postTitle {\n font-size: 4.5rem;\n }\n}\n.edlsb-bodyContainer {\n width: 100%;\n max-width: 56rem;\n margin: 0 auto;\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n padding-top: 5rem;\n padding-bottom: 5rem;\n}\n.edlsb-thumbnailWrapper {\n margin-bottom: 2rem;\n border-radius: 1rem;\n overflow: hidden;\n box-shadow: 0 25px 50px -12px rgb(49 46 129 / 0.1);\n margin-top: -8rem;\n position: relative;\n z-index: 20;\n}\n.edlsb-thumbnail {\n width: 100%;\n height: auto;\n object-fit: cover;\n max-height: 600px;\n}\n.edlsb-tocWrapper {\n margin-bottom: 2.5rem;\n}\n.edlsb-tocToggle {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n padding: 1rem 1.25rem;\n border-radius: 1rem;\n background-color: rgba(241, 245, 249, 0.8);\n border: none;\n cursor: pointer;\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.edlsb-tocToggle:hover {\n background-color: #f1f5f9;\n}\n.edlsb-tocToggle:hover .edlsb-tocIconWrap {\n color: #334155;\n}\n.edlsb-tocToggleInner {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n.edlsb-tocIconWrap {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: 0.5rem;\n background-color: rgba(226, 232, 240, 0.8);\n color: #64748b;\n transition-property: color;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.edlsb-tocLabel {\n font-size: 13px;\n font-weight: 600;\n color: #475569;\n}\n.edlsb-tocCount {\n color: #94a3b8;\n font-weight: 400;\n margin-left: 0.25rem;\n}\n.edlsb-chevronIcon {\n width: 1rem;\n height: 1rem;\n color: #94a3b8;\n transition-property: transform;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n}\n.edlsb-chevronIconOpen {\n transform: rotate(180deg);\n}\n.edlsb-tocPanelInner {\n margin-top: 0.375rem;\n border-radius: 1rem;\n background-color: rgba(241, 245, 249, 0.8);\n padding: 0.5rem;\n}\n.edlsb-tocGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 0.125rem;\n}\n@media (min-width: 640px) {\n .edlsb-tocGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n.edlsb-tocItem {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n text-align: left;\n border-radius: 0.75rem;\n padding: 0.625rem 0.75rem;\n font-size: 13px;\n border: none;\n cursor: pointer;\n background-color: transparent;\n color: #475569;\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.edlsb-tocItem:hover {\n background-color: #ffffff;\n color: #0f172a;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n.edlsb-tocItemActive {\n background-color: #0f172a;\n color: #ffffff;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n.edlsb-tocItemActive:hover {\n background-color: #0f172a;\n color: #ffffff;\n}\n.edlsb-tocItemLevel3 {\n padding-left: 2rem;\n}\n.edlsb-tocBadge {\n flex-shrink: 0;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 0.375rem;\n font-size: 10px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(226, 232, 240, 0.8);\n color: #94a3b8;\n}\n.edlsb-tocBadgeActive {\n background-color: rgba(255, 255, 255, 0.15);\n color: rgba(255, 255, 255, 0.8);\n}\n.edlsb-tocItemText {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.edlsb-shareSection {\n margin-top: 3.5rem;\n border-top: 1px solid #e2e8f0;\n padding-top: 1.5rem;\n}\n.edlsb-shareInner {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n@media (min-width: 640px) {\n .edlsb-shareInner {\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n }\n}\n.edlsb-shareTitle {\n font-size: 1rem;\n line-height: 1.5rem;\n font-weight: 600;\n color: #0f172a;\n}\n.edlsb-shareSubtitle {\n font-size: 0.875rem;\n line-height: 1.25rem;\n color: #64748b;\n}\n.edlsb-shareButtons {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.edlsb-shareBtn {\n height: 2.5rem;\n padding-left: 1rem;\n padding-right: 1rem;\n border-radius: 9999px;\n border: 1px solid #e2e8f0;\n background-color: #ffffff;\n color: #334155;\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition-property:\n color,\n background-color,\n border-color;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.edlsb-shareBtn:hover {\n border-color: #cbd5e1;\n color: #0f172a;\n}\n.edlsb-shareBtnInner {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n}\n.edlsb-copyBtn {\n height: 2.5rem;\n width: 2.5rem;\n border-radius: 9999px;\n border: 1px solid #e2e8f0;\n background-color: #ffffff;\n color: #475569;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition-property:\n color,\n background-color,\n border-color;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.edlsb-copyBtn:hover {\n border-color: #cbd5e1;\n color: #0f172a;\n}\n.edlsb-bodyContainer .blog-content {\n color: #1e293b;\n line-height: 1.8;\n font-size: 1.05rem;\n overflow-wrap: anywhere;\n}\n.edlsb-bodyContainer .blog-content > * + * {\n margin-top: 1rem;\n}\n.edlsb-bodyContainer .blog-content pre {\n margin: 1.25rem 0;\n padding: 0.9rem 1rem;\n border-radius: 0.75rem;\n background: #0b1220;\n color: #e2e8f0;\n overflow-x: auto;\n border: 1px solid #1f2937;\n -webkit-overflow-scrolling: touch;\n}\n.edlsb-bodyContainer .blog-content pre code {\n background: transparent;\n padding: 0;\n border-radius: 0;\n color: inherit;\n font-size: 0.875rem;\n line-height: 1.6;\n}\n.edlsb-bodyContainer .blog-content code {\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n "Liberation Mono",\n "Courier New",\n monospace;\n background: #e2e8f0;\n color: #0f172a;\n padding: 0.15rem 0.4rem;\n border-radius: 0.35rem;\n font-size: 0.875em;\n}\n.edlsb-bodyContainer .blog-content img {\n display: block;\n max-width: 100%;\n width: auto;\n height: auto;\n margin: 1.25rem auto;\n border-radius: 0.75rem;\n}\n.edlsb-bodyContainer .blog-content a {\n color: #2563eb;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n');
73
+
74
+ // src/tiptap-renderer.ts
75
+ function escapeHtml(str) {
76
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
77
+ }
78
+ function applyMark(html, mark) {
79
+ var _a, _b, _c, _d, _e, _f, _g;
80
+ switch (mark.type) {
81
+ case "bold":
82
+ return `<strong>${html}</strong>`;
83
+ case "italic":
84
+ return `<em>${html}</em>`;
85
+ case "strike":
86
+ return `<s>${html}</s>`;
87
+ case "underline":
88
+ return `<u>${html}</u>`;
89
+ case "code":
90
+ return `<code>${html}</code>`;
91
+ case "link": {
92
+ const href = escapeHtml((_b = (_a = mark.attrs) == null ? void 0 : _a.href) != null ? _b : "");
93
+ const target = escapeHtml((_d = (_c = mark.attrs) == null ? void 0 : _c.target) != null ? _d : "_blank");
94
+ return `<a href="${href}" target="${target}" rel="noopener noreferrer">${html}</a>`;
95
+ }
96
+ case "textStyle": {
97
+ const color = (_e = mark.attrs) == null ? void 0 : _e.color;
98
+ const fontSize = (_f = mark.attrs) == null ? void 0 : _f.fontSize;
99
+ const style = [
100
+ color ? `color:${color}` : "",
101
+ fontSize ? `font-size:${fontSize}` : ""
102
+ ].filter(Boolean).join(";");
103
+ return style ? `<span style="${style}">${html}</span>` : html;
104
+ }
105
+ case "highlight": {
106
+ const color = (_g = mark.attrs) == null ? void 0 : _g.color;
107
+ const style = color ? ` style="background-color:${color}"` : "";
108
+ return `<mark${style}>${html}</mark>`;
109
+ }
110
+ default:
111
+ return html;
112
+ }
113
+ }
114
+ function renderChildren(node) {
115
+ if (!Array.isArray(node == null ? void 0 : node.content)) return "";
116
+ return node.content.map(renderNode).join("");
117
+ }
118
+ function renderNode(node) {
119
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
120
+ if (!node) return "";
121
+ switch (node.type) {
122
+ // ── Document root ────────────────────────────────────────────────────
123
+ case "doc":
124
+ return renderChildren(node);
125
+ // ── Block nodes ──────────────────────────────────────────────────────
126
+ case "paragraph": {
127
+ const inner = renderChildren(node);
128
+ if (!inner) return `<p><br /></p>`;
129
+ return `<p>${inner}</p>`;
130
+ }
131
+ case "heading": {
132
+ const level = (_b = (_a = node.attrs) == null ? void 0 : _a.level) != null ? _b : 1;
133
+ return `<h${level}>${renderChildren(node)}</h${level}>`;
134
+ }
135
+ case "blockquote":
136
+ return `<blockquote>${renderChildren(node)}</blockquote>`;
137
+ case "bulletList":
138
+ return `<ul>${renderChildren(node)}</ul>`;
139
+ case "orderedList":
140
+ return `<ol>${renderChildren(node)}</ol>`;
141
+ case "listItem":
142
+ return `<li>${renderChildren(node)}</li>`;
143
+ case "taskList":
144
+ return `<ul class="task-list">${renderChildren(node)}</ul>`;
145
+ case "taskItem": {
146
+ const checked = ((_c = node.attrs) == null ? void 0 : _c.checked) ? " checked" : "";
147
+ return `<li class="task-item"><input type="checkbox"${checked} disabled /><div>${renderChildren(node)}</div></li>`;
148
+ }
149
+ case "codeBlock": {
150
+ const lang = ((_d = node.attrs) == null ? void 0 : _d.language) ? ` data-language="${escapeHtml(node.attrs.language)}"` : "";
151
+ return `<pre${lang}><code>${renderChildren(node)}</code></pre>`;
152
+ }
153
+ case "horizontalRule":
154
+ return `<hr />`;
155
+ case "hardBreak":
156
+ return `<br />`;
157
+ // ── Media / embeds ───────────────────────────────────────────────────
158
+ case "image": {
159
+ const src = escapeHtml((_f = (_e = node.attrs) == null ? void 0 : _e.src) != null ? _f : "");
160
+ const alt = escapeHtml((_h = (_g = node.attrs) == null ? void 0 : _g.alt) != null ? _h : "");
161
+ const title = ((_i = node.attrs) == null ? void 0 : _i.title) ? ` title="${escapeHtml(node.attrs.title)}"` : "";
162
+ return `<img src="${src}" alt="${alt}"${title} loading="lazy" />`;
163
+ }
164
+ case "resizableImage": {
165
+ const src = escapeHtml((_k = (_j = node.attrs) == null ? void 0 : _j.src) != null ? _k : "");
166
+ const alt = escapeHtml((_m = (_l = node.attrs) == null ? void 0 : _l.alt) != null ? _m : "");
167
+ const width = ((_n = node.attrs) == null ? void 0 : _n.width) ? ` width="${escapeHtml(String(node.attrs.width))}"` : "";
168
+ return `<img src="${src}" alt="${alt}"${width} loading="lazy" />`;
169
+ }
170
+ case "youtube": {
171
+ const src = escapeHtml((_p = (_o = node.attrs) == null ? void 0 : _o.src) != null ? _p : "");
172
+ const width = (_r = (_q = node.attrs) == null ? void 0 : _q.width) != null ? _r : 640;
173
+ const height = (_t = (_s = node.attrs) == null ? void 0 : _s.height) != null ? _t : 480;
174
+ if (!src) return "";
175
+ return `<div class="rounded-lg my-4 overflow-hidden" style="position:relative;padding-bottom:56.25%;height:0;"><iframe src="${src}" width="${width}" height="${height}" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>`;
176
+ }
177
+ case "twitter":
178
+ case "tweet": {
179
+ const url = escapeHtml((_x = (_w = (_u = node.attrs) == null ? void 0 : _u.src) != null ? _w : (_v = node.attrs) == null ? void 0 : _v.url) != null ? _x : "");
180
+ if (!url) return "";
181
+ return `<div class="max-w-xl"><a href="${url}" target="_blank" rel="noopener noreferrer" class="text-themecolor font-semibold underline underline-offset-[3px] hover:text-themecolorhover transition-colors">${url}</a></div>`;
182
+ }
183
+ // ── Inline nodes ─────────────────────────────────────────────────────
184
+ case "text": {
185
+ let out = escapeHtml((_y = node.text) != null ? _y : "");
186
+ if (Array.isArray(node.marks)) {
187
+ for (const mark of node.marks) {
188
+ out = applyMark(out, mark);
189
+ }
190
+ }
191
+ return out;
192
+ }
193
+ default:
194
+ return renderChildren(node);
195
+ }
196
+ }
197
+ function renderTiptapToHTML(jsonContent) {
198
+ try {
199
+ if (!jsonContent) return "";
200
+ let contentObj;
201
+ if (typeof jsonContent === "string") {
202
+ try {
203
+ contentObj = JSON.parse(jsonContent);
204
+ } catch (e) {
205
+ return jsonContent;
206
+ }
207
+ } else {
208
+ contentObj = jsonContent;
209
+ }
210
+ if (!contentObj || typeof contentObj !== "object") {
211
+ return String(jsonContent);
212
+ }
213
+ return renderNode(contentObj);
214
+ } catch (error) {
215
+ console.error("Failed to parse Tiptap JSON to HTML:", error);
216
+ return "<p>Error loading content.</p>";
217
+ }
218
+ }
219
+
220
+ // src/BlogRenderer.tsx
221
+ var import_jsx_runtime = require("react/jsx-runtime");
222
+ var styles = {
223
+ wrapper: "edlsb-wrapper",
224
+ progressBar: "edlsb-progressBar",
225
+ main: "edlsb-main",
226
+ headerSection: "edlsb-headerSection",
227
+ headerContainer: "edlsb-headerContainer",
228
+ headerContent: "edlsb-headerContent",
229
+ metaRow: "edlsb-metaRow",
230
+ articleBadge: "edlsb-articleBadge",
231
+ dot: "edlsb-dot",
232
+ metaItem: "edlsb-metaItem",
233
+ icon: "edlsb-icon",
234
+ postTitle: "edlsb-postTitle",
235
+ bodyContainer: "edlsb-bodyContainer",
236
+ thumbnailWrapper: "edlsb-thumbnailWrapper",
237
+ thumbnail: "edlsb-thumbnail",
238
+ tocWrapper: "edlsb-tocWrapper",
239
+ tocToggle: "edlsb-tocToggle",
240
+ tocToggleInner: "edlsb-tocToggleInner",
241
+ tocIconWrap: "edlsb-tocIconWrap",
242
+ tocLabel: "edlsb-tocLabel",
243
+ tocCount: "edlsb-tocCount",
244
+ chevronIcon: "edlsb-chevronIcon",
245
+ chevronIconOpen: "edlsb-chevronIconOpen",
246
+ tocPanelInner: "edlsb-tocPanelInner",
247
+ tocGrid: "edlsb-tocGrid",
248
+ tocItem: "edlsb-tocItem",
249
+ tocItemActive: "edlsb-tocItemActive",
250
+ tocItemLevel3: "edlsb-tocItemLevel3",
251
+ tocBadge: "edlsb-tocBadge",
252
+ tocBadgeActive: "edlsb-tocBadgeActive",
253
+ tocItemText: "edlsb-tocItemText",
254
+ shareSection: "edlsb-shareSection",
255
+ shareInner: "edlsb-shareInner",
256
+ shareTitle: "edlsb-shareTitle",
257
+ shareSubtitle: "edlsb-shareSubtitle",
258
+ shareButtons: "edlsb-shareButtons",
259
+ shareBtn: "edlsb-shareBtn",
260
+ shareBtnInner: "edlsb-shareBtnInner",
261
+ copyBtn: "edlsb-copyBtn"
262
+ };
263
+ var baseIconProps = {
264
+ xmlns: "http://www.w3.org/2000/svg",
265
+ width: "1em",
266
+ height: "1em",
267
+ style: { flexShrink: 0 },
268
+ "aria-hidden": true
269
+ };
270
+ var Calendar = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
271
+ "svg",
272
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), {
273
+ viewBox: "0 0 24 24",
274
+ fill: "none",
275
+ stroke: "currentColor",
276
+ strokeLinecap: "round",
277
+ strokeLinejoin: "round"
278
+ }), props), {
279
+ children: [
280
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2", strokeWidth: "2" }),
281
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "16", y1: "2", x2: "16", y2: "6", strokeWidth: "2" }),
282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "6", strokeWidth: "2" }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10", strokeWidth: "2" })
284
+ ]
285
+ })
286
+ );
287
+ var Clock = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
288
+ "svg",
289
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), {
290
+ viewBox: "0 0 24 24",
291
+ fill: "none",
292
+ stroke: "currentColor",
293
+ strokeLinecap: "round",
294
+ strokeLinejoin: "round"
295
+ }), props), {
296
+ children: [
297
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "9", strokeWidth: "2" }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "7", x2: "12", y2: "12", strokeWidth: "2" }),
299
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "12", x2: "15", y2: "14", strokeWidth: "2" })
300
+ ]
301
+ })
302
+ );
303
+ var ChevronDown = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
304
+ "svg",
305
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), {
306
+ viewBox: "0 0 24 24",
307
+ fill: "none",
308
+ stroke: "currentColor",
309
+ strokeLinecap: "round",
310
+ strokeLinejoin: "round"
311
+ }), props), {
312
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "6 9 12 15 18 9", strokeWidth: "2" })
313
+ })
314
+ );
315
+ var Twitter = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), { viewBox: "0 0 24 24", fill: "currentColor" }), props), { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18.244 2h3.308l-7.227 8.26L22.8 22h-6.637l-5.197-6.787L4.99 22H1.68l7.73-8.835L1.2 2h6.806l4.697 6.21L18.244 2Zm-1.16 18h1.833L7.01 3.896H5.044L17.083 20Z" }) }));
316
+ var Linkedin = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), { viewBox: "0 0 24 24", fill: "currentColor" }), props), { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6.94 8.5a1.94 1.94 0 1 1 0-3.88 1.94 1.94 0 0 1 0 3.88ZM5.26 9.94h3.36V20H5.26V9.94Zm5.28 0h3.22v1.38h.05c.45-.85 1.55-1.74 3.2-1.74 3.42 0 4.05 2.1 4.05 4.84V20h-3.36v-4.95c0-1.18-.02-2.7-1.78-2.7-1.78 0-2.05 1.3-2.05 2.62V20h-3.33V9.94Z" }) }));
317
+ var Facebook = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), { viewBox: "0 0 24 24", fill: "currentColor" }), props), { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13.5 22v-8h2.7l.5-3h-3.2V9.2c0-.9.3-1.5 1.6-1.5h1.7V5c-.3 0-1.3-.1-2.4-.1-2.4 0-4 1.4-4 3.9V11H8v3h2.4v8h3.1Z" }) }));
318
+ var LinkIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
319
+ "svg",
320
+ __spreadProps(__spreadValues(__spreadProps(__spreadValues({}, baseIconProps), {
321
+ viewBox: "0 0 24 24",
322
+ fill: "none",
323
+ stroke: "currentColor",
324
+ strokeLinecap: "round",
325
+ strokeLinejoin: "round"
326
+ }), props), {
327
+ children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
329
+ "path",
330
+ {
331
+ d: "M10 14a5 5 0 0 1 0-7l1.5-1.5a5 5 0 0 1 7 7L17 14",
332
+ strokeWidth: "2"
333
+ }
334
+ ),
335
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
336
+ "path",
337
+ {
338
+ d: "M14 10a5 5 0 0 1 0 7l-1.5 1.5a5 5 0 1 1-7-7L7 10",
339
+ strokeWidth: "2"
340
+ }
341
+ )
342
+ ]
343
+ })
344
+ );
345
+ var stripProseWrappers = (html) => {
346
+ let result = html;
347
+ const proseDiv = /^\s*<div[^>]*\bprose\b[^>]*>([\s\S]*)<\/div>\s*$/;
348
+ let prev = "";
349
+ while (prev !== result) {
350
+ prev = result;
351
+ const match = result.match(proseDiv);
352
+ if (match) result = match[1].trim();
353
+ }
354
+ return result;
355
+ };
356
+ function BlogRenderer({ post }) {
357
+ const rawHtml = post.content_json ? renderTiptapToHTML(post.content_json) : "<p>Could not render content</p>";
358
+ const htmlContent = stripProseWrappers(rawHtml);
359
+ const articleRef = (0, import_react.useRef)(null);
360
+ const [renderedHtml, setRenderedHtml] = (0, import_react.useState)(htmlContent);
361
+ const [tocItems, setTocItems] = (0, import_react.useState)([]);
362
+ const [activeHeadingId, setActiveHeadingId] = (0, import_react.useState)("");
363
+ const [tocOpen, setTocOpen] = (0, import_react.useState)(false);
364
+ const [scrollProgress, setScrollProgress] = (0, import_react.useState)(0);
365
+ const [mounted, setMounted] = (0, import_react.useState)(false);
366
+ const getFullThumbnail = (path) => {
367
+ if (!path) return void 0;
368
+ if (path.startsWith("http")) return path;
369
+ return `https://cdn.dl.surf/${path}`;
370
+ };
371
+ const thumbUrl = getFullThumbnail(post.thumbnail_path);
372
+ const publishDate = post.created_at || (/* @__PURE__ */ new Date()).toISOString();
373
+ const formattedDate = new Date(publishDate).toLocaleDateString("en-US", {
374
+ year: "numeric",
375
+ month: "long",
376
+ day: "numeric"
377
+ });
378
+ const shareUrl = typeof window !== "undefined" ? window.location.href : "";
379
+ const shareTitle = post.title;
380
+ const shareOnTwitter = () => window.open(
381
+ `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(shareTitle)}`,
382
+ "_blank"
383
+ );
384
+ const shareOnFacebook = () => window.open(
385
+ `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`,
386
+ "_blank"
387
+ );
388
+ const shareOnLinkedIn = () => window.open(
389
+ `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`,
390
+ "_blank"
391
+ );
392
+ const copyLink = () => {
393
+ navigator.clipboard.writeText(shareUrl);
394
+ alert("Link copied to clipboard!");
395
+ };
396
+ (0, import_react.useEffect)(() => {
397
+ setMounted(true);
398
+ }, []);
399
+ (0, import_react.useEffect)(() => {
400
+ const handleScroll = () => {
401
+ const scrollTop = window.scrollY || document.documentElement.scrollTop;
402
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
403
+ setScrollProgress(docHeight > 0 ? scrollTop / docHeight : 0);
404
+ };
405
+ window.addEventListener("scroll", handleScroll, { passive: true });
406
+ return () => window.removeEventListener("scroll", handleScroll);
407
+ }, []);
408
+ (0, import_react.useEffect)(() => {
409
+ if (typeof window === "undefined") return;
410
+ const wrapper = document.createElement("div");
411
+ wrapper.innerHTML = htmlContent || "";
412
+ const headings = Array.from(wrapper.querySelectorAll("h2, h3"));
413
+ const nextTocItems = [];
414
+ const usedIds = /* @__PURE__ */ new Set();
415
+ headings.forEach((heading, index) => {
416
+ var _a;
417
+ const text = ((_a = heading.textContent) == null ? void 0 : _a.trim()) || `Section ${index + 1}`;
418
+ const level = heading.tagName.toLowerCase() === "h2" ? 2 : 3;
419
+ const base = text.toLowerCase().replace(/[^a-z0-9\s-]/g, "").trim().replace(/\s+/g, "-") || `section-${index + 1}`;
420
+ let id = base;
421
+ let suffix = 2;
422
+ while (usedIds.has(id)) {
423
+ id = `${base}-${suffix}`;
424
+ suffix += 1;
425
+ }
426
+ usedIds.add(id);
427
+ heading.setAttribute("id", id);
428
+ nextTocItems.push({ id, text, level });
429
+ });
430
+ setRenderedHtml(wrapper.innerHTML);
431
+ setTocItems(nextTocItems);
432
+ }, [htmlContent]);
433
+ (0, import_react.useEffect)(() => {
434
+ if (!tocItems.length) return;
435
+ const headingElements = tocItems.map((item) => document.getElementById(item.id)).filter((el) => Boolean(el));
436
+ if (!headingElements.length) return;
437
+ const observer = new IntersectionObserver(
438
+ (entries) => {
439
+ var _a, _b;
440
+ const visible = entries.filter((entry) => entry.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
441
+ if ((_b = (_a = visible[0]) == null ? void 0 : _a.target) == null ? void 0 : _b.id) {
442
+ setActiveHeadingId(visible[0].target.id);
443
+ }
444
+ },
445
+ { rootMargin: "-90px 0px -65% 0px", threshold: 0.1 }
446
+ );
447
+ headingElements.forEach((el) => observer.observe(el));
448
+ return () => observer.disconnect();
449
+ }, [tocItems, renderedHtml]);
450
+ const scrollToHeading = (id) => {
451
+ setTocOpen(false);
452
+ setTimeout(() => {
453
+ const el = document.getElementById(id);
454
+ if (!el) return;
455
+ const offset = 110;
456
+ const top = el.getBoundingClientRect().top + window.scrollY - offset;
457
+ window.scrollTo({ top, behavior: "smooth" });
458
+ }, 280);
459
+ };
460
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.wrapper, children: [
461
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
462
+ "div",
463
+ {
464
+ className: styles.progressBar,
465
+ style: { transform: `scaleX(${scrollProgress})` }
466
+ }
467
+ ),
468
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className: styles.main, ref: articleRef, children: [
469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.headerSection, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.headerContainer, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
470
+ "div",
471
+ {
472
+ className: styles.headerContent,
473
+ style: {
474
+ opacity: mounted ? 1 : 0,
475
+ transform: mounted ? "none" : "translateY(20px)",
476
+ transition: "opacity 0.4s ease, transform 0.4s ease"
477
+ },
478
+ children: [
479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.metaRow, children: [
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.articleBadge, children: "Article" }),
481
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.dot }),
482
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.metaItem, children: [
483
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Clock, { className: styles.icon }),
484
+ " 5 Min Read"
485
+ ] }),
486
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.dot }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.metaItem, children: [
488
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Calendar, { className: styles.icon }),
489
+ " ",
490
+ formattedDate
491
+ ] })
492
+ ] }),
493
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: styles.postTitle, children: post.title })
494
+ ]
495
+ }
496
+ ) }) }),
497
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.bodyContainer, children: [
498
+ thumbUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
499
+ "div",
500
+ {
501
+ className: styles.thumbnailWrapper,
502
+ style: {
503
+ opacity: mounted ? 1 : 0,
504
+ transform: mounted ? "none" : "scale(0.95)",
505
+ transition: "opacity 0.4s ease 0.2s, transform 0.4s ease 0.2s"
506
+ },
507
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
508
+ "img",
509
+ {
510
+ src: thumbUrl,
511
+ alt: post.title,
512
+ className: styles.thumbnail
513
+ }
514
+ )
515
+ }
516
+ ),
517
+ tocItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.tocWrapper, children: [
518
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
519
+ "button",
520
+ {
521
+ onClick: () => setTocOpen(!tocOpen),
522
+ className: styles.tocToggle,
523
+ children: [
524
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.tocToggleInner, children: [
525
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.tocIconWrap, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
526
+ "svg",
527
+ {
528
+ width: "14",
529
+ height: "14",
530
+ viewBox: "0 0 16 16",
531
+ fill: "none",
532
+ xmlns: "http://www.w3.org/2000/svg",
533
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
534
+ "path",
535
+ {
536
+ d: "M2 4h12M2 8h8M2 12h10",
537
+ stroke: "currentColor",
538
+ strokeWidth: "1.5",
539
+ strokeLinecap: "round"
540
+ }
541
+ )
542
+ }
543
+ ) }),
544
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.tocLabel, children: [
545
+ "Table of contents",
546
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.tocCount, children: [
547
+ "\xB7 ",
548
+ tocItems.length,
549
+ " sections"
550
+ ] })
551
+ ] })
552
+ ] }),
553
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
554
+ ChevronDown,
555
+ {
556
+ className: `${styles.chevronIcon}${tocOpen ? ` ${styles.chevronIconOpen}` : ""}`
557
+ }
558
+ )
559
+ ]
560
+ }
561
+ ),
562
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
563
+ "div",
564
+ {
565
+ style: {
566
+ overflow: "hidden",
567
+ maxHeight: tocOpen ? "2000px" : "0px",
568
+ opacity: tocOpen ? 1 : 0,
569
+ transition: "max-height 0.25s ease-in-out, opacity 0.25s ease-in-out"
570
+ },
571
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.tocPanelInner, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.tocGrid, children: tocItems.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
572
+ "button",
573
+ {
574
+ onClick: () => scrollToHeading(item.id),
575
+ className: [
576
+ styles.tocItem,
577
+ activeHeadingId === item.id ? styles.tocItemActive : "",
578
+ item.level === 3 ? styles.tocItemLevel3 : ""
579
+ ].filter(Boolean).join(" "),
580
+ children: [
581
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
582
+ "span",
583
+ {
584
+ className: [
585
+ styles.tocBadge,
586
+ activeHeadingId === item.id ? styles.tocBadgeActive : ""
587
+ ].filter(Boolean).join(" "),
588
+ children: idx + 1
589
+ }
590
+ ),
591
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: styles.tocItemText, children: item.text })
592
+ ]
593
+ },
594
+ item.id
595
+ )) }) })
596
+ }
597
+ )
598
+ ] }),
599
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
600
+ "div",
601
+ {
602
+ className: "blog-content",
603
+ dangerouslySetInnerHTML: { __html: renderedHtml }
604
+ }
605
+ ),
606
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.shareSection, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.shareInner, children: [
607
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
608
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: styles.shareTitle, children: "Share this article" }),
609
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: styles.shareSubtitle, children: "If it helped, pass it on." })
610
+ ] }),
611
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: styles.shareButtons, children: [
612
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: shareOnTwitter, className: styles.shareBtn, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.shareBtnInner, children: [
613
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Twitter, { className: styles.icon }),
614
+ " X"
615
+ ] }) }),
616
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: shareOnLinkedIn, className: styles.shareBtn, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.shareBtnInner, children: [
617
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Linkedin, { className: styles.icon }),
618
+ " LinkedIn"
619
+ ] }) }),
620
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: shareOnFacebook, className: styles.shareBtn, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: styles.shareBtnInner, children: [
621
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Facebook, { className: styles.icon }),
622
+ " Facebook"
623
+ ] }) }),
624
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
625
+ "button",
626
+ {
627
+ onClick: copyLink,
628
+ className: styles.copyBtn,
629
+ title: "Copy link",
630
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkIcon, { className: styles.icon })
631
+ }
632
+ )
633
+ ] })
634
+ ] }) })
635
+ ] })
636
+ ] })
637
+ ] });
638
+ }
639
+
640
+ // src/index.ts
641
+ function renderText() {
642
+ return "Hello World";
643
+ }
644
+ // Annotate the CommonJS export names for ESM import in node:
645
+ 0 && (module.exports = {
646
+ BlogRenderer,
647
+ renderText
648
+ });
649
+ //# sourceMappingURL=index.js.map