embed-dlsurf-blogs 1.0.2 → 1.0.3

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/README.md CHANGED
@@ -104,22 +104,6 @@ export default function Page() {
104
104
  }
105
105
  ```
106
106
 
107
- ### 3. Advanced: override API base URL
108
-
109
- ```tsx
110
- import BlogRenderer from "embed-dlsurf-blogs";
111
-
112
- export default function Page() {
113
- return (
114
- <BlogRenderer
115
- user="rishav"
116
- linkSlug="why-django-is-a-game-changer-in-modern-web-development"
117
- apiBaseUrl="https://docapi.dl.surf/api/doc"
118
- />
119
- );
120
- }
121
- ```
122
-
123
107
  ## Component Props
124
108
 
125
109
  ```ts
@@ -127,7 +111,6 @@ type BlogRendererProps = {
127
111
  user?: string;
128
112
  linkSlug?: string;
129
113
  blogUrl?: string;
130
- apiBaseUrl?: string;
131
114
  };
132
115
  ```
133
116
 
@@ -140,7 +123,6 @@ Notes:
140
123
 
141
124
  - Default export: `BlogRenderer`
142
125
  - Named export: `BlogRenderer`
143
- - Utility: `renderText`
144
126
 
145
127
  ## Internal Behavior
146
128
 
package/dist/index.d.mts CHANGED
@@ -31,6 +31,4 @@ interface BlogPost {
31
31
  }
32
32
  declare function BlogRenderer({ post, user, linkSlug, blogUrl, }: BlogRendererProps): react_jsx_runtime.JSX.Element;
33
33
 
34
- declare function renderText(): string;
35
-
36
- export { BlogRenderer, BlogRenderer as default, renderText };
34
+ export { BlogRenderer, BlogRenderer as default };
package/dist/index.d.ts CHANGED
@@ -31,6 +31,4 @@ interface BlogPost {
31
31
  }
32
32
  declare function BlogRenderer({ post, user, linkSlug, blogUrl, }: BlogRendererProps): react_jsx_runtime.JSX.Element;
33
33
 
34
- declare function renderText(): string;
35
-
36
- export { BlogRenderer, BlogRenderer as default, renderText };
34
+ export { BlogRenderer, BlogRenderer as default };
package/dist/index.js CHANGED
@@ -38,8 +38,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
38
38
  var index_exports = {};
39
39
  __export(index_exports, {
40
40
  BlogRenderer: () => BlogRenderer,
41
- default: () => BlogRenderer,
42
- renderText: () => renderText
41
+ default: () => BlogRenderer
43
42
  });
44
43
  module.exports = __toCommonJS(index_exports);
45
44
 
@@ -733,14 +732,8 @@ function BlogRenderer({
733
732
  ] })
734
733
  ] });
735
734
  }
736
-
737
- // src/index.ts
738
- function renderText() {
739
- return "Hello World";
740
- }
741
735
  // Annotate the CommonJS export names for ESM import in node:
742
736
  0 && (module.exports = {
743
- BlogRenderer,
744
- renderText
737
+ BlogRenderer
745
738
  });
746
739
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/BlogRenderer.tsx","#style-inject:#style-inject","../src/BlogRenderer.css","../src/tiptap-renderer.ts"],"sourcesContent":["export { BlogRenderer } from \"./BlogRenderer\";\nexport { BlogRenderer as default } from \"./BlogRenderer\";\nexport function renderText() {\n return \"Hello World\";\n}\nexport type { JSONContent } from \"@tiptap/core\";\n","import React, { useEffect, useRef, useState } from \"react\";\nimport \"./BlogRenderer.css\";\nimport { renderTiptapToHTML } from \"./tiptap-renderer\";\n\nconst styles = {\n wrapper: \"edlsb-wrapper\",\n progressBar: \"edlsb-progressBar\",\n main: \"edlsb-main\",\n headerSection: \"edlsb-headerSection\",\n headerContainer: \"edlsb-headerContainer\",\n headerContent: \"edlsb-headerContent\",\n metaRow: \"edlsb-metaRow\",\n articleBadge: \"edlsb-articleBadge\",\n dot: \"edlsb-dot\",\n metaItem: \"edlsb-metaItem\",\n icon: \"edlsb-icon\",\n postTitle: \"edlsb-postTitle\",\n bodyContainer: \"edlsb-bodyContainer\",\n thumbnailWrapper: \"edlsb-thumbnailWrapper\",\n thumbnail: \"edlsb-thumbnail\",\n tocWrapper: \"edlsb-tocWrapper\",\n tocToggle: \"edlsb-tocToggle\",\n tocToggleInner: \"edlsb-tocToggleInner\",\n tocIconWrap: \"edlsb-tocIconWrap\",\n tocLabel: \"edlsb-tocLabel\",\n tocCount: \"edlsb-tocCount\",\n chevronIcon: \"edlsb-chevronIcon\",\n chevronIconOpen: \"edlsb-chevronIconOpen\",\n tocPanelInner: \"edlsb-tocPanelInner\",\n tocGrid: \"edlsb-tocGrid\",\n tocItem: \"edlsb-tocItem\",\n tocItemActive: \"edlsb-tocItemActive\",\n tocItemLevel3: \"edlsb-tocItemLevel3\",\n tocBadge: \"edlsb-tocBadge\",\n tocBadgeActive: \"edlsb-tocBadgeActive\",\n tocItemText: \"edlsb-tocItemText\",\n shareSection: \"edlsb-shareSection\",\n shareInner: \"edlsb-shareInner\",\n shareTitle: \"edlsb-shareTitle\",\n shareSubtitle: \"edlsb-shareSubtitle\",\n shareButtons: \"edlsb-shareButtons\",\n shareBtn: \"edlsb-shareBtn\",\n shareBtnInner: \"edlsb-shareBtnInner\",\n copyBtn: \"edlsb-copyBtn\",\n} as const;\n\nconst baseIconProps = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n style: { flexShrink: 0 },\n \"aria-hidden\": true,\n} as const;\n\nconst Calendar = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" strokeWidth=\"2\" />\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Clock = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"9\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"7\" x2=\"12\" y2=\"12\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"12\" x2=\"15\" y2=\"14\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst ChevronDown = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <polyline points=\"6 9 12 15 18 9\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Twitter = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Linkedin = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Facebook = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst LinkIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path\n d=\"M10 14a5 5 0 0 1 0-7l1.5-1.5a5 5 0 0 1 7 7L17 14\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M14 10a5 5 0 0 1 0 7l-1.5 1.5a5 5 0 1 1-7-7L7 10\"\n strokeWidth=\"2\"\n />\n </svg>\n);\n\ninterface BlogRendererProps {\n post?: BlogPost;\n user?: string;\n linkSlug?: string;\n blogUrl?: string;\n}\n\ninterface BlogPostProfile {\n username: string;\n display_name: string;\n account_level: string;\n profile_picture: string;\n}\n\ninterface BlogPost {\n id: number;\n title: string;\n content_json: string;\n thumbnail_path: string | null;\n keywords: string;\n followers_only: boolean;\n visibility: string;\n created_at: string;\n link_slug: string;\n updated_at: string;\n profile: BlogPostProfile;\n ads_step: number;\n banner_ads: boolean;\n video_ads: boolean;\n}\n\ninterface TocItem {\n id: string;\n text: string;\n level: 2 | 3;\n}\n\ninterface DocApiResponse {\n status: string;\n message: string;\n data: BlogPost;\n}\n\nconst DEFAULT_DOC_API_BASE_URL = \"https://docapi.dl.surf/api/doc\";\n\nconst normalizeUsername = (value: string): string =>\n value.trim().replace(/^@+/, \"\");\n\nconst parseBlogReference = (\n blogUrl: string,\n): { user: string; linkSlug: string } | null => {\n try {\n const url = new URL(blogUrl);\n const segments = url.pathname.split(\"/\").filter(Boolean);\n\n // Supports: /api/doc/{user}/{linkSlug}\n const apiIndex = segments.findIndex(\n (segment, idx) => segment === \"api\" && segments[idx + 1] === \"doc\",\n );\n if (apiIndex >= 0 && segments.length >= apiIndex + 4) {\n return {\n user: decodeURIComponent(segments[apiIndex + 2]),\n linkSlug: decodeURIComponent(segments[apiIndex + 3]),\n };\n }\n\n // Fallback: use last two path segments as {user}/{linkSlug}\n if (segments.length >= 2) {\n return {\n user: decodeURIComponent(segments[segments.length - 2]),\n linkSlug: decodeURIComponent(segments[segments.length - 1]),\n };\n }\n\n return null;\n } catch {\n return null;\n }\n};\n\nconst stripProseWrappers = (html: string): string => {\n // Repeatedly unwrap outermost <div class=\"prose ...\"> until none remain.\n let result = html;\n const proseDiv = /^\\s*<div[^>]*\\bprose\\b[^>]*>([\\s\\S]*)<\\/div>\\s*$/;\n let prev = \"\";\n\n while (prev !== result) {\n prev = result;\n const match = result.match(proseDiv);\n if (match) result = match[1].trim();\n }\n\n return result;\n};\n\nexport function BlogRenderer({\n post,\n user,\n linkSlug,\n blogUrl,\n}: BlogRendererProps) {\n const [resolvedPost, setResolvedPost] = useState<BlogPost | null>(\n post ?? null,\n );\n const [isFetchingPost, setIsFetchingPost] = useState(!post);\n const [fetchError, setFetchError] = useState<string | null>(null);\n\n useEffect(() => {\n if (post) {\n setResolvedPost(post);\n setIsFetchingPost(false);\n setFetchError(null);\n return;\n }\n\n const directUser = user ? normalizeUsername(user) : undefined;\n const directSlug = linkSlug?.trim();\n let resolvedUser = directUser;\n let resolvedSlug = directSlug;\n\n if ((!resolvedUser || !resolvedSlug) && blogUrl) {\n const parsed = parseBlogReference(blogUrl);\n if (parsed) {\n resolvedUser = normalizeUsername(parsed.user);\n resolvedSlug = parsed.linkSlug;\n }\n }\n\n if (!resolvedUser || !resolvedSlug) {\n setResolvedPost(null);\n setIsFetchingPost(false);\n setFetchError(\n \"Provide either post, user+linkSlug, or a blogUrl with /{user}/{linkSlug}.\",\n );\n return;\n }\n\n const controller = new AbortController();\n const fetchPost = async () => {\n try {\n setIsFetchingPost(true);\n setFetchError(null);\n\n const base = DEFAULT_DOC_API_BASE_URL;\n\n const endpoint = `${base}/${encodeURIComponent(resolvedUser!)}/${encodeURIComponent(resolvedSlug!)}`;\n const response = await fetch(endpoint, { signal: controller.signal });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch document (${response.status})`);\n }\n\n const payload = (await response.json()) as DocApiResponse;\n if (!payload?.data) {\n throw new Error(\"Invalid API response: missing data field\");\n }\n\n setResolvedPost(payload.data);\n } catch (error) {\n if (controller.signal.aborted) return;\n setResolvedPost(null);\n setFetchError(\n error instanceof Error ? error.message : \"Failed to fetch document\",\n );\n } finally {\n if (!controller.signal.aborted) {\n setIsFetchingPost(false);\n }\n }\n };\n\n fetchPost();\n return () => controller.abort();\n }, [post, user, linkSlug, blogUrl]);\n\n const rawHtml = resolvedPost?.content_json\n ? renderTiptapToHTML(resolvedPost.content_json)\n : \"<p>Could not render content</p>\";\n const htmlContent = stripProseWrappers(rawHtml);\n\n const articleRef = useRef<HTMLDivElement>(null);\n const [renderedHtml, setRenderedHtml] = useState(htmlContent);\n const [tocItems, setTocItems] = useState<TocItem[]>([]);\n const [activeHeadingId, setActiveHeadingId] = useState(\"\");\n\n const [tocOpen, setTocOpen] = useState(false);\n const [scrollProgress, setScrollProgress] = useState(0);\n const [mounted, setMounted] = useState(false);\n\n const postData = resolvedPost;\n\n const getFullThumbnail = (path: string | undefined | null) => {\n if (!path) return undefined;\n if (path.startsWith(\"http\")) return path;\n return `https://cdn.dl.surf/${path}`;\n };\n\n const thumbUrl = getFullThumbnail(postData?.thumbnail_path);\n const publishDate = postData?.created_at || new Date().toISOString();\n const formattedDate = new Date(publishDate).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n\n // Share handlers\n const shareUrl = typeof window !== \"undefined\" ? window.location.href : \"\";\n const shareTitle = postData?.title || \"\";\n\n const shareOnTwitter = () =>\n window.open(\n `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(shareTitle)}`,\n \"_blank\",\n );\n const shareOnFacebook = () =>\n window.open(\n `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const shareOnLinkedIn = () =>\n window.open(\n `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const copyLink = () => {\n navigator.clipboard.writeText(shareUrl);\n alert(\"Link copied to clipboard!\");\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const handleScroll = () => {\n const scrollTop = window.scrollY || document.documentElement.scrollTop;\n const docHeight =\n document.documentElement.scrollHeight - window.innerHeight;\n setScrollProgress(docHeight > 0 ? scrollTop / docHeight : 0);\n };\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", handleScroll);\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = htmlContent || \"\";\n\n const headings = Array.from(wrapper.querySelectorAll(\"h2, h3\"));\n const nextTocItems: TocItem[] = [];\n const usedIds = new Set<string>();\n\n headings.forEach((heading, index) => {\n const text = heading.textContent?.trim() || `Section ${index + 1}`;\n const level = heading.tagName.toLowerCase() === \"h2\" ? 2 : 3;\n const base =\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\") || `section-${index + 1}`;\n\n let id = base;\n let suffix = 2;\n while (usedIds.has(id)) {\n id = `${base}-${suffix}`;\n suffix += 1;\n }\n usedIds.add(id);\n\n heading.setAttribute(\"id\", id);\n nextTocItems.push({ id, text, level });\n });\n\n setRenderedHtml(wrapper.innerHTML);\n setTocItems(nextTocItems);\n }, [htmlContent]);\n\n useEffect(() => {\n if (!tocItems.length) return;\n\n const headingElements = tocItems\n .map((item) => document.getElementById(item.id))\n .filter((el): el is HTMLElement => Boolean(el));\n\n if (!headingElements.length) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n const visible = entries\n .filter((entry) => entry.isIntersecting)\n .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);\n\n if (visible[0]?.target?.id) {\n setActiveHeadingId(visible[0].target.id);\n }\n },\n { rootMargin: \"-90px 0px -65% 0px\", threshold: 0.1 },\n );\n\n headingElements.forEach((el) => observer.observe(el));\n return () => observer.disconnect();\n }, [tocItems, renderedHtml]);\n\n const scrollToHeading = (id: string) => {\n setTocOpen(false);\n // Wait for collapse animation to finish before calculating position\n setTimeout(() => {\n const el = document.getElementById(id);\n if (!el) return;\n const offset = 110;\n const top = el.getBoundingClientRect().top + window.scrollY - offset;\n window.scrollTo({ top, behavior: \"smooth\" });\n }, 280);\n };\n\n if (!postData) {\n return (\n <div className={styles.wrapper}>\n <main className={styles.main}>\n <div className={styles.bodyContainer}>\n <p>\n {isFetchingPost\n ? \"Loading blog...\"\n : fetchError || \"Could not load blog content.\"}\n </p>\n </div>\n </main>\n </div>\n );\n }\n\n return (\n <div className={styles.wrapper}>\n <div\n className={styles.progressBar}\n style={{ transform: `scaleX(${scrollProgress})` }}\n />\n\n <main className={styles.main} ref={articleRef}>\n <div className={styles.headerSection}>\n <div className={styles.headerContainer}>\n <div\n className={styles.headerContent}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"translateY(20px)\",\n transition: \"opacity 0.4s ease, transform 0.4s ease\",\n }}\n >\n <div className={styles.metaRow}>\n <span className={styles.articleBadge}>Article</span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Clock className={styles.icon} /> 5 Min Read\n </span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Calendar className={styles.icon} /> {formattedDate}\n </span>\n </div>\n\n <h1 className={styles.postTitle}>{postData.title}</h1>\n </div>\n </div>\n </div>\n\n <div className={styles.bodyContainer}>\n {thumbUrl && (\n <div\n className={styles.thumbnailWrapper}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"scale(0.95)\",\n transition: \"opacity 0.4s ease 0.2s, transform 0.4s ease 0.2s\",\n }}\n >\n <img\n src={thumbUrl}\n alt={postData.title}\n className={styles.thumbnail}\n />\n </div>\n )}\n\n {/* Table of Contents — collapsible */}\n {tocItems.length > 0 && (\n <div className={styles.tocWrapper}>\n <button\n onClick={() => setTocOpen(!tocOpen)}\n className={styles.tocToggle}\n >\n <div className={styles.tocToggleInner}>\n <span className={styles.tocIconWrap}>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2 4h12M2 8h8M2 12h10\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n <span className={styles.tocLabel}>\n Table of contents\n <span className={styles.tocCount}>\n · {tocItems.length} sections\n </span>\n </span>\n </div>\n <ChevronDown\n className={`${styles.chevronIcon}${tocOpen ? ` ${styles.chevronIconOpen}` : \"\"}`}\n />\n </button>\n\n <div\n style={{\n overflow: \"hidden\",\n maxHeight: tocOpen ? \"2000px\" : \"0px\",\n opacity: tocOpen ? 1 : 0,\n transition:\n \"max-height 0.25s ease-in-out, opacity 0.25s ease-in-out\",\n }}\n >\n <div className={styles.tocPanelInner}>\n <div className={styles.tocGrid}>\n {tocItems.map((item, idx) => (\n <button\n key={item.id}\n onClick={() => scrollToHeading(item.id)}\n className={[\n styles.tocItem,\n activeHeadingId === item.id\n ? styles.tocItemActive\n : \"\",\n item.level === 3 ? styles.tocItemLevel3 : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <span\n className={[\n styles.tocBadge,\n activeHeadingId === item.id\n ? styles.tocBadgeActive\n : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {idx + 1}\n </span>\n <span className={styles.tocItemText}>{item.text}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <div\n className=\"blog-content\"\n dangerouslySetInnerHTML={{ __html: renderedHtml }}\n />\n\n {/* Share section */}\n <div className={styles.shareSection}>\n <div className={styles.shareInner}>\n <div>\n <h3 className={styles.shareTitle}>Share this article</h3>\n <p className={styles.shareSubtitle}>\n If it helped, pass it on.\n </p>\n </div>\n <div className={styles.shareButtons}>\n <button onClick={shareOnTwitter} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Twitter className={styles.icon} /> X\n </span>\n </button>\n <button onClick={shareOnLinkedIn} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Linkedin className={styles.icon} /> LinkedIn\n </span>\n </button>\n <button onClick={shareOnFacebook} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Facebook className={styles.icon} /> Facebook\n </span>\n </button>\n <button\n onClick={copyLink}\n className={styles.copyBtn}\n title=\"Copy link\"\n >\n <LinkIcon className={styles.icon} />\n </button>\n </div>\n </div>\n </div>\n </div>\n </main>\n </div>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';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\")","/**\n * SSR-safe Tiptap JSON → HTML renderer.\n *\n * Pure recursive serializer – zero DOM APIs required.\n * Works in Next.js server components and any Node.js environment.\n *\n * Styling matches the Blog View Styling Guide exactly:\n * - prose prose-lg dark:prose-invert wrapper classes\n * - per-node Tailwind classes identical to the Tiptap extension HTMLAttributes\n * - dark-mode variants included throughout\n */\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n// ─── Mark renderer ────────────────────────────────────────────────────────────\n\nfunction applyMark(html: string, mark: any): string {\n switch (mark.type) {\n case 'bold':\n return `<strong>${html}</strong>`;\n case 'italic':\n return `<em>${html}</em>`;\n case 'strike':\n return `<s>${html}</s>`;\n case 'underline':\n return `<u>${html}</u>`;\n case 'code':\n return `<code>${html}</code>`;\n case 'link': {\n const href = escapeHtml(mark.attrs?.href ?? '');\n const target = escapeHtml(mark.attrs?.target ?? '_blank');\n return `<a href=\"${href}\" target=\"${target}\" rel=\"noopener noreferrer\">${html}</a>`;\n }\n case 'textStyle': {\n // Handles color / font-size set via the TextStyle extension\n const color = mark.attrs?.color;\n const fontSize = mark.attrs?.fontSize;\n const style = [\n color ? `color:${color}` : '',\n fontSize ? `font-size:${fontSize}` : '',\n ].filter(Boolean).join(';');\n return style ? `<span style=\"${style}\">${html}</span>` : html;\n }\n case 'highlight': {\n const color = mark.attrs?.color;\n const style = color ? ` style=\"background-color:${color}\"` : '';\n return `<mark${style}>${html}</mark>`;\n }\n default:\n return html;\n }\n}\n\n// ─── Node renderer ────────────────────────────────────────────────────────────\n\nfunction renderChildren(node: any): string {\n if (!Array.isArray(node?.content)) return '';\n return node.content.map(renderNode).join('');\n}\n\nfunction renderNode(node: any): string {\n if (!node) return '';\n\n switch (node.type) {\n\n // ── Document root ────────────────────────────────────────────────────\n case 'doc':\n return renderChildren(node);\n\n // ── Block nodes ──────────────────────────────────────────────────────\n case 'paragraph': {\n const inner = renderChildren(node);\n if (!inner) return `<p><br /></p>`;\n return `<p>${inner}</p>`;\n }\n\n case 'heading': {\n const level = node.attrs?.level ?? 1;\n return `<h${level}>${renderChildren(node)}</h${level}>`;\n }\n\n case 'blockquote':\n return `<blockquote>${renderChildren(node)}</blockquote>`;\n\n case 'bulletList':\n return `<ul>${renderChildren(node)}</ul>`;\n\n case 'orderedList':\n return `<ol>${renderChildren(node)}</ol>`;\n\n case 'listItem':\n return `<li>${renderChildren(node)}</li>`;\n\n case 'taskList':\n return `<ul class=\"task-list\">${renderChildren(node)}</ul>`;\n\n case 'taskItem': {\n const checked = node.attrs?.checked ? ' checked' : '';\n return `<li class=\"task-item\"><input type=\"checkbox\"${checked} disabled /><div>${renderChildren(node)}</div></li>`;\n }\n\n case 'codeBlock': {\n const lang = node.attrs?.language ? ` data-language=\"${escapeHtml(node.attrs.language)}\"` : '';\n return `<pre${lang}><code>${renderChildren(node)}</code></pre>`;\n }\n\n case 'horizontalRule':\n return `<hr />`;\n\n case 'hardBreak':\n return `<br />`;\n\n // ── Media / embeds ───────────────────────────────────────────────────\n case 'image': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const title = node.attrs?.title ? ` title=\"${escapeHtml(node.attrs.title)}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${title} loading=\"lazy\" />`;\n }\n\n case 'resizableImage': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const width = node.attrs?.width ? ` width=\"${escapeHtml(String(node.attrs.width))}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${width} loading=\"lazy\" />`;\n }\n\n case 'youtube': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const width = node.attrs?.width ?? 640;\n const height = node.attrs?.height ?? 480;\n if (!src) return '';\n 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>`;\n }\n\n case 'twitter':\n case 'tweet': {\n // Render a simple link card since Twitter embeds require client-side JS\n const url = escapeHtml(node.attrs?.src ?? node.attrs?.url ?? '');\n if (!url) return '';\n 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>`;\n }\n\n // ── Inline nodes ─────────────────────────────────────────────────────\n case 'text': {\n let out = escapeHtml(node.text ?? '');\n if (Array.isArray(node.marks)) {\n for (const mark of node.marks) {\n out = applyMark(out, mark);\n }\n }\n return out;\n }\n\n default:\n // Gracefully handle unknown nodes by rendering their children\n return renderChildren(node);\n }\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport function renderTiptapToHTML(\n jsonContent: Record<string, any> | string,\n): string {\n try {\n if (!jsonContent) return '';\n\n let contentObj: any;\n if (typeof jsonContent === 'string') {\n try {\n contentObj = JSON.parse(jsonContent);\n } catch {\n // Not valid JSON → treat as a raw HTML string and return as-is\n return jsonContent;\n }\n } else {\n contentObj = jsonContent;\n }\n\n if (!contentObj || typeof contentObj !== 'object') {\n return String(jsonContent);\n }\n\n return renderNode(contentObj);\n } catch (error) {\n console.error('Failed to parse Tiptap JSON to HTML:', error);\n return '<p>Error loading content.</p>';\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/BlogRenderer.tsx","#style-inject:#style-inject","../src/BlogRenderer.css","../src/tiptap-renderer.ts"],"sourcesContent":["export { BlogRenderer } from \"./BlogRenderer\";\nexport { BlogRenderer as default } from \"./BlogRenderer\";\nexport type { JSONContent } from \"@tiptap/core\";\n","import React, { useEffect, useRef, useState } from \"react\";\nimport \"./BlogRenderer.css\";\nimport { renderTiptapToHTML } from \"./tiptap-renderer\";\n\nconst styles = {\n wrapper: \"edlsb-wrapper\",\n progressBar: \"edlsb-progressBar\",\n main: \"edlsb-main\",\n headerSection: \"edlsb-headerSection\",\n headerContainer: \"edlsb-headerContainer\",\n headerContent: \"edlsb-headerContent\",\n metaRow: \"edlsb-metaRow\",\n articleBadge: \"edlsb-articleBadge\",\n dot: \"edlsb-dot\",\n metaItem: \"edlsb-metaItem\",\n icon: \"edlsb-icon\",\n postTitle: \"edlsb-postTitle\",\n bodyContainer: \"edlsb-bodyContainer\",\n thumbnailWrapper: \"edlsb-thumbnailWrapper\",\n thumbnail: \"edlsb-thumbnail\",\n tocWrapper: \"edlsb-tocWrapper\",\n tocToggle: \"edlsb-tocToggle\",\n tocToggleInner: \"edlsb-tocToggleInner\",\n tocIconWrap: \"edlsb-tocIconWrap\",\n tocLabel: \"edlsb-tocLabel\",\n tocCount: \"edlsb-tocCount\",\n chevronIcon: \"edlsb-chevronIcon\",\n chevronIconOpen: \"edlsb-chevronIconOpen\",\n tocPanelInner: \"edlsb-tocPanelInner\",\n tocGrid: \"edlsb-tocGrid\",\n tocItem: \"edlsb-tocItem\",\n tocItemActive: \"edlsb-tocItemActive\",\n tocItemLevel3: \"edlsb-tocItemLevel3\",\n tocBadge: \"edlsb-tocBadge\",\n tocBadgeActive: \"edlsb-tocBadgeActive\",\n tocItemText: \"edlsb-tocItemText\",\n shareSection: \"edlsb-shareSection\",\n shareInner: \"edlsb-shareInner\",\n shareTitle: \"edlsb-shareTitle\",\n shareSubtitle: \"edlsb-shareSubtitle\",\n shareButtons: \"edlsb-shareButtons\",\n shareBtn: \"edlsb-shareBtn\",\n shareBtnInner: \"edlsb-shareBtnInner\",\n copyBtn: \"edlsb-copyBtn\",\n} as const;\n\nconst baseIconProps = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n style: { flexShrink: 0 },\n \"aria-hidden\": true,\n} as const;\n\nconst Calendar = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" strokeWidth=\"2\" />\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Clock = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"9\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"7\" x2=\"12\" y2=\"12\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"12\" x2=\"15\" y2=\"14\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst ChevronDown = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <polyline points=\"6 9 12 15 18 9\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Twitter = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Linkedin = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Facebook = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst LinkIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path\n d=\"M10 14a5 5 0 0 1 0-7l1.5-1.5a5 5 0 0 1 7 7L17 14\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M14 10a5 5 0 0 1 0 7l-1.5 1.5a5 5 0 1 1-7-7L7 10\"\n strokeWidth=\"2\"\n />\n </svg>\n);\n\ninterface BlogRendererProps {\n post?: BlogPost;\n user?: string;\n linkSlug?: string;\n blogUrl?: string;\n}\n\ninterface BlogPostProfile {\n username: string;\n display_name: string;\n account_level: string;\n profile_picture: string;\n}\n\ninterface BlogPost {\n id: number;\n title: string;\n content_json: string;\n thumbnail_path: string | null;\n keywords: string;\n followers_only: boolean;\n visibility: string;\n created_at: string;\n link_slug: string;\n updated_at: string;\n profile: BlogPostProfile;\n ads_step: number;\n banner_ads: boolean;\n video_ads: boolean;\n}\n\ninterface TocItem {\n id: string;\n text: string;\n level: 2 | 3;\n}\n\ninterface DocApiResponse {\n status: string;\n message: string;\n data: BlogPost;\n}\n\nconst DEFAULT_DOC_API_BASE_URL = \"https://docapi.dl.surf/api/doc\";\n\nconst normalizeUsername = (value: string): string =>\n value.trim().replace(/^@+/, \"\");\n\nconst parseBlogReference = (\n blogUrl: string,\n): { user: string; linkSlug: string } | null => {\n try {\n const url = new URL(blogUrl);\n const segments = url.pathname.split(\"/\").filter(Boolean);\n\n // Supports: /api/doc/{user}/{linkSlug}\n const apiIndex = segments.findIndex(\n (segment, idx) => segment === \"api\" && segments[idx + 1] === \"doc\",\n );\n if (apiIndex >= 0 && segments.length >= apiIndex + 4) {\n return {\n user: decodeURIComponent(segments[apiIndex + 2]),\n linkSlug: decodeURIComponent(segments[apiIndex + 3]),\n };\n }\n\n // Fallback: use last two path segments as {user}/{linkSlug}\n if (segments.length >= 2) {\n return {\n user: decodeURIComponent(segments[segments.length - 2]),\n linkSlug: decodeURIComponent(segments[segments.length - 1]),\n };\n }\n\n return null;\n } catch {\n return null;\n }\n};\n\nconst stripProseWrappers = (html: string): string => {\n // Repeatedly unwrap outermost <div class=\"prose ...\"> until none remain.\n let result = html;\n const proseDiv = /^\\s*<div[^>]*\\bprose\\b[^>]*>([\\s\\S]*)<\\/div>\\s*$/;\n let prev = \"\";\n\n while (prev !== result) {\n prev = result;\n const match = result.match(proseDiv);\n if (match) result = match[1].trim();\n }\n\n return result;\n};\n\nexport function BlogRenderer({\n post,\n user,\n linkSlug,\n blogUrl,\n}: BlogRendererProps) {\n const [resolvedPost, setResolvedPost] = useState<BlogPost | null>(\n post ?? null,\n );\n const [isFetchingPost, setIsFetchingPost] = useState(!post);\n const [fetchError, setFetchError] = useState<string | null>(null);\n\n useEffect(() => {\n if (post) {\n setResolvedPost(post);\n setIsFetchingPost(false);\n setFetchError(null);\n return;\n }\n\n const directUser = user ? normalizeUsername(user) : undefined;\n const directSlug = linkSlug?.trim();\n let resolvedUser = directUser;\n let resolvedSlug = directSlug;\n\n if ((!resolvedUser || !resolvedSlug) && blogUrl) {\n const parsed = parseBlogReference(blogUrl);\n if (parsed) {\n resolvedUser = normalizeUsername(parsed.user);\n resolvedSlug = parsed.linkSlug;\n }\n }\n\n if (!resolvedUser || !resolvedSlug) {\n setResolvedPost(null);\n setIsFetchingPost(false);\n setFetchError(\n \"Provide either post, user+linkSlug, or a blogUrl with /{user}/{linkSlug}.\",\n );\n return;\n }\n\n const controller = new AbortController();\n const fetchPost = async () => {\n try {\n setIsFetchingPost(true);\n setFetchError(null);\n\n const base = DEFAULT_DOC_API_BASE_URL;\n\n const endpoint = `${base}/${encodeURIComponent(resolvedUser!)}/${encodeURIComponent(resolvedSlug!)}`;\n const response = await fetch(endpoint, { signal: controller.signal });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch document (${response.status})`);\n }\n\n const payload = (await response.json()) as DocApiResponse;\n if (!payload?.data) {\n throw new Error(\"Invalid API response: missing data field\");\n }\n\n setResolvedPost(payload.data);\n } catch (error) {\n if (controller.signal.aborted) return;\n setResolvedPost(null);\n setFetchError(\n error instanceof Error ? error.message : \"Failed to fetch document\",\n );\n } finally {\n if (!controller.signal.aborted) {\n setIsFetchingPost(false);\n }\n }\n };\n\n fetchPost();\n return () => controller.abort();\n }, [post, user, linkSlug, blogUrl]);\n\n const rawHtml = resolvedPost?.content_json\n ? renderTiptapToHTML(resolvedPost.content_json)\n : \"<p>Could not render content</p>\";\n const htmlContent = stripProseWrappers(rawHtml);\n\n const articleRef = useRef<HTMLDivElement>(null);\n const [renderedHtml, setRenderedHtml] = useState(htmlContent);\n const [tocItems, setTocItems] = useState<TocItem[]>([]);\n const [activeHeadingId, setActiveHeadingId] = useState(\"\");\n\n const [tocOpen, setTocOpen] = useState(false);\n const [scrollProgress, setScrollProgress] = useState(0);\n const [mounted, setMounted] = useState(false);\n\n const postData = resolvedPost;\n\n const getFullThumbnail = (path: string | undefined | null) => {\n if (!path) return undefined;\n if (path.startsWith(\"http\")) return path;\n return `https://cdn.dl.surf/${path}`;\n };\n\n const thumbUrl = getFullThumbnail(postData?.thumbnail_path);\n const publishDate = postData?.created_at || new Date().toISOString();\n const formattedDate = new Date(publishDate).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n\n // Share handlers\n const shareUrl = typeof window !== \"undefined\" ? window.location.href : \"\";\n const shareTitle = postData?.title || \"\";\n\n const shareOnTwitter = () =>\n window.open(\n `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(shareTitle)}`,\n \"_blank\",\n );\n const shareOnFacebook = () =>\n window.open(\n `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const shareOnLinkedIn = () =>\n window.open(\n `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const copyLink = () => {\n navigator.clipboard.writeText(shareUrl);\n alert(\"Link copied to clipboard!\");\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const handleScroll = () => {\n const scrollTop = window.scrollY || document.documentElement.scrollTop;\n const docHeight =\n document.documentElement.scrollHeight - window.innerHeight;\n setScrollProgress(docHeight > 0 ? scrollTop / docHeight : 0);\n };\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", handleScroll);\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = htmlContent || \"\";\n\n const headings = Array.from(wrapper.querySelectorAll(\"h2, h3\"));\n const nextTocItems: TocItem[] = [];\n const usedIds = new Set<string>();\n\n headings.forEach((heading, index) => {\n const text = heading.textContent?.trim() || `Section ${index + 1}`;\n const level = heading.tagName.toLowerCase() === \"h2\" ? 2 : 3;\n const base =\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\") || `section-${index + 1}`;\n\n let id = base;\n let suffix = 2;\n while (usedIds.has(id)) {\n id = `${base}-${suffix}`;\n suffix += 1;\n }\n usedIds.add(id);\n\n heading.setAttribute(\"id\", id);\n nextTocItems.push({ id, text, level });\n });\n\n setRenderedHtml(wrapper.innerHTML);\n setTocItems(nextTocItems);\n }, [htmlContent]);\n\n useEffect(() => {\n if (!tocItems.length) return;\n\n const headingElements = tocItems\n .map((item) => document.getElementById(item.id))\n .filter((el): el is HTMLElement => Boolean(el));\n\n if (!headingElements.length) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n const visible = entries\n .filter((entry) => entry.isIntersecting)\n .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);\n\n if (visible[0]?.target?.id) {\n setActiveHeadingId(visible[0].target.id);\n }\n },\n { rootMargin: \"-90px 0px -65% 0px\", threshold: 0.1 },\n );\n\n headingElements.forEach((el) => observer.observe(el));\n return () => observer.disconnect();\n }, [tocItems, renderedHtml]);\n\n const scrollToHeading = (id: string) => {\n setTocOpen(false);\n // Wait for collapse animation to finish before calculating position\n setTimeout(() => {\n const el = document.getElementById(id);\n if (!el) return;\n const offset = 110;\n const top = el.getBoundingClientRect().top + window.scrollY - offset;\n window.scrollTo({ top, behavior: \"smooth\" });\n }, 280);\n };\n\n if (!postData) {\n return (\n <div className={styles.wrapper}>\n <main className={styles.main}>\n <div className={styles.bodyContainer}>\n <p>\n {isFetchingPost\n ? \"Loading blog...\"\n : fetchError || \"Could not load blog content.\"}\n </p>\n </div>\n </main>\n </div>\n );\n }\n\n return (\n <div className={styles.wrapper}>\n <div\n className={styles.progressBar}\n style={{ transform: `scaleX(${scrollProgress})` }}\n />\n\n <main className={styles.main} ref={articleRef}>\n <div className={styles.headerSection}>\n <div className={styles.headerContainer}>\n <div\n className={styles.headerContent}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"translateY(20px)\",\n transition: \"opacity 0.4s ease, transform 0.4s ease\",\n }}\n >\n <div className={styles.metaRow}>\n <span className={styles.articleBadge}>Article</span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Clock className={styles.icon} /> 5 Min Read\n </span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Calendar className={styles.icon} /> {formattedDate}\n </span>\n </div>\n\n <h1 className={styles.postTitle}>{postData.title}</h1>\n </div>\n </div>\n </div>\n\n <div className={styles.bodyContainer}>\n {thumbUrl && (\n <div\n className={styles.thumbnailWrapper}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"scale(0.95)\",\n transition: \"opacity 0.4s ease 0.2s, transform 0.4s ease 0.2s\",\n }}\n >\n <img\n src={thumbUrl}\n alt={postData.title}\n className={styles.thumbnail}\n />\n </div>\n )}\n\n {/* Table of Contents — collapsible */}\n {tocItems.length > 0 && (\n <div className={styles.tocWrapper}>\n <button\n onClick={() => setTocOpen(!tocOpen)}\n className={styles.tocToggle}\n >\n <div className={styles.tocToggleInner}>\n <span className={styles.tocIconWrap}>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2 4h12M2 8h8M2 12h10\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n <span className={styles.tocLabel}>\n Table of contents\n <span className={styles.tocCount}>\n · {tocItems.length} sections\n </span>\n </span>\n </div>\n <ChevronDown\n className={`${styles.chevronIcon}${tocOpen ? ` ${styles.chevronIconOpen}` : \"\"}`}\n />\n </button>\n\n <div\n style={{\n overflow: \"hidden\",\n maxHeight: tocOpen ? \"2000px\" : \"0px\",\n opacity: tocOpen ? 1 : 0,\n transition:\n \"max-height 0.25s ease-in-out, opacity 0.25s ease-in-out\",\n }}\n >\n <div className={styles.tocPanelInner}>\n <div className={styles.tocGrid}>\n {tocItems.map((item, idx) => (\n <button\n key={item.id}\n onClick={() => scrollToHeading(item.id)}\n className={[\n styles.tocItem,\n activeHeadingId === item.id\n ? styles.tocItemActive\n : \"\",\n item.level === 3 ? styles.tocItemLevel3 : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <span\n className={[\n styles.tocBadge,\n activeHeadingId === item.id\n ? styles.tocBadgeActive\n : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {idx + 1}\n </span>\n <span className={styles.tocItemText}>{item.text}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <div\n className=\"blog-content\"\n dangerouslySetInnerHTML={{ __html: renderedHtml }}\n />\n\n {/* Share section */}\n <div className={styles.shareSection}>\n <div className={styles.shareInner}>\n <div>\n <h3 className={styles.shareTitle}>Share this article</h3>\n <p className={styles.shareSubtitle}>\n If it helped, pass it on.\n </p>\n </div>\n <div className={styles.shareButtons}>\n <button onClick={shareOnTwitter} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Twitter className={styles.icon} /> X\n </span>\n </button>\n <button onClick={shareOnLinkedIn} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Linkedin className={styles.icon} /> LinkedIn\n </span>\n </button>\n <button onClick={shareOnFacebook} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Facebook className={styles.icon} /> Facebook\n </span>\n </button>\n <button\n onClick={copyLink}\n className={styles.copyBtn}\n title=\"Copy link\"\n >\n <LinkIcon className={styles.icon} />\n </button>\n </div>\n </div>\n </div>\n </div>\n </main>\n </div>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';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\")","/**\n * SSR-safe Tiptap JSON → HTML renderer.\n *\n * Pure recursive serializer – zero DOM APIs required.\n * Works in Next.js server components and any Node.js environment.\n *\n * Styling matches the Blog View Styling Guide exactly:\n * - prose prose-lg dark:prose-invert wrapper classes\n * - per-node Tailwind classes identical to the Tiptap extension HTMLAttributes\n * - dark-mode variants included throughout\n */\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n// ─── Mark renderer ────────────────────────────────────────────────────────────\n\nfunction applyMark(html: string, mark: any): string {\n switch (mark.type) {\n case 'bold':\n return `<strong>${html}</strong>`;\n case 'italic':\n return `<em>${html}</em>`;\n case 'strike':\n return `<s>${html}</s>`;\n case 'underline':\n return `<u>${html}</u>`;\n case 'code':\n return `<code>${html}</code>`;\n case 'link': {\n const href = escapeHtml(mark.attrs?.href ?? '');\n const target = escapeHtml(mark.attrs?.target ?? '_blank');\n return `<a href=\"${href}\" target=\"${target}\" rel=\"noopener noreferrer\">${html}</a>`;\n }\n case 'textStyle': {\n // Handles color / font-size set via the TextStyle extension\n const color = mark.attrs?.color;\n const fontSize = mark.attrs?.fontSize;\n const style = [\n color ? `color:${color}` : '',\n fontSize ? `font-size:${fontSize}` : '',\n ].filter(Boolean).join(';');\n return style ? `<span style=\"${style}\">${html}</span>` : html;\n }\n case 'highlight': {\n const color = mark.attrs?.color;\n const style = color ? ` style=\"background-color:${color}\"` : '';\n return `<mark${style}>${html}</mark>`;\n }\n default:\n return html;\n }\n}\n\n// ─── Node renderer ────────────────────────────────────────────────────────────\n\nfunction renderChildren(node: any): string {\n if (!Array.isArray(node?.content)) return '';\n return node.content.map(renderNode).join('');\n}\n\nfunction renderNode(node: any): string {\n if (!node) return '';\n\n switch (node.type) {\n\n // ── Document root ────────────────────────────────────────────────────\n case 'doc':\n return renderChildren(node);\n\n // ── Block nodes ──────────────────────────────────────────────────────\n case 'paragraph': {\n const inner = renderChildren(node);\n if (!inner) return `<p><br /></p>`;\n return `<p>${inner}</p>`;\n }\n\n case 'heading': {\n const level = node.attrs?.level ?? 1;\n return `<h${level}>${renderChildren(node)}</h${level}>`;\n }\n\n case 'blockquote':\n return `<blockquote>${renderChildren(node)}</blockquote>`;\n\n case 'bulletList':\n return `<ul>${renderChildren(node)}</ul>`;\n\n case 'orderedList':\n return `<ol>${renderChildren(node)}</ol>`;\n\n case 'listItem':\n return `<li>${renderChildren(node)}</li>`;\n\n case 'taskList':\n return `<ul class=\"task-list\">${renderChildren(node)}</ul>`;\n\n case 'taskItem': {\n const checked = node.attrs?.checked ? ' checked' : '';\n return `<li class=\"task-item\"><input type=\"checkbox\"${checked} disabled /><div>${renderChildren(node)}</div></li>`;\n }\n\n case 'codeBlock': {\n const lang = node.attrs?.language ? ` data-language=\"${escapeHtml(node.attrs.language)}\"` : '';\n return `<pre${lang}><code>${renderChildren(node)}</code></pre>`;\n }\n\n case 'horizontalRule':\n return `<hr />`;\n\n case 'hardBreak':\n return `<br />`;\n\n // ── Media / embeds ───────────────────────────────────────────────────\n case 'image': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const title = node.attrs?.title ? ` title=\"${escapeHtml(node.attrs.title)}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${title} loading=\"lazy\" />`;\n }\n\n case 'resizableImage': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const width = node.attrs?.width ? ` width=\"${escapeHtml(String(node.attrs.width))}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${width} loading=\"lazy\" />`;\n }\n\n case 'youtube': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const width = node.attrs?.width ?? 640;\n const height = node.attrs?.height ?? 480;\n if (!src) return '';\n 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>`;\n }\n\n case 'twitter':\n case 'tweet': {\n // Render a simple link card since Twitter embeds require client-side JS\n const url = escapeHtml(node.attrs?.src ?? node.attrs?.url ?? '');\n if (!url) return '';\n 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>`;\n }\n\n // ── Inline nodes ─────────────────────────────────────────────────────\n case 'text': {\n let out = escapeHtml(node.text ?? '');\n if (Array.isArray(node.marks)) {\n for (const mark of node.marks) {\n out = applyMark(out, mark);\n }\n }\n return out;\n }\n\n default:\n // Gracefully handle unknown nodes by rendering their children\n return renderChildren(node);\n }\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport function renderTiptapToHTML(\n jsonContent: Record<string, any> | string,\n): string {\n try {\n if (!jsonContent) return '';\n\n let contentObj: any;\n if (typeof jsonContent === 'string') {\n try {\n contentObj = JSON.parse(jsonContent);\n } catch {\n // Not valid JSON → treat as a raw HTML string and return as-is\n return jsonContent;\n }\n } else {\n contentObj = jsonContent;\n }\n\n if (!contentObj || typeof contentObj !== 'object') {\n return String(jsonContent);\n }\n\n return renderNode(contentObj);\n } catch (error) {\n console.error('Failed to parse Tiptap JSON to HTML:', error);\n return '<p>Error loading content.</p>';\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -708,14 +708,8 @@ function BlogRenderer({
708
708
  ] })
709
709
  ] });
710
710
  }
711
-
712
- // src/index.ts
713
- function renderText() {
714
- return "Hello World";
715
- }
716
711
  export {
717
712
  BlogRenderer,
718
- BlogRenderer as default,
719
- renderText
713
+ BlogRenderer as default
720
714
  };
721
715
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/BlogRenderer.tsx","#style-inject:#style-inject","../src/BlogRenderer.css","../src/tiptap-renderer.ts","../src/index.ts"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport \"./BlogRenderer.css\";\nimport { renderTiptapToHTML } from \"./tiptap-renderer\";\n\nconst styles = {\n wrapper: \"edlsb-wrapper\",\n progressBar: \"edlsb-progressBar\",\n main: \"edlsb-main\",\n headerSection: \"edlsb-headerSection\",\n headerContainer: \"edlsb-headerContainer\",\n headerContent: \"edlsb-headerContent\",\n metaRow: \"edlsb-metaRow\",\n articleBadge: \"edlsb-articleBadge\",\n dot: \"edlsb-dot\",\n metaItem: \"edlsb-metaItem\",\n icon: \"edlsb-icon\",\n postTitle: \"edlsb-postTitle\",\n bodyContainer: \"edlsb-bodyContainer\",\n thumbnailWrapper: \"edlsb-thumbnailWrapper\",\n thumbnail: \"edlsb-thumbnail\",\n tocWrapper: \"edlsb-tocWrapper\",\n tocToggle: \"edlsb-tocToggle\",\n tocToggleInner: \"edlsb-tocToggleInner\",\n tocIconWrap: \"edlsb-tocIconWrap\",\n tocLabel: \"edlsb-tocLabel\",\n tocCount: \"edlsb-tocCount\",\n chevronIcon: \"edlsb-chevronIcon\",\n chevronIconOpen: \"edlsb-chevronIconOpen\",\n tocPanelInner: \"edlsb-tocPanelInner\",\n tocGrid: \"edlsb-tocGrid\",\n tocItem: \"edlsb-tocItem\",\n tocItemActive: \"edlsb-tocItemActive\",\n tocItemLevel3: \"edlsb-tocItemLevel3\",\n tocBadge: \"edlsb-tocBadge\",\n tocBadgeActive: \"edlsb-tocBadgeActive\",\n tocItemText: \"edlsb-tocItemText\",\n shareSection: \"edlsb-shareSection\",\n shareInner: \"edlsb-shareInner\",\n shareTitle: \"edlsb-shareTitle\",\n shareSubtitle: \"edlsb-shareSubtitle\",\n shareButtons: \"edlsb-shareButtons\",\n shareBtn: \"edlsb-shareBtn\",\n shareBtnInner: \"edlsb-shareBtnInner\",\n copyBtn: \"edlsb-copyBtn\",\n} as const;\n\nconst baseIconProps = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n style: { flexShrink: 0 },\n \"aria-hidden\": true,\n} as const;\n\nconst Calendar = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" strokeWidth=\"2\" />\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Clock = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"9\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"7\" x2=\"12\" y2=\"12\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"12\" x2=\"15\" y2=\"14\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst ChevronDown = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <polyline points=\"6 9 12 15 18 9\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Twitter = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Linkedin = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Facebook = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst LinkIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path\n d=\"M10 14a5 5 0 0 1 0-7l1.5-1.5a5 5 0 0 1 7 7L17 14\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M14 10a5 5 0 0 1 0 7l-1.5 1.5a5 5 0 1 1-7-7L7 10\"\n strokeWidth=\"2\"\n />\n </svg>\n);\n\ninterface BlogRendererProps {\n post?: BlogPost;\n user?: string;\n linkSlug?: string;\n blogUrl?: string;\n}\n\ninterface BlogPostProfile {\n username: string;\n display_name: string;\n account_level: string;\n profile_picture: string;\n}\n\ninterface BlogPost {\n id: number;\n title: string;\n content_json: string;\n thumbnail_path: string | null;\n keywords: string;\n followers_only: boolean;\n visibility: string;\n created_at: string;\n link_slug: string;\n updated_at: string;\n profile: BlogPostProfile;\n ads_step: number;\n banner_ads: boolean;\n video_ads: boolean;\n}\n\ninterface TocItem {\n id: string;\n text: string;\n level: 2 | 3;\n}\n\ninterface DocApiResponse {\n status: string;\n message: string;\n data: BlogPost;\n}\n\nconst DEFAULT_DOC_API_BASE_URL = \"https://docapi.dl.surf/api/doc\";\n\nconst normalizeUsername = (value: string): string =>\n value.trim().replace(/^@+/, \"\");\n\nconst parseBlogReference = (\n blogUrl: string,\n): { user: string; linkSlug: string } | null => {\n try {\n const url = new URL(blogUrl);\n const segments = url.pathname.split(\"/\").filter(Boolean);\n\n // Supports: /api/doc/{user}/{linkSlug}\n const apiIndex = segments.findIndex(\n (segment, idx) => segment === \"api\" && segments[idx + 1] === \"doc\",\n );\n if (apiIndex >= 0 && segments.length >= apiIndex + 4) {\n return {\n user: decodeURIComponent(segments[apiIndex + 2]),\n linkSlug: decodeURIComponent(segments[apiIndex + 3]),\n };\n }\n\n // Fallback: use last two path segments as {user}/{linkSlug}\n if (segments.length >= 2) {\n return {\n user: decodeURIComponent(segments[segments.length - 2]),\n linkSlug: decodeURIComponent(segments[segments.length - 1]),\n };\n }\n\n return null;\n } catch {\n return null;\n }\n};\n\nconst stripProseWrappers = (html: string): string => {\n // Repeatedly unwrap outermost <div class=\"prose ...\"> until none remain.\n let result = html;\n const proseDiv = /^\\s*<div[^>]*\\bprose\\b[^>]*>([\\s\\S]*)<\\/div>\\s*$/;\n let prev = \"\";\n\n while (prev !== result) {\n prev = result;\n const match = result.match(proseDiv);\n if (match) result = match[1].trim();\n }\n\n return result;\n};\n\nexport function BlogRenderer({\n post,\n user,\n linkSlug,\n blogUrl,\n}: BlogRendererProps) {\n const [resolvedPost, setResolvedPost] = useState<BlogPost | null>(\n post ?? null,\n );\n const [isFetchingPost, setIsFetchingPost] = useState(!post);\n const [fetchError, setFetchError] = useState<string | null>(null);\n\n useEffect(() => {\n if (post) {\n setResolvedPost(post);\n setIsFetchingPost(false);\n setFetchError(null);\n return;\n }\n\n const directUser = user ? normalizeUsername(user) : undefined;\n const directSlug = linkSlug?.trim();\n let resolvedUser = directUser;\n let resolvedSlug = directSlug;\n\n if ((!resolvedUser || !resolvedSlug) && blogUrl) {\n const parsed = parseBlogReference(blogUrl);\n if (parsed) {\n resolvedUser = normalizeUsername(parsed.user);\n resolvedSlug = parsed.linkSlug;\n }\n }\n\n if (!resolvedUser || !resolvedSlug) {\n setResolvedPost(null);\n setIsFetchingPost(false);\n setFetchError(\n \"Provide either post, user+linkSlug, or a blogUrl with /{user}/{linkSlug}.\",\n );\n return;\n }\n\n const controller = new AbortController();\n const fetchPost = async () => {\n try {\n setIsFetchingPost(true);\n setFetchError(null);\n\n const base = DEFAULT_DOC_API_BASE_URL;\n\n const endpoint = `${base}/${encodeURIComponent(resolvedUser!)}/${encodeURIComponent(resolvedSlug!)}`;\n const response = await fetch(endpoint, { signal: controller.signal });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch document (${response.status})`);\n }\n\n const payload = (await response.json()) as DocApiResponse;\n if (!payload?.data) {\n throw new Error(\"Invalid API response: missing data field\");\n }\n\n setResolvedPost(payload.data);\n } catch (error) {\n if (controller.signal.aborted) return;\n setResolvedPost(null);\n setFetchError(\n error instanceof Error ? error.message : \"Failed to fetch document\",\n );\n } finally {\n if (!controller.signal.aborted) {\n setIsFetchingPost(false);\n }\n }\n };\n\n fetchPost();\n return () => controller.abort();\n }, [post, user, linkSlug, blogUrl]);\n\n const rawHtml = resolvedPost?.content_json\n ? renderTiptapToHTML(resolvedPost.content_json)\n : \"<p>Could not render content</p>\";\n const htmlContent = stripProseWrappers(rawHtml);\n\n const articleRef = useRef<HTMLDivElement>(null);\n const [renderedHtml, setRenderedHtml] = useState(htmlContent);\n const [tocItems, setTocItems] = useState<TocItem[]>([]);\n const [activeHeadingId, setActiveHeadingId] = useState(\"\");\n\n const [tocOpen, setTocOpen] = useState(false);\n const [scrollProgress, setScrollProgress] = useState(0);\n const [mounted, setMounted] = useState(false);\n\n const postData = resolvedPost;\n\n const getFullThumbnail = (path: string | undefined | null) => {\n if (!path) return undefined;\n if (path.startsWith(\"http\")) return path;\n return `https://cdn.dl.surf/${path}`;\n };\n\n const thumbUrl = getFullThumbnail(postData?.thumbnail_path);\n const publishDate = postData?.created_at || new Date().toISOString();\n const formattedDate = new Date(publishDate).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n\n // Share handlers\n const shareUrl = typeof window !== \"undefined\" ? window.location.href : \"\";\n const shareTitle = postData?.title || \"\";\n\n const shareOnTwitter = () =>\n window.open(\n `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(shareTitle)}`,\n \"_blank\",\n );\n const shareOnFacebook = () =>\n window.open(\n `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const shareOnLinkedIn = () =>\n window.open(\n `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const copyLink = () => {\n navigator.clipboard.writeText(shareUrl);\n alert(\"Link copied to clipboard!\");\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const handleScroll = () => {\n const scrollTop = window.scrollY || document.documentElement.scrollTop;\n const docHeight =\n document.documentElement.scrollHeight - window.innerHeight;\n setScrollProgress(docHeight > 0 ? scrollTop / docHeight : 0);\n };\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", handleScroll);\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = htmlContent || \"\";\n\n const headings = Array.from(wrapper.querySelectorAll(\"h2, h3\"));\n const nextTocItems: TocItem[] = [];\n const usedIds = new Set<string>();\n\n headings.forEach((heading, index) => {\n const text = heading.textContent?.trim() || `Section ${index + 1}`;\n const level = heading.tagName.toLowerCase() === \"h2\" ? 2 : 3;\n const base =\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\") || `section-${index + 1}`;\n\n let id = base;\n let suffix = 2;\n while (usedIds.has(id)) {\n id = `${base}-${suffix}`;\n suffix += 1;\n }\n usedIds.add(id);\n\n heading.setAttribute(\"id\", id);\n nextTocItems.push({ id, text, level });\n });\n\n setRenderedHtml(wrapper.innerHTML);\n setTocItems(nextTocItems);\n }, [htmlContent]);\n\n useEffect(() => {\n if (!tocItems.length) return;\n\n const headingElements = tocItems\n .map((item) => document.getElementById(item.id))\n .filter((el): el is HTMLElement => Boolean(el));\n\n if (!headingElements.length) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n const visible = entries\n .filter((entry) => entry.isIntersecting)\n .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);\n\n if (visible[0]?.target?.id) {\n setActiveHeadingId(visible[0].target.id);\n }\n },\n { rootMargin: \"-90px 0px -65% 0px\", threshold: 0.1 },\n );\n\n headingElements.forEach((el) => observer.observe(el));\n return () => observer.disconnect();\n }, [tocItems, renderedHtml]);\n\n const scrollToHeading = (id: string) => {\n setTocOpen(false);\n // Wait for collapse animation to finish before calculating position\n setTimeout(() => {\n const el = document.getElementById(id);\n if (!el) return;\n const offset = 110;\n const top = el.getBoundingClientRect().top + window.scrollY - offset;\n window.scrollTo({ top, behavior: \"smooth\" });\n }, 280);\n };\n\n if (!postData) {\n return (\n <div className={styles.wrapper}>\n <main className={styles.main}>\n <div className={styles.bodyContainer}>\n <p>\n {isFetchingPost\n ? \"Loading blog...\"\n : fetchError || \"Could not load blog content.\"}\n </p>\n </div>\n </main>\n </div>\n );\n }\n\n return (\n <div className={styles.wrapper}>\n <div\n className={styles.progressBar}\n style={{ transform: `scaleX(${scrollProgress})` }}\n />\n\n <main className={styles.main} ref={articleRef}>\n <div className={styles.headerSection}>\n <div className={styles.headerContainer}>\n <div\n className={styles.headerContent}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"translateY(20px)\",\n transition: \"opacity 0.4s ease, transform 0.4s ease\",\n }}\n >\n <div className={styles.metaRow}>\n <span className={styles.articleBadge}>Article</span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Clock className={styles.icon} /> 5 Min Read\n </span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Calendar className={styles.icon} /> {formattedDate}\n </span>\n </div>\n\n <h1 className={styles.postTitle}>{postData.title}</h1>\n </div>\n </div>\n </div>\n\n <div className={styles.bodyContainer}>\n {thumbUrl && (\n <div\n className={styles.thumbnailWrapper}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"scale(0.95)\",\n transition: \"opacity 0.4s ease 0.2s, transform 0.4s ease 0.2s\",\n }}\n >\n <img\n src={thumbUrl}\n alt={postData.title}\n className={styles.thumbnail}\n />\n </div>\n )}\n\n {/* Table of Contents — collapsible */}\n {tocItems.length > 0 && (\n <div className={styles.tocWrapper}>\n <button\n onClick={() => setTocOpen(!tocOpen)}\n className={styles.tocToggle}\n >\n <div className={styles.tocToggleInner}>\n <span className={styles.tocIconWrap}>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2 4h12M2 8h8M2 12h10\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n <span className={styles.tocLabel}>\n Table of contents\n <span className={styles.tocCount}>\n · {tocItems.length} sections\n </span>\n </span>\n </div>\n <ChevronDown\n className={`${styles.chevronIcon}${tocOpen ? ` ${styles.chevronIconOpen}` : \"\"}`}\n />\n </button>\n\n <div\n style={{\n overflow: \"hidden\",\n maxHeight: tocOpen ? \"2000px\" : \"0px\",\n opacity: tocOpen ? 1 : 0,\n transition:\n \"max-height 0.25s ease-in-out, opacity 0.25s ease-in-out\",\n }}\n >\n <div className={styles.tocPanelInner}>\n <div className={styles.tocGrid}>\n {tocItems.map((item, idx) => (\n <button\n key={item.id}\n onClick={() => scrollToHeading(item.id)}\n className={[\n styles.tocItem,\n activeHeadingId === item.id\n ? styles.tocItemActive\n : \"\",\n item.level === 3 ? styles.tocItemLevel3 : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <span\n className={[\n styles.tocBadge,\n activeHeadingId === item.id\n ? styles.tocBadgeActive\n : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {idx + 1}\n </span>\n <span className={styles.tocItemText}>{item.text}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <div\n className=\"blog-content\"\n dangerouslySetInnerHTML={{ __html: renderedHtml }}\n />\n\n {/* Share section */}\n <div className={styles.shareSection}>\n <div className={styles.shareInner}>\n <div>\n <h3 className={styles.shareTitle}>Share this article</h3>\n <p className={styles.shareSubtitle}>\n If it helped, pass it on.\n </p>\n </div>\n <div className={styles.shareButtons}>\n <button onClick={shareOnTwitter} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Twitter className={styles.icon} /> X\n </span>\n </button>\n <button onClick={shareOnLinkedIn} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Linkedin className={styles.icon} /> LinkedIn\n </span>\n </button>\n <button onClick={shareOnFacebook} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Facebook className={styles.icon} /> Facebook\n </span>\n </button>\n <button\n onClick={copyLink}\n className={styles.copyBtn}\n title=\"Copy link\"\n >\n <LinkIcon className={styles.icon} />\n </button>\n </div>\n </div>\n </div>\n </div>\n </main>\n </div>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';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\")","/**\n * SSR-safe Tiptap JSON → HTML renderer.\n *\n * Pure recursive serializer – zero DOM APIs required.\n * Works in Next.js server components and any Node.js environment.\n *\n * Styling matches the Blog View Styling Guide exactly:\n * - prose prose-lg dark:prose-invert wrapper classes\n * - per-node Tailwind classes identical to the Tiptap extension HTMLAttributes\n * - dark-mode variants included throughout\n */\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n// ─── Mark renderer ────────────────────────────────────────────────────────────\n\nfunction applyMark(html: string, mark: any): string {\n switch (mark.type) {\n case 'bold':\n return `<strong>${html}</strong>`;\n case 'italic':\n return `<em>${html}</em>`;\n case 'strike':\n return `<s>${html}</s>`;\n case 'underline':\n return `<u>${html}</u>`;\n case 'code':\n return `<code>${html}</code>`;\n case 'link': {\n const href = escapeHtml(mark.attrs?.href ?? '');\n const target = escapeHtml(mark.attrs?.target ?? '_blank');\n return `<a href=\"${href}\" target=\"${target}\" rel=\"noopener noreferrer\">${html}</a>`;\n }\n case 'textStyle': {\n // Handles color / font-size set via the TextStyle extension\n const color = mark.attrs?.color;\n const fontSize = mark.attrs?.fontSize;\n const style = [\n color ? `color:${color}` : '',\n fontSize ? `font-size:${fontSize}` : '',\n ].filter(Boolean).join(';');\n return style ? `<span style=\"${style}\">${html}</span>` : html;\n }\n case 'highlight': {\n const color = mark.attrs?.color;\n const style = color ? ` style=\"background-color:${color}\"` : '';\n return `<mark${style}>${html}</mark>`;\n }\n default:\n return html;\n }\n}\n\n// ─── Node renderer ────────────────────────────────────────────────────────────\n\nfunction renderChildren(node: any): string {\n if (!Array.isArray(node?.content)) return '';\n return node.content.map(renderNode).join('');\n}\n\nfunction renderNode(node: any): string {\n if (!node) return '';\n\n switch (node.type) {\n\n // ── Document root ────────────────────────────────────────────────────\n case 'doc':\n return renderChildren(node);\n\n // ── Block nodes ──────────────────────────────────────────────────────\n case 'paragraph': {\n const inner = renderChildren(node);\n if (!inner) return `<p><br /></p>`;\n return `<p>${inner}</p>`;\n }\n\n case 'heading': {\n const level = node.attrs?.level ?? 1;\n return `<h${level}>${renderChildren(node)}</h${level}>`;\n }\n\n case 'blockquote':\n return `<blockquote>${renderChildren(node)}</blockquote>`;\n\n case 'bulletList':\n return `<ul>${renderChildren(node)}</ul>`;\n\n case 'orderedList':\n return `<ol>${renderChildren(node)}</ol>`;\n\n case 'listItem':\n return `<li>${renderChildren(node)}</li>`;\n\n case 'taskList':\n return `<ul class=\"task-list\">${renderChildren(node)}</ul>`;\n\n case 'taskItem': {\n const checked = node.attrs?.checked ? ' checked' : '';\n return `<li class=\"task-item\"><input type=\"checkbox\"${checked} disabled /><div>${renderChildren(node)}</div></li>`;\n }\n\n case 'codeBlock': {\n const lang = node.attrs?.language ? ` data-language=\"${escapeHtml(node.attrs.language)}\"` : '';\n return `<pre${lang}><code>${renderChildren(node)}</code></pre>`;\n }\n\n case 'horizontalRule':\n return `<hr />`;\n\n case 'hardBreak':\n return `<br />`;\n\n // ── Media / embeds ───────────────────────────────────────────────────\n case 'image': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const title = node.attrs?.title ? ` title=\"${escapeHtml(node.attrs.title)}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${title} loading=\"lazy\" />`;\n }\n\n case 'resizableImage': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const width = node.attrs?.width ? ` width=\"${escapeHtml(String(node.attrs.width))}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${width} loading=\"lazy\" />`;\n }\n\n case 'youtube': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const width = node.attrs?.width ?? 640;\n const height = node.attrs?.height ?? 480;\n if (!src) return '';\n 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>`;\n }\n\n case 'twitter':\n case 'tweet': {\n // Render a simple link card since Twitter embeds require client-side JS\n const url = escapeHtml(node.attrs?.src ?? node.attrs?.url ?? '');\n if (!url) return '';\n 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>`;\n }\n\n // ── Inline nodes ─────────────────────────────────────────────────────\n case 'text': {\n let out = escapeHtml(node.text ?? '');\n if (Array.isArray(node.marks)) {\n for (const mark of node.marks) {\n out = applyMark(out, mark);\n }\n }\n return out;\n }\n\n default:\n // Gracefully handle unknown nodes by rendering their children\n return renderChildren(node);\n }\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport function renderTiptapToHTML(\n jsonContent: Record<string, any> | string,\n): string {\n try {\n if (!jsonContent) return '';\n\n let contentObj: any;\n if (typeof jsonContent === 'string') {\n try {\n contentObj = JSON.parse(jsonContent);\n } catch {\n // Not valid JSON → treat as a raw HTML string and return as-is\n return jsonContent;\n }\n } else {\n contentObj = jsonContent;\n }\n\n if (!contentObj || typeof contentObj !== 'object') {\n return String(jsonContent);\n }\n\n return renderNode(contentObj);\n } catch (error) {\n console.error('Failed to parse Tiptap JSON to HTML:', error);\n return '<p>Error loading content.</p>';\n }\n}\n","export { BlogRenderer } from \"./BlogRenderer\";\nexport { BlogRenderer as default } from \"./BlogRenderer\";\nexport function renderText() {\n return \"Hello World\";\n}\nexport type { JSONContent } from \"@tiptap/core\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/BlogRenderer.tsx","#style-inject:#style-inject","../src/BlogRenderer.css","../src/tiptap-renderer.ts"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport \"./BlogRenderer.css\";\nimport { renderTiptapToHTML } from \"./tiptap-renderer\";\n\nconst styles = {\n wrapper: \"edlsb-wrapper\",\n progressBar: \"edlsb-progressBar\",\n main: \"edlsb-main\",\n headerSection: \"edlsb-headerSection\",\n headerContainer: \"edlsb-headerContainer\",\n headerContent: \"edlsb-headerContent\",\n metaRow: \"edlsb-metaRow\",\n articleBadge: \"edlsb-articleBadge\",\n dot: \"edlsb-dot\",\n metaItem: \"edlsb-metaItem\",\n icon: \"edlsb-icon\",\n postTitle: \"edlsb-postTitle\",\n bodyContainer: \"edlsb-bodyContainer\",\n thumbnailWrapper: \"edlsb-thumbnailWrapper\",\n thumbnail: \"edlsb-thumbnail\",\n tocWrapper: \"edlsb-tocWrapper\",\n tocToggle: \"edlsb-tocToggle\",\n tocToggleInner: \"edlsb-tocToggleInner\",\n tocIconWrap: \"edlsb-tocIconWrap\",\n tocLabel: \"edlsb-tocLabel\",\n tocCount: \"edlsb-tocCount\",\n chevronIcon: \"edlsb-chevronIcon\",\n chevronIconOpen: \"edlsb-chevronIconOpen\",\n tocPanelInner: \"edlsb-tocPanelInner\",\n tocGrid: \"edlsb-tocGrid\",\n tocItem: \"edlsb-tocItem\",\n tocItemActive: \"edlsb-tocItemActive\",\n tocItemLevel3: \"edlsb-tocItemLevel3\",\n tocBadge: \"edlsb-tocBadge\",\n tocBadgeActive: \"edlsb-tocBadgeActive\",\n tocItemText: \"edlsb-tocItemText\",\n shareSection: \"edlsb-shareSection\",\n shareInner: \"edlsb-shareInner\",\n shareTitle: \"edlsb-shareTitle\",\n shareSubtitle: \"edlsb-shareSubtitle\",\n shareButtons: \"edlsb-shareButtons\",\n shareBtn: \"edlsb-shareBtn\",\n shareBtnInner: \"edlsb-shareBtnInner\",\n copyBtn: \"edlsb-copyBtn\",\n} as const;\n\nconst baseIconProps = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n style: { flexShrink: 0 },\n \"aria-hidden\": true,\n} as const;\n\nconst Calendar = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" strokeWidth=\"2\" />\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" strokeWidth=\"2\" />\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Clock = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"9\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"7\" x2=\"12\" y2=\"12\" strokeWidth=\"2\" />\n <line x1=\"12\" y1=\"12\" x2=\"15\" y2=\"14\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst ChevronDown = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <polyline points=\"6 9 12 15 18 9\" strokeWidth=\"2\" />\n </svg>\n);\n\nconst Twitter = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Linkedin = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst Facebook = (props: React.SVGProps<SVGSVGElement>) => (\n <svg {...baseIconProps} viewBox=\"0 0 24 24\" fill=\"currentColor\" {...props}>\n <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\" />\n </svg>\n);\n\nconst LinkIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <svg\n {...baseIconProps}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...props}\n >\n <path\n d=\"M10 14a5 5 0 0 1 0-7l1.5-1.5a5 5 0 0 1 7 7L17 14\"\n strokeWidth=\"2\"\n />\n <path\n d=\"M14 10a5 5 0 0 1 0 7l-1.5 1.5a5 5 0 1 1-7-7L7 10\"\n strokeWidth=\"2\"\n />\n </svg>\n);\n\ninterface BlogRendererProps {\n post?: BlogPost;\n user?: string;\n linkSlug?: string;\n blogUrl?: string;\n}\n\ninterface BlogPostProfile {\n username: string;\n display_name: string;\n account_level: string;\n profile_picture: string;\n}\n\ninterface BlogPost {\n id: number;\n title: string;\n content_json: string;\n thumbnail_path: string | null;\n keywords: string;\n followers_only: boolean;\n visibility: string;\n created_at: string;\n link_slug: string;\n updated_at: string;\n profile: BlogPostProfile;\n ads_step: number;\n banner_ads: boolean;\n video_ads: boolean;\n}\n\ninterface TocItem {\n id: string;\n text: string;\n level: 2 | 3;\n}\n\ninterface DocApiResponse {\n status: string;\n message: string;\n data: BlogPost;\n}\n\nconst DEFAULT_DOC_API_BASE_URL = \"https://docapi.dl.surf/api/doc\";\n\nconst normalizeUsername = (value: string): string =>\n value.trim().replace(/^@+/, \"\");\n\nconst parseBlogReference = (\n blogUrl: string,\n): { user: string; linkSlug: string } | null => {\n try {\n const url = new URL(blogUrl);\n const segments = url.pathname.split(\"/\").filter(Boolean);\n\n // Supports: /api/doc/{user}/{linkSlug}\n const apiIndex = segments.findIndex(\n (segment, idx) => segment === \"api\" && segments[idx + 1] === \"doc\",\n );\n if (apiIndex >= 0 && segments.length >= apiIndex + 4) {\n return {\n user: decodeURIComponent(segments[apiIndex + 2]),\n linkSlug: decodeURIComponent(segments[apiIndex + 3]),\n };\n }\n\n // Fallback: use last two path segments as {user}/{linkSlug}\n if (segments.length >= 2) {\n return {\n user: decodeURIComponent(segments[segments.length - 2]),\n linkSlug: decodeURIComponent(segments[segments.length - 1]),\n };\n }\n\n return null;\n } catch {\n return null;\n }\n};\n\nconst stripProseWrappers = (html: string): string => {\n // Repeatedly unwrap outermost <div class=\"prose ...\"> until none remain.\n let result = html;\n const proseDiv = /^\\s*<div[^>]*\\bprose\\b[^>]*>([\\s\\S]*)<\\/div>\\s*$/;\n let prev = \"\";\n\n while (prev !== result) {\n prev = result;\n const match = result.match(proseDiv);\n if (match) result = match[1].trim();\n }\n\n return result;\n};\n\nexport function BlogRenderer({\n post,\n user,\n linkSlug,\n blogUrl,\n}: BlogRendererProps) {\n const [resolvedPost, setResolvedPost] = useState<BlogPost | null>(\n post ?? null,\n );\n const [isFetchingPost, setIsFetchingPost] = useState(!post);\n const [fetchError, setFetchError] = useState<string | null>(null);\n\n useEffect(() => {\n if (post) {\n setResolvedPost(post);\n setIsFetchingPost(false);\n setFetchError(null);\n return;\n }\n\n const directUser = user ? normalizeUsername(user) : undefined;\n const directSlug = linkSlug?.trim();\n let resolvedUser = directUser;\n let resolvedSlug = directSlug;\n\n if ((!resolvedUser || !resolvedSlug) && blogUrl) {\n const parsed = parseBlogReference(blogUrl);\n if (parsed) {\n resolvedUser = normalizeUsername(parsed.user);\n resolvedSlug = parsed.linkSlug;\n }\n }\n\n if (!resolvedUser || !resolvedSlug) {\n setResolvedPost(null);\n setIsFetchingPost(false);\n setFetchError(\n \"Provide either post, user+linkSlug, or a blogUrl with /{user}/{linkSlug}.\",\n );\n return;\n }\n\n const controller = new AbortController();\n const fetchPost = async () => {\n try {\n setIsFetchingPost(true);\n setFetchError(null);\n\n const base = DEFAULT_DOC_API_BASE_URL;\n\n const endpoint = `${base}/${encodeURIComponent(resolvedUser!)}/${encodeURIComponent(resolvedSlug!)}`;\n const response = await fetch(endpoint, { signal: controller.signal });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch document (${response.status})`);\n }\n\n const payload = (await response.json()) as DocApiResponse;\n if (!payload?.data) {\n throw new Error(\"Invalid API response: missing data field\");\n }\n\n setResolvedPost(payload.data);\n } catch (error) {\n if (controller.signal.aborted) return;\n setResolvedPost(null);\n setFetchError(\n error instanceof Error ? error.message : \"Failed to fetch document\",\n );\n } finally {\n if (!controller.signal.aborted) {\n setIsFetchingPost(false);\n }\n }\n };\n\n fetchPost();\n return () => controller.abort();\n }, [post, user, linkSlug, blogUrl]);\n\n const rawHtml = resolvedPost?.content_json\n ? renderTiptapToHTML(resolvedPost.content_json)\n : \"<p>Could not render content</p>\";\n const htmlContent = stripProseWrappers(rawHtml);\n\n const articleRef = useRef<HTMLDivElement>(null);\n const [renderedHtml, setRenderedHtml] = useState(htmlContent);\n const [tocItems, setTocItems] = useState<TocItem[]>([]);\n const [activeHeadingId, setActiveHeadingId] = useState(\"\");\n\n const [tocOpen, setTocOpen] = useState(false);\n const [scrollProgress, setScrollProgress] = useState(0);\n const [mounted, setMounted] = useState(false);\n\n const postData = resolvedPost;\n\n const getFullThumbnail = (path: string | undefined | null) => {\n if (!path) return undefined;\n if (path.startsWith(\"http\")) return path;\n return `https://cdn.dl.surf/${path}`;\n };\n\n const thumbUrl = getFullThumbnail(postData?.thumbnail_path);\n const publishDate = postData?.created_at || new Date().toISOString();\n const formattedDate = new Date(publishDate).toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n\n // Share handlers\n const shareUrl = typeof window !== \"undefined\" ? window.location.href : \"\";\n const shareTitle = postData?.title || \"\";\n\n const shareOnTwitter = () =>\n window.open(\n `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(shareTitle)}`,\n \"_blank\",\n );\n const shareOnFacebook = () =>\n window.open(\n `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const shareOnLinkedIn = () =>\n window.open(\n `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}`,\n \"_blank\",\n );\n const copyLink = () => {\n navigator.clipboard.writeText(shareUrl);\n alert(\"Link copied to clipboard!\");\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const handleScroll = () => {\n const scrollTop = window.scrollY || document.documentElement.scrollTop;\n const docHeight =\n document.documentElement.scrollHeight - window.innerHeight;\n setScrollProgress(docHeight > 0 ? scrollTop / docHeight : 0);\n };\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", handleScroll);\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const wrapper = document.createElement(\"div\");\n wrapper.innerHTML = htmlContent || \"\";\n\n const headings = Array.from(wrapper.querySelectorAll(\"h2, h3\"));\n const nextTocItems: TocItem[] = [];\n const usedIds = new Set<string>();\n\n headings.forEach((heading, index) => {\n const text = heading.textContent?.trim() || `Section ${index + 1}`;\n const level = heading.tagName.toLowerCase() === \"h2\" ? 2 : 3;\n const base =\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\") || `section-${index + 1}`;\n\n let id = base;\n let suffix = 2;\n while (usedIds.has(id)) {\n id = `${base}-${suffix}`;\n suffix += 1;\n }\n usedIds.add(id);\n\n heading.setAttribute(\"id\", id);\n nextTocItems.push({ id, text, level });\n });\n\n setRenderedHtml(wrapper.innerHTML);\n setTocItems(nextTocItems);\n }, [htmlContent]);\n\n useEffect(() => {\n if (!tocItems.length) return;\n\n const headingElements = tocItems\n .map((item) => document.getElementById(item.id))\n .filter((el): el is HTMLElement => Boolean(el));\n\n if (!headingElements.length) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n const visible = entries\n .filter((entry) => entry.isIntersecting)\n .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);\n\n if (visible[0]?.target?.id) {\n setActiveHeadingId(visible[0].target.id);\n }\n },\n { rootMargin: \"-90px 0px -65% 0px\", threshold: 0.1 },\n );\n\n headingElements.forEach((el) => observer.observe(el));\n return () => observer.disconnect();\n }, [tocItems, renderedHtml]);\n\n const scrollToHeading = (id: string) => {\n setTocOpen(false);\n // Wait for collapse animation to finish before calculating position\n setTimeout(() => {\n const el = document.getElementById(id);\n if (!el) return;\n const offset = 110;\n const top = el.getBoundingClientRect().top + window.scrollY - offset;\n window.scrollTo({ top, behavior: \"smooth\" });\n }, 280);\n };\n\n if (!postData) {\n return (\n <div className={styles.wrapper}>\n <main className={styles.main}>\n <div className={styles.bodyContainer}>\n <p>\n {isFetchingPost\n ? \"Loading blog...\"\n : fetchError || \"Could not load blog content.\"}\n </p>\n </div>\n </main>\n </div>\n );\n }\n\n return (\n <div className={styles.wrapper}>\n <div\n className={styles.progressBar}\n style={{ transform: `scaleX(${scrollProgress})` }}\n />\n\n <main className={styles.main} ref={articleRef}>\n <div className={styles.headerSection}>\n <div className={styles.headerContainer}>\n <div\n className={styles.headerContent}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"translateY(20px)\",\n transition: \"opacity 0.4s ease, transform 0.4s ease\",\n }}\n >\n <div className={styles.metaRow}>\n <span className={styles.articleBadge}>Article</span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Clock className={styles.icon} /> 5 Min Read\n </span>\n <span className={styles.dot} />\n <span className={styles.metaItem}>\n <Calendar className={styles.icon} /> {formattedDate}\n </span>\n </div>\n\n <h1 className={styles.postTitle}>{postData.title}</h1>\n </div>\n </div>\n </div>\n\n <div className={styles.bodyContainer}>\n {thumbUrl && (\n <div\n className={styles.thumbnailWrapper}\n style={{\n opacity: mounted ? 1 : 0,\n transform: mounted ? \"none\" : \"scale(0.95)\",\n transition: \"opacity 0.4s ease 0.2s, transform 0.4s ease 0.2s\",\n }}\n >\n <img\n src={thumbUrl}\n alt={postData.title}\n className={styles.thumbnail}\n />\n </div>\n )}\n\n {/* Table of Contents — collapsible */}\n {tocItems.length > 0 && (\n <div className={styles.tocWrapper}>\n <button\n onClick={() => setTocOpen(!tocOpen)}\n className={styles.tocToggle}\n >\n <div className={styles.tocToggleInner}>\n <span className={styles.tocIconWrap}>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M2 4h12M2 8h8M2 12h10\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n <span className={styles.tocLabel}>\n Table of contents\n <span className={styles.tocCount}>\n · {tocItems.length} sections\n </span>\n </span>\n </div>\n <ChevronDown\n className={`${styles.chevronIcon}${tocOpen ? ` ${styles.chevronIconOpen}` : \"\"}`}\n />\n </button>\n\n <div\n style={{\n overflow: \"hidden\",\n maxHeight: tocOpen ? \"2000px\" : \"0px\",\n opacity: tocOpen ? 1 : 0,\n transition:\n \"max-height 0.25s ease-in-out, opacity 0.25s ease-in-out\",\n }}\n >\n <div className={styles.tocPanelInner}>\n <div className={styles.tocGrid}>\n {tocItems.map((item, idx) => (\n <button\n key={item.id}\n onClick={() => scrollToHeading(item.id)}\n className={[\n styles.tocItem,\n activeHeadingId === item.id\n ? styles.tocItemActive\n : \"\",\n item.level === 3 ? styles.tocItemLevel3 : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <span\n className={[\n styles.tocBadge,\n activeHeadingId === item.id\n ? styles.tocBadgeActive\n : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {idx + 1}\n </span>\n <span className={styles.tocItemText}>{item.text}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <div\n className=\"blog-content\"\n dangerouslySetInnerHTML={{ __html: renderedHtml }}\n />\n\n {/* Share section */}\n <div className={styles.shareSection}>\n <div className={styles.shareInner}>\n <div>\n <h3 className={styles.shareTitle}>Share this article</h3>\n <p className={styles.shareSubtitle}>\n If it helped, pass it on.\n </p>\n </div>\n <div className={styles.shareButtons}>\n <button onClick={shareOnTwitter} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Twitter className={styles.icon} /> X\n </span>\n </button>\n <button onClick={shareOnLinkedIn} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Linkedin className={styles.icon} /> LinkedIn\n </span>\n </button>\n <button onClick={shareOnFacebook} className={styles.shareBtn}>\n <span className={styles.shareBtnInner}>\n <Facebook className={styles.icon} /> Facebook\n </span>\n </button>\n <button\n onClick={copyLink}\n className={styles.copyBtn}\n title=\"Copy link\"\n >\n <LinkIcon className={styles.icon} />\n </button>\n </div>\n </div>\n </div>\n </div>\n </main>\n </div>\n );\n}\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';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\")","/**\n * SSR-safe Tiptap JSON → HTML renderer.\n *\n * Pure recursive serializer – zero DOM APIs required.\n * Works in Next.js server components and any Node.js environment.\n *\n * Styling matches the Blog View Styling Guide exactly:\n * - prose prose-lg dark:prose-invert wrapper classes\n * - per-node Tailwind classes identical to the Tiptap extension HTMLAttributes\n * - dark-mode variants included throughout\n */\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n// ─── Mark renderer ────────────────────────────────────────────────────────────\n\nfunction applyMark(html: string, mark: any): string {\n switch (mark.type) {\n case 'bold':\n return `<strong>${html}</strong>`;\n case 'italic':\n return `<em>${html}</em>`;\n case 'strike':\n return `<s>${html}</s>`;\n case 'underline':\n return `<u>${html}</u>`;\n case 'code':\n return `<code>${html}</code>`;\n case 'link': {\n const href = escapeHtml(mark.attrs?.href ?? '');\n const target = escapeHtml(mark.attrs?.target ?? '_blank');\n return `<a href=\"${href}\" target=\"${target}\" rel=\"noopener noreferrer\">${html}</a>`;\n }\n case 'textStyle': {\n // Handles color / font-size set via the TextStyle extension\n const color = mark.attrs?.color;\n const fontSize = mark.attrs?.fontSize;\n const style = [\n color ? `color:${color}` : '',\n fontSize ? `font-size:${fontSize}` : '',\n ].filter(Boolean).join(';');\n return style ? `<span style=\"${style}\">${html}</span>` : html;\n }\n case 'highlight': {\n const color = mark.attrs?.color;\n const style = color ? ` style=\"background-color:${color}\"` : '';\n return `<mark${style}>${html}</mark>`;\n }\n default:\n return html;\n }\n}\n\n// ─── Node renderer ────────────────────────────────────────────────────────────\n\nfunction renderChildren(node: any): string {\n if (!Array.isArray(node?.content)) return '';\n return node.content.map(renderNode).join('');\n}\n\nfunction renderNode(node: any): string {\n if (!node) return '';\n\n switch (node.type) {\n\n // ── Document root ────────────────────────────────────────────────────\n case 'doc':\n return renderChildren(node);\n\n // ── Block nodes ──────────────────────────────────────────────────────\n case 'paragraph': {\n const inner = renderChildren(node);\n if (!inner) return `<p><br /></p>`;\n return `<p>${inner}</p>`;\n }\n\n case 'heading': {\n const level = node.attrs?.level ?? 1;\n return `<h${level}>${renderChildren(node)}</h${level}>`;\n }\n\n case 'blockquote':\n return `<blockquote>${renderChildren(node)}</blockquote>`;\n\n case 'bulletList':\n return `<ul>${renderChildren(node)}</ul>`;\n\n case 'orderedList':\n return `<ol>${renderChildren(node)}</ol>`;\n\n case 'listItem':\n return `<li>${renderChildren(node)}</li>`;\n\n case 'taskList':\n return `<ul class=\"task-list\">${renderChildren(node)}</ul>`;\n\n case 'taskItem': {\n const checked = node.attrs?.checked ? ' checked' : '';\n return `<li class=\"task-item\"><input type=\"checkbox\"${checked} disabled /><div>${renderChildren(node)}</div></li>`;\n }\n\n case 'codeBlock': {\n const lang = node.attrs?.language ? ` data-language=\"${escapeHtml(node.attrs.language)}\"` : '';\n return `<pre${lang}><code>${renderChildren(node)}</code></pre>`;\n }\n\n case 'horizontalRule':\n return `<hr />`;\n\n case 'hardBreak':\n return `<br />`;\n\n // ── Media / embeds ───────────────────────────────────────────────────\n case 'image': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const title = node.attrs?.title ? ` title=\"${escapeHtml(node.attrs.title)}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${title} loading=\"lazy\" />`;\n }\n\n case 'resizableImage': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const alt = escapeHtml(node.attrs?.alt ?? '');\n const width = node.attrs?.width ? ` width=\"${escapeHtml(String(node.attrs.width))}\"` : '';\n return `<img src=\"${src}\" alt=\"${alt}\"${width} loading=\"lazy\" />`;\n }\n\n case 'youtube': {\n const src = escapeHtml(node.attrs?.src ?? '');\n const width = node.attrs?.width ?? 640;\n const height = node.attrs?.height ?? 480;\n if (!src) return '';\n 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>`;\n }\n\n case 'twitter':\n case 'tweet': {\n // Render a simple link card since Twitter embeds require client-side JS\n const url = escapeHtml(node.attrs?.src ?? node.attrs?.url ?? '');\n if (!url) return '';\n 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>`;\n }\n\n // ── Inline nodes ─────────────────────────────────────────────────────\n case 'text': {\n let out = escapeHtml(node.text ?? '');\n if (Array.isArray(node.marks)) {\n for (const mark of node.marks) {\n out = applyMark(out, mark);\n }\n }\n return out;\n }\n\n default:\n // Gracefully handle unknown nodes by rendering their children\n return renderChildren(node);\n }\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport function renderTiptapToHTML(\n jsonContent: Record<string, any> | string,\n): string {\n try {\n if (!jsonContent) return '';\n\n let contentObj: any;\n if (typeof jsonContent === 'string') {\n try {\n contentObj = JSON.parse(jsonContent);\n } catch {\n // Not valid JSON → treat as a raw HTML string and return as-is\n return jsonContent;\n }\n } else {\n contentObj = jsonContent;\n }\n\n if (!contentObj || typeof contentObj !== 'object') {\n return String(jsonContent);\n }\n\n return renderNode(contentObj);\n } catch (error) {\n console.error('Failed to parse Tiptap JSON to HTML:', error);\n return '<p>Error loading content.</p>';\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "embed-dlsurf-blogs",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",