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