@twelvemonday/blog-editor 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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components/BlogEditor.tsx","../src/context.tsx","../src/theme.ts","../src/lib/blog-blocks.ts","../src/lib/blog-seo.ts","../src/components/BlockCanvas.tsx","../src/lib/paste-html.ts","../src/components/BlockToolbar.tsx","../src/components/PostSidebar.tsx","../src/components/BlockLibrary.tsx","../src/components/SeoPanel.tsx"],"sourcesContent":["export { default as BlogEditor } from './components/BlogEditor';\nexport { EditorProvider, useEditorContext } from './context';\nexport { defaultTheme, resolveTheme, themeToCssVars } from './theme';\n\nexport type {\n BlogEditorProps,\n EditorDocument,\n EditorTheme,\n OnUploadImage,\n SaveResult,\n} from './types';\n\n/** @deprecated Use BlogEditorProps */\nexport type { BlogEditorProps as BlockEditorProps } from './types';\n\nexport {\n BLOCK_LABELS,\n HEADING_CLASSES,\n HEADING_LABELS,\n blocksToHtml,\n createBlock,\n htmlToBlocks,\n slugifyTitle,\n} from './lib/blog-blocks';\nexport type { BlogBlock, BlogBlockType, HeadingLevel } from './lib/blog-blocks';\n\nexport {\n cleanPastedHtml,\n inlineHtmlFromBlocks,\n insertHtmlAtCursor,\n isMultiBlockPaste,\n pastedHtmlToBlocks,\n} from './lib/paste-html';\n\nexport {\n computeSeoScore,\n descriptionLengthColor,\n getSeoPreview,\n titleLengthColor,\n} from './lib/blog-seo';\nexport type { SeoCheck, SeoScore } from './lib/blog-seo';\n","'use client';\n\nimport { useMemo, useState } from 'react';\nimport {\n ArrowLeft,\n ExternalLink,\n Loader2,\n PanelRightClose,\n PanelRightOpen,\n Redo2,\n Undo2,\n} from 'lucide-react';\nimport {\n DndContext,\n DragOverlay,\n PointerSensor,\n closestCenter,\n useSensor,\n useSensors,\n type DragEndEvent,\n type DragStartEvent,\n} from '@dnd-kit/core';\nimport { arrayMove } from '@dnd-kit/sortable';\nimport { EditorProvider } from '../context';\nimport { resolveTheme, themeToCssVars } from '../theme';\nimport type { BlogEditorProps, EditorDocument } from '../types';\nimport {\n blocksToHtml,\n createBlock,\n htmlToBlocks,\n slugifyTitle,\n BLOCK_LABELS,\n type BlogBlock,\n type BlogBlockType,\n} from '../lib/blog-blocks';\nimport { computeSeoScore } from '../lib/blog-seo';\nimport BlockCanvas from './BlockCanvas';\nimport PostSidebar from './PostSidebar';\n\nfunction BlogEditorInner({\n initial,\n originalSlug,\n onSave,\n onNavigate,\n backHref = '#',\n previewUrl,\n newPostSlug = 'new-post',\n className = '',\n}: Omit<BlogEditorProps, 'theme' | 'onUploadImage' | 'uploadFile' | 'siteName' | 'baseUrl'>) {\n const [post, setPost] = useState<EditorDocument>(initial);\n const initialBlocks = useMemo(() => htmlToBlocks(initial.content), [initial.content]);\n const [blocks, setBlocks] = useState<BlogBlock[]>(initialBlocks);\n const [blocksHistory, setBlocksHistory] = useState<BlogBlock[][]>([initialBlocks]);\n const [historyIndex, setHistoryIndex] = useState(0);\n const [activeId, setActiveId] = useState<string | null>(null);\n const [draggingType, setDraggingType] = useState<BlogBlockType | null>(null);\n const [saving, setSaving] = useState(false);\n const [message, setMessage] = useState('');\n const [sidebarOpen, setSidebarOpen] = useState(true);\n const [seoOpen, setSeoOpen] = useState(false);\n\n const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));\n\n const isNew = (originalSlug ?? initial.slug) === newPostSlug;\n const editSlug = originalSlug ?? initial.slug;\n const contentHtml = useMemo(() => blocksToHtml(blocks), [blocks]);\n const seoScore = useMemo(() => computeSeoScore(post, contentHtml).score, [post, contentHtml]);\n const activeBlock = blocks.find((b) => b.id === activeId);\n\n const updatePost = (patch: Partial<EditorDocument>) => setPost((p) => ({ ...p, ...patch }));\n\n const handleBlocksChange = (next: BlogBlock[]) => {\n setBlocksHistory((hist) => [...hist.slice(0, historyIndex + 1), next]);\n setHistoryIndex((i) => i + 1);\n setBlocks(next);\n };\n\n const updateActiveBlock = (patch: Partial<BlogBlock>) => {\n if (!activeId) return;\n handleBlocksChange(blocks.map((b) => (b.id === activeId ? { ...b, ...patch } : b)));\n };\n\n const addBlock = (type: BlogBlockType, afterIndex?: number) => {\n const newBlock = createBlock(type);\n const next = [...blocks];\n const at = afterIndex !== undefined && afterIndex >= 0 ? afterIndex + 1 : next.length;\n next.splice(at, 0, newBlock);\n handleBlocksChange(next);\n setActiveId(newBlock.id);\n };\n\n const handleDragStart = (event: DragStartEvent) => {\n const data = event.active.data.current as { source?: string; type?: BlogBlockType };\n if (data?.source === 'library' && data.type) setDraggingType(data.type);\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n setDraggingType(null);\n const { active, over } = event;\n if (!over) return;\n\n const data = active.data.current as { source?: string; type?: BlogBlockType };\n\n if (data?.source === 'library' && data.type) {\n const overId = String(over.id);\n if (overId === 'canvas-drop') {\n addBlock(data.type);\n return;\n }\n const idx = blocks.findIndex((b) => b.id === overId);\n addBlock(data.type, idx >= 0 ? idx : blocks.length - 1);\n return;\n }\n\n if (active.id !== over.id) {\n const oldIndex = blocks.findIndex((b) => b.id === active.id);\n const newIndex = blocks.findIndex((b) => b.id === over.id);\n if (oldIndex >= 0 && newIndex >= 0) {\n handleBlocksChange(arrayMove(blocks, oldIndex, newIndex));\n }\n }\n };\n\n const undo = () => {\n if (historyIndex <= 0) return;\n const idx = historyIndex - 1;\n setHistoryIndex(idx);\n setBlocks(blocksHistory[idx]);\n };\n\n const redo = () => {\n if (historyIndex >= blocksHistory.length - 1) return;\n const idx = historyIndex + 1;\n setHistoryIndex(idx);\n setBlocks(blocksHistory[idx]);\n };\n\n const resolvedTitle = useMemo(() => post.title.trim() || 'No title', [post.title]);\n\n const save = async (publish?: boolean) => {\n setSaving(true);\n setMessage('');\n try {\n const title = post.title.trim() || 'Untitled Post';\n let slug = post.slug.trim();\n if (isNew || slug === newPostSlug) slug = slugifyTitle(title);\n const payload: EditorDocument = {\n ...post,\n title,\n slug,\n content: contentHtml,\n status: publish ? 'published' : post.status,\n publishedAt: publish ? new Date().toISOString() : post.publishedAt,\n };\n\n const result = await onSave(payload, { publish, contentHtml });\n const newSlug = result?.slug ?? slug;\n\n setPost({ ...payload, slug: newSlug });\n setMessage(publish ? 'Published!' : 'Draft saved');\n\n if (onNavigate && (isNew || newSlug !== editSlug)) {\n onNavigate(newSlug);\n }\n } catch {\n setMessage('Failed to save');\n } finally {\n setSaving(false);\n }\n };\n\n const previewHref = previewUrl && post.slug !== newPostSlug ? previewUrl(post.slug) : undefined;\n\n return (\n <DndContext sensors={sensors} collisionDetection={closestCenter} onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\n <div className={`flex flex-col h-screen bg-[var(--be-bg)] ${className}`}>\n <header className=\"h-14 bg-[var(--be-surface)] border-b border-gray-200 flex items-center justify-between px-4 shrink-0 z-30\">\n <div className=\"flex items-center gap-2\">\n <a href={backHref} className=\"p-2 hover:bg-gray-100 rounded\" title=\"Back to posts\">\n <ArrowLeft size={18} className=\"text-gray-600\" />\n </a>\n <button type=\"button\" onClick={undo} disabled={historyIndex <= 0} className=\"p-2 hover:bg-gray-100 rounded disabled:opacity-30\" title=\"Undo\">\n <Undo2 size={18} className=\"text-gray-600\" />\n </button>\n <button type=\"button\" onClick={redo} disabled={historyIndex >= blocksHistory.length - 1} className=\"p-2 hover:bg-gray-100 rounded disabled:opacity-30\" title=\"Redo\">\n <Redo2 size={18} className=\"text-gray-600\" />\n </button>\n <span className=\"hidden md:inline text-sm text-gray-500 ml-2 max-w-[240px] truncate\">\n {resolvedTitle} — {post.status === 'published' ? 'Post' : 'Draft'}\n </span>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {message && <span className=\"text-xs be-text-primary hidden sm:inline\">{message}</span>}\n <button\n type=\"button\"\n onClick={() => {\n setSidebarOpen(true);\n setSeoOpen(true);\n }}\n className={`flex items-center gap-1.5 text-sm font-medium px-3 py-1.5 rounded-lg border transition-colors ${\n seoOpen\n ? 'be-border-primary be-bg-primary-muted be-text-primary ring-1 ring-[color-mix(in_srgb,var(--be-primary)_30%,transparent)]'\n : seoScore >= 70\n ? 'border-green-200 bg-green-50 text-green-700 hover:bg-green-100'\n : seoScore >= 40\n ? 'border-amber-200 bg-amber-50 text-amber-700 hover:bg-amber-100'\n : 'border-gray-200 bg-gray-50 text-gray-700 hover:bg-gray-100'\n }`}\n >\n SEO\n <span className=\"text-xs font-bold\">{seoScore}</span>\n </button>\n <button type=\"button\" onClick={() => save(false)} disabled={saving} className=\"text-sm text-gray-700 be-text-primary hover:opacity-80 px-3 py-1.5 disabled:opacity-50\">\n Save draft\n </button>\n {previewHref && post.status === 'published' && (\n <a href={previewHref} target=\"_blank\" rel=\"noopener noreferrer\" className=\"p-2 hover:bg-gray-100 rounded text-gray-600\" title=\"Preview\">\n <ExternalLink size={18} />\n </a>\n )}\n <button\n type=\"button\"\n onClick={() => {\n setSidebarOpen((v) => !v);\n if (sidebarOpen) setSeoOpen(false);\n }}\n className={`p-2 rounded transition-colors ${sidebarOpen ? 'bg-gray-100 be-text-primary' : 'hover:bg-gray-100 text-gray-600'}`}\n title={sidebarOpen ? 'Collapse sidebar' : 'Expand sidebar'}\n >\n {sidebarOpen ? <PanelRightClose size={18} /> : <PanelRightOpen size={18} />}\n </button>\n <button\n type=\"button\"\n onClick={() => save(true)}\n disabled={saving}\n className=\"be-btn-primary text-sm font-medium px-4 py-2 rounded disabled:opacity-50 flex items-center gap-2\"\n >\n {saving && <Loader2 size={14} className=\"animate-spin\" />}\n {post.status === 'published' ? 'Update' : 'Publish'}\n </button>\n </div>\n </header>\n\n <div className=\"flex flex-1 overflow-hidden\">\n <div className=\"flex-1 overflow-y-auto overflow-x-hidden bg-[var(--be-surface)]\">\n <div className=\"max-w-[840px] mx-auto pt-12 pb-24 px-6\">\n <input\n type=\"text\"\n value={post.title}\n onChange={(e) => updatePost({ title: e.target.value })}\n placeholder=\"Add title\"\n className=\"w-full text-4xl md:text-5xl font-serif text-gray-900 placeholder:text-gray-300 border-none outline-none bg-transparent mb-8\"\n />\n </div>\n <BlockCanvas blocks={blocks} onChange={handleBlocksChange} activeId={activeId} onActiveIdChange={setActiveId} />\n </div>\n\n {sidebarOpen && (\n <PostSidebar\n post={post}\n contentHtml={contentHtml}\n onChange={updatePost}\n onAddBlock={(type) => addBlock(type)}\n activeBlock={activeBlock}\n onUpdateBlock={updateActiveBlock}\n seoMode={seoOpen}\n onCloseSeo={() => setSeoOpen(false)}\n />\n )}\n </div>\n </div>\n\n <DragOverlay>\n {draggingType ? (\n <div className=\"px-4 py-2 bg-white be-border-primary border rounded-lg shadow-lg text-sm font-medium text-gray-800\">\n {BLOCK_LABELS[draggingType]}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n );\n}\n\nexport default function BlogEditor({\n theme,\n onUploadImage,\n uploadFile,\n siteName,\n baseUrl,\n ...props\n}: BlogEditorProps) {\n const resolved = resolveTheme(theme);\n const imageUpload = onUploadImage ?? uploadFile;\n return (\n <EditorProvider onUploadImage={imageUpload} theme={resolved} siteName={siteName} baseUrl={baseUrl}>\n <div className=\"blog-editor-root\" style={themeToCssVars(resolved)}>\n <BlogEditorInner {...props} />\n </div>\n </EditorProvider>\n );\n}\n","'use client';\n\nimport { createContext, useContext } from 'react';\nimport { defaultTheme, resolveTheme } from './theme';\nimport type { EditorTheme, OnUploadImage } from './types';\n\nexport interface EditorContextValue {\n onUploadImage?: OnUploadImage;\n theme: EditorTheme;\n siteName: string;\n baseUrl: string;\n}\n\nconst EditorContext = createContext<EditorContextValue>({\n theme: defaultTheme,\n siteName: 'Site',\n baseUrl: 'https://example.com',\n});\n\nexport function EditorProvider({\n children,\n onUploadImage,\n theme,\n siteName = 'Site',\n baseUrl = 'https://example.com',\n}: {\n children: React.ReactNode;\n onUploadImage?: OnUploadImage;\n theme?: Partial<EditorTheme>;\n siteName?: string;\n baseUrl?: string;\n}) {\n return (\n <EditorContext.Provider\n value={{\n onUploadImage,\n theme: resolveTheme(theme),\n siteName,\n baseUrl,\n }}\n >\n {children}\n </EditorContext.Provider>\n );\n}\n\nexport function useEditorContext() {\n return useContext(EditorContext);\n}\n","import type { CSSProperties } from 'react';\nimport type { EditorTheme } from './types';\n\nexport const defaultTheme: EditorTheme = {\n primary: '#04644A',\n primaryHover: '#035239',\n primaryMuted: '#f0fdf4',\n primaryBorder: '#bbf7d0',\n background: '#f0f0f1',\n surface: '#ffffff',\n successText: '#04644A',\n};\n\nexport function resolveTheme(partial?: Partial<EditorTheme>): EditorTheme {\n return { ...defaultTheme, ...partial };\n}\n\nexport function themeToCssVars(theme: EditorTheme): CSSProperties {\n return {\n '--be-primary': theme.primary,\n '--be-primary-hover': theme.primaryHover,\n '--be-primary-muted': theme.primaryMuted,\n '--be-primary-border': theme.primaryBorder,\n '--be-bg': theme.background,\n '--be-surface': theme.surface,\n '--be-success-text': theme.successText,\n } as CSSProperties;\n}\n","export type BlogBlockType =\n | 'paragraph'\n | 'heading'\n | 'list'\n | 'quote'\n | 'image'\n | 'embed'\n | 'html'\n | 'code'\n | 'separator';\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\nexport interface BlogBlock {\n id: string;\n type: BlogBlockType;\n html?: string;\n level?: HeadingLevel;\n items?: string[];\n ordered?: boolean;\n src?: string;\n alt?: string;\n caption?: string;\n imageWidth?: number;\n imageHeight?: number;\n imageWidthPercent?: number;\n embedUrl?: string;\n embedHeight?: number;\n rawHtml?: string;\n}\n\nexport const BLOCK_LABELS: Record<BlogBlockType, string> = {\n paragraph: 'Paragraph',\n heading: 'Heading',\n list: 'List',\n quote: 'Quote',\n image: 'Image',\n embed: 'Embed / iframe',\n html: 'Custom HTML',\n code: 'Code',\n separator: 'Separator',\n};\n\nexport const HEADING_LABELS: Record<HeadingLevel, string> = {\n 1: 'Heading 1',\n 2: 'Heading 2',\n 3: 'Heading 3',\n 4: 'Heading 4',\n 5: 'Heading 5',\n 6: 'Heading 6',\n};\n\nexport function createBlock(type: BlogBlockType): BlogBlock {\n const id = `blk-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n switch (type) {\n case 'heading':\n return { id, type, level: 2, html: '' };\n case 'list':\n return { id, type, items: [''], ordered: false };\n case 'image':\n return { id, type, src: '', alt: '', caption: '' };\n case 'embed':\n return { id, type, embedUrl: '', embedHeight: 400 };\n case 'html':\n return { id, type, rawHtml: '<div></div>' };\n case 'code':\n return { id, type, html: '' };\n case 'separator':\n return { id, type };\n case 'quote':\n return { id, type, html: '' };\n default:\n return { id, type: 'paragraph', html: '' };\n }\n}\n\nfunction parseHeading(el: HTMLElement): BlogBlock {\n const level = parseInt(el.tagName[1], 10) as HeadingLevel;\n return { ...createBlock('heading'), level: level >= 1 && level <= 6 ? level : 2, html: el.innerHTML };\n}\n\nfunction parseList(el: HTMLElement): BlogBlock {\n const ordered = el.tagName.toLowerCase() === 'ol';\n const items = Array.from(el.querySelectorAll(':scope > li')).map((li) => li.innerHTML);\n return { ...createBlock('list'), ordered, items: items.length ? items : [''] };\n}\n\nfunction parseImageDimensions(img: HTMLImageElement): Pick<BlogBlock, 'imageWidth' | 'imageHeight' | 'imageWidthPercent'> {\n let imageWidth: number | undefined;\n let imageHeight: number | undefined;\n let imageWidthPercent: number | undefined;\n\n const style = img.getAttribute('style') || '';\n const wStyle = style.match(/width:\\s*(\\d+(?:\\.\\d+)?)(px|%)/i);\n if (wStyle) {\n if (wStyle[2] === '%') imageWidthPercent = parseFloat(wStyle[1]);\n else imageWidth = parseFloat(wStyle[1]);\n }\n const hStyle = style.match(/height:\\s*(\\d+(?:\\.\\d+)?)px/i);\n if (hStyle) imageHeight = parseFloat(hStyle[1]);\n\n const wAttr = img.getAttribute('width');\n const hAttr = img.getAttribute('height');\n if (!imageWidth && !imageWidthPercent && wAttr) {\n const w = parseInt(wAttr, 10);\n if (Number.isFinite(w)) imageWidth = w;\n }\n if (!imageHeight && hAttr) {\n const h = parseInt(hAttr, 10);\n if (Number.isFinite(h)) imageHeight = h;\n }\n\n return { imageWidth, imageHeight, imageWidthPercent };\n}\n\nfunction imageStyleAttr(block: BlogBlock): string {\n const parts: string[] = [];\n if (block.imageWidthPercent) parts.push(`width: ${block.imageWidthPercent}%`);\n else if (block.imageWidth) parts.push(`width: ${block.imageWidth}px`);\n if (block.imageHeight) parts.push(`height: ${block.imageHeight}px`);\n else if (block.imageWidthPercent || block.imageWidth) parts.push('height: auto');\n return parts.length ? ` style=\"${parts.join('; ')}\"` : '';\n}\n\nfunction parseEmbed(el: HTMLElement): BlogBlock | null {\n const iframe = el.tagName.toLowerCase() === 'iframe' ? el : el.querySelector('iframe');\n if (!iframe) return null;\n const height = parseInt(iframe.getAttribute('height') || '400', 10);\n return {\n ...createBlock('embed'),\n embedUrl: iframe.getAttribute('src') || '',\n embedHeight: Number.isFinite(height) ? height : 400,\n rawHtml: el.tagName.toLowerCase() === 'iframe' ? undefined : el.outerHTML,\n };\n}\n\nexport function htmlToBlocks(html: string): BlogBlock[] {\n const trimmed = html?.trim();\n if (!trimmed) return [createBlock('paragraph')];\n if (typeof DOMParser === 'undefined') return [createBlock('paragraph')];\n\n const doc = new DOMParser().parseFromString(trimmed, 'text/html');\n const blocks: BlogBlock[] = [];\n\n for (const node of Array.from(doc.body.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent?.trim();\n if (text) blocks.push({ ...createBlock('paragraph'), html: text });\n continue;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) continue;\n const el = node as HTMLElement;\n const tag = el.tagName.toLowerCase();\n\n if (tag === 'p') {\n if (!el.textContent?.trim() && !el.querySelector('img')) continue;\n blocks.push({ ...createBlock('paragraph'), html: el.innerHTML });\n } else if (/^h[1-6]$/.test(tag)) {\n blocks.push(parseHeading(el));\n } else if (tag === 'ul' || tag === 'ol') {\n blocks.push(parseList(el));\n } else if (tag === 'blockquote') {\n blocks.push({ ...createBlock('quote'), html: el.innerHTML });\n } else if (tag === 'hr') {\n blocks.push(createBlock('separator'));\n } else if (tag === 'pre') {\n const code = el.querySelector('code');\n blocks.push({ ...createBlock('code'), html: code?.textContent || el.textContent || '' });\n } else if (tag === 'figure') {\n const img = el.querySelector('img');\n const caption = el.querySelector('figcaption')?.textContent || '';\n if (img) {\n blocks.push({\n ...createBlock('image'),\n src: img.getAttribute('src') || '',\n alt: img.getAttribute('alt') || '',\n caption,\n ...parseImageDimensions(img),\n });\n } else {\n blocks.push({ ...createBlock('html'), rawHtml: el.outerHTML });\n }\n } else if (tag === 'img') {\n blocks.push({\n ...createBlock('image'),\n src: el.getAttribute('src') || '',\n alt: el.getAttribute('alt') || '',\n ...parseImageDimensions(el as HTMLImageElement),\n });\n } else if (tag === 'iframe' || el.querySelector('iframe')) {\n const embed = parseEmbed(el);\n blocks.push(embed || { ...createBlock('html'), rawHtml: el.outerHTML });\n } else if (tag === 'div' && el.classList.contains('embed-responsive')) {\n const embed = parseEmbed(el);\n blocks.push(embed || { ...createBlock('html'), rawHtml: el.outerHTML });\n } else {\n blocks.push({ ...createBlock('html'), rawHtml: el.outerHTML });\n }\n }\n\n return blocks.length ? blocks : [createBlock('paragraph')];\n}\n\nexport function blocksToHtml(blocks: BlogBlock[]): string {\n return blocks\n .map((block) => {\n switch (block.type) {\n case 'paragraph':\n return `<p>${block.html || ''}</p>`;\n case 'heading': {\n const level = block.level && block.level >= 1 && block.level <= 6 ? block.level : 2;\n return `<h${level}>${block.html || ''}</h${level}>`;\n }\n case 'list': {\n const tag = block.ordered ? 'ol' : 'ul';\n const items = (block.items || []).filter((item) => item.trim());\n if (!items.length) return '';\n return `<${tag}>${items.map((item) => `<li>${item}</li>`).join('')}</${tag}>`;\n }\n case 'quote':\n return `<blockquote>${block.html || ''}</blockquote>`;\n case 'image':\n if (!block.src) return '';\n return `<figure><img src=\"${block.src}\" alt=\"${block.alt || ''}\"${imageStyleAttr(block)} />${\n block.caption ? `<figcaption>${block.caption}</figcaption>` : ''\n }</figure>`;\n case 'embed':\n if (block.rawHtml?.trim()) return block.rawHtml;\n if (!block.embedUrl) return '';\n return `<div class=\"embed-responsive\"><iframe src=\"${block.embedUrl}\" width=\"100%\" height=\"${block.embedHeight || 400}\" frameborder=\"0\" allowfullscreen loading=\"lazy\" title=\"Embedded content\"></iframe></div>`;\n case 'html':\n return block.rawHtml || '';\n case 'code':\n return `<pre><code>${(block.html || '').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</code></pre>`;\n case 'separator':\n return '<hr />';\n default:\n return '';\n }\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nexport function slugifyTitle(title: string): string {\n return (\n title\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '') || 'new-post'\n );\n}\n\nexport const HEADING_CLASSES: Record<HeadingLevel, string> = {\n 1: 'text-4xl md:text-5xl',\n 2: 'text-3xl md:text-4xl',\n 3: 'text-2xl md:text-3xl',\n 4: 'text-xl md:text-2xl',\n 5: 'text-lg md:text-xl',\n 6: 'text-base md:text-lg',\n};\n","import type { EditorDocument } from '../types';\n\nexport interface SeoCheck {\n id: string;\n label: string;\n passed: boolean;\n}\n\nexport interface SeoScore {\n score: number;\n checks: SeoCheck[];\n}\n\nexport function getSeoPreview(post: EditorDocument, siteName = 'Site', baseUrl = 'https://example.com') {\n const title = post.metaTitle?.trim() || post.title.trim() || 'Untitled Post';\n const description =\n post.metaDescription?.trim() || post.excerpt.trim() || 'Add a meta description for better search visibility.';\n const slug = post.slug && post.slug !== 'new-post' ? post.slug : 'your-post-slug';\n const url = `${baseUrl.replace(/\\/$/, '')}/blogs/${slug}`;\n\n return { title, description, url, siteName };\n}\n\nexport function computeSeoScore(post: EditorDocument, contentHtml = ''): SeoScore {\n const plain = contentHtml.replace(/<[^>]+>/g, ' ').replace(/\\s+/g, ' ').trim();\n const wordCount = plain ? plain.split(' ').filter(Boolean).length : 0;\n const title = post.metaTitle?.trim() || post.title.trim();\n const description = post.metaDescription?.trim() || post.excerpt.trim();\n const keyword = post.focusKeyword?.trim().toLowerCase() || '';\n const slug = post.slug?.toLowerCase() || '';\n\n const checks: SeoCheck[] = [\n { id: 'title', label: 'SEO title is set', passed: title.length > 0 },\n {\n id: 'title-length',\n label: 'SEO title length is good (30–60 chars)',\n passed: title.length >= 30 && title.length <= 60,\n },\n { id: 'description', label: 'Meta description is set', passed: description.length > 0 },\n {\n id: 'description-length',\n label: 'Meta description length is good (120–160 chars)',\n passed: description.length >= 120 && description.length <= 160,\n },\n {\n id: 'keyword-title',\n label: 'Focus keyword appears in SEO title',\n passed: !keyword || title.toLowerCase().includes(keyword),\n },\n {\n id: 'keyword-slug',\n label: 'Focus keyword appears in URL slug',\n passed: !keyword || slug.includes(keyword.replace(/\\s+/g, '-')),\n },\n {\n id: 'keyword-content',\n label: 'Focus keyword appears in content',\n passed: !keyword || plain.toLowerCase().includes(keyword),\n },\n { id: 'featured', label: 'Featured image is set', passed: Boolean(post.featuredImage) },\n {\n id: 'content-length',\n label: 'Content has enough words (300+)',\n passed: wordCount >= 300,\n },\n { id: 'tags', label: 'At least one tag added', passed: post.tags.length > 0 },\n ];\n\n const passed = checks.filter((c) => c.passed).length;\n const score = Math.round((passed / checks.length) * 100);\n\n return { score, checks };\n}\n\nexport function titleLengthColor(len: number) {\n if (len === 0) return 'bg-gray-200';\n if (len < 30 || len > 60) return 'bg-amber-400';\n return 'bg-green-500';\n}\n\nexport function descriptionLengthColor(len: number) {\n if (len === 0) return 'bg-gray-200';\n if (len < 120 || len > 160) return 'bg-amber-400';\n return 'bg-green-500';\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useDroppable, type DraggableAttributes } from '@dnd-kit/core';\nimport { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport { Plus } from 'lucide-react';\nimport type { BlogBlock, BlogBlockType, HeadingLevel } from '../lib/blog-blocks';\nimport { BLOCK_LABELS, createBlock, HEADING_CLASSES } from '../lib/blog-blocks';\nimport {\n cleanPastedHtml,\n inlineHtmlFromBlocks,\n insertHtmlAtCursor,\n isMultiBlockPaste,\n pastedHtmlToBlocks,\n} from '../lib/paste-html';\nimport { useEditorContext } from '../context';\nimport BlockToolbar from './BlockToolbar';\n\nconst SLASH_OPTIONS: BlogBlockType[] = [\n 'paragraph',\n 'heading',\n 'list',\n 'quote',\n 'image',\n 'embed',\n 'html',\n 'code',\n 'separator',\n];\n\nfunction ListItem({\n html,\n onChange,\n onFocus,\n onEnter,\n onBackspaceEmpty,\n shouldFocus,\n onPaste,\n}: {\n html: string;\n onChange: (html: string) => void;\n onFocus: () => void;\n onEnter: () => void;\n onBackspaceEmpty: () => void;\n shouldFocus?: boolean;\n onPaste?: (e: React.ClipboardEvent<HTMLDivElement>) => void;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (ref.current && document.activeElement !== ref.current) {\n ref.current.innerHTML = html || '';\n }\n }, [html]);\n\n useEffect(() => {\n if (!shouldFocus || !ref.current) return;\n ref.current.focus();\n const range = document.createRange();\n range.selectNodeContents(ref.current);\n range.collapse(false);\n const sel = window.getSelection();\n sel?.removeAllRanges();\n sel?.addRange(range);\n }, [shouldFocus]);\n\n const isEmpty = (el: HTMLDivElement) => !(el.textContent || '').trim();\n\n return (\n <li>\n <div\n ref={ref}\n contentEditable\n suppressContentEditableWarning\n className=\"outline-none text-[16px] text-gray-800 min-h-[24px]\"\n onFocus={onFocus}\n onBlur={(e) => onChange(e.currentTarget.innerHTML)}\n onPaste={onPaste}\n onKeyDown={(e) => {\n const el = e.currentTarget as HTMLDivElement;\n if (e.key === 'Enter') {\n e.preventDefault();\n onChange(el.innerHTML);\n onEnter();\n return;\n }\n if (e.key === 'Backspace' && isEmpty(el)) {\n e.preventDefault();\n onChange('');\n onBackspaceEmpty();\n }\n }}\n />\n </li>\n );\n}\n\nfunction RichBlock({\n block,\n placeholder,\n className,\n onChange,\n onKeyDown,\n onFocus,\n onPaste,\n}: {\n block: BlogBlock;\n placeholder: string;\n className: string;\n onChange: (html: string) => void;\n onKeyDown: (e: React.KeyboardEvent) => void;\n onFocus: () => void;\n onPaste?: (e: React.ClipboardEvent<HTMLDivElement>) => void;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (ref.current && document.activeElement !== ref.current) {\n ref.current.innerHTML = block.html || '';\n }\n }, [block.id, block.html]);\n\n return (\n <div\n ref={ref}\n contentEditable\n suppressContentEditableWarning\n data-placeholder={placeholder}\n className={`outline-none empty:before:content-[attr(data-placeholder)] empty:before:text-gray-400 ${className}`}\n onFocus={onFocus}\n onBlur={(e) => onChange(e.currentTarget.innerHTML)}\n onPaste={onPaste}\n onKeyDown={onKeyDown}\n />\n );\n}\n\nfunction HtmlBlockEditor({\n blockId,\n rawHtml,\n onChange,\n onFocus,\n}: {\n blockId: string;\n rawHtml: string;\n onChange: (html: string) => void;\n onFocus: () => void;\n}) {\n const previewRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (previewRef.current && document.activeElement !== previewRef.current) {\n previewRef.current.innerHTML = rawHtml || '';\n }\n }, [blockId, rawHtml]);\n\n return (\n <div className=\"space-y-3\">\n <p className=\"text-xs text-gray-500\">Click content to edit directly — tables, divs, headings, links</p>\n <div\n ref={previewRef}\n contentEditable\n suppressContentEditableWarning\n onFocus={onFocus}\n onBlur={(e) => onChange(e.currentTarget.innerHTML)}\n onPaste={(e) => {\n const html = e.clipboardData.getData('text/html');\n const text = e.clipboardData.getData('text/plain');\n if (!html && !text) return;\n e.preventDefault();\n const raw = html || text.replace(/\\n/g, '<br>');\n const cleaned = html ? cleanPastedHtml(raw) : raw.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n const pastedBlocks = pastedHtmlToBlocks(cleaned);\n const inline = isMultiBlockPaste(pastedBlocks)\n ? pastedBlocks\n .map((b) => {\n if (b.type === 'paragraph' || b.type === 'heading' || b.type === 'quote') return `<p>${b.html || ''}</p>`;\n if (b.type === 'list') return `<ul>${(b.items || []).map((i) => `<li>${i}</li>`).join('')}</ul>`;\n return inlineHtmlFromBlocks([b]);\n })\n .join('')\n : inlineHtmlFromBlocks(pastedBlocks) || cleaned;\n insertHtmlAtCursor(inline);\n requestAnimationFrame(() => {\n if (previewRef.current) onChange(previewRef.current.innerHTML);\n });\n }}\n className=\"blog-content min-h-[160px] outline-none border border-gray-200 rounded-lg p-4 bg-white focus:ring-1 focus:ring-blue-400 empty:before:content-[attr(data-placeholder)] empty:before:text-gray-400\"\n data-placeholder=\"Click here to type or paste content...\"\n />\n <details className=\"text-sm\">\n <summary className=\"cursor-pointer text-gray-500 hover:text-gray-700 text-xs\">View / edit HTML source</summary>\n <textarea\n value={rawHtml || ''}\n onChange={(e) => onChange(e.target.value)}\n rows={6}\n className=\"mt-2 w-full border border-gray-200 rounded px-3 py-2 text-xs font-mono bg-gray-50\"\n spellCheck={false}\n />\n </details>\n </div>\n );\n}\n\nconst IMAGE_SIZE_PRESETS = [\n { label: 'Auto', value: 'auto' as const },\n { label: '25%', value: 25 },\n { label: '50%', value: 50 },\n { label: '75%', value: 75 },\n { label: '100%', value: 100 },\n];\n\nfunction imageDisplayStyle(block: BlogBlock): React.CSSProperties {\n if (block.imageWidthPercent) return { width: `${block.imageWidthPercent}%`, height: block.imageHeight ? `${block.imageHeight}px` : 'auto' };\n if (block.imageWidth) return { width: `${block.imageWidth}px`, height: block.imageHeight ? `${block.imageHeight}px` : 'auto' };\n if (block.imageHeight) return { height: `${block.imageHeight}px`, width: 'auto' };\n return { maxWidth: '100%', height: 'auto' };\n}\n\nfunction ImageBlockEditor({\n block,\n isActive,\n onChange,\n onFocus,\n onUpload,\n canUpload,\n}: {\n block: BlogBlock;\n isActive: boolean;\n onChange: (patch: Partial<BlogBlock>) => void;\n onFocus: () => void;\n onUpload: (file: File) => void;\n canUpload: boolean;\n}) {\n const imgRef = useRef<HTMLImageElement>(null);\n const resizeRef = useRef<{ startX: number; startY: number; startW: number; startH: number; aspect: number } | null>(null);\n\n const activePreset =\n block.imageWidthPercent === 25\n ? 25\n : block.imageWidthPercent === 50\n ? 50\n : block.imageWidthPercent === 75\n ? 75\n : block.imageWidthPercent === 100\n ? 100\n : !block.imageWidth && !block.imageHeight && !block.imageWidthPercent\n ? 'auto'\n : null;\n\n const startResize = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const img = imgRef.current;\n if (!img) return;\n const rect = img.getBoundingClientRect();\n resizeRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startW: rect.width,\n startH: rect.height,\n aspect: rect.width / Math.max(rect.height, 1),\n };\n\n const onMove = (ev: MouseEvent) => {\n const data = resizeRef.current;\n if (!data) return;\n const dx = ev.clientX - data.startX;\n const dy = ev.clientY - data.startY;\n const newW = Math.max(80, Math.round(data.startW + dx));\n const newH = Math.max(60, Math.round(data.startH + dy));\n if (ev.shiftKey) {\n onChange({ imageWidth: newW, imageHeight: newH, imageWidthPercent: undefined });\n } else {\n onChange({ imageWidth: newW, imageHeight: undefined, imageWidthPercent: undefined });\n }\n };\n\n const onUp = () => {\n resizeRef.current = null;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n };\n\n return (\n <div className=\"space-y-3\" onFocus={onFocus}>\n {block.src ? (\n <div\n className={`relative inline-block max-w-full ${isActive ? 'ring-2 ring-blue-400 ring-offset-2 rounded-lg' : ''}`}\n onClick={onFocus}\n >\n <img\n ref={imgRef}\n src={block.src}\n alt={block.alt || ''}\n style={imageDisplayStyle(block)}\n className=\"rounded-lg border border-gray-200 block\"\n draggable={false}\n />\n {isActive && (\n <button\n type=\"button\"\n aria-label=\"Resize image\"\n onMouseDown={startResize}\n className=\"absolute bottom-1 right-1 w-3.5 h-3.5 bg-white border-2 border-blue-500 rounded-sm cursor-se-resize shadow-sm hover:bg-blue-50\"\n />\n )}\n </div>\n ) : canUpload ? (\n <label className=\"flex flex-col items-center justify-center h-48 border-2 border-dashed border-gray-200 rounded-lg cursor-pointer be-hover-border-primary hover:bg-gray-50 transition-colors\">\n <span className=\"text-gray-500 text-sm\">Click to upload image</span>\n <input\n type=\"file\"\n accept=\"image/*\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (file) onUpload(file);\n }}\n />\n </label>\n ) : (\n <div className=\"flex flex-col items-center justify-center h-32 border-2 border-dashed border-gray-200 rounded-lg bg-gray-50 px-4 text-center\">\n <span className=\"text-gray-500 text-sm\">Paste an image URL below</span>\n <span className=\"text-gray-400 text-xs mt-1\">Pass <code className=\"bg-gray-100 px-1 rounded\">onUploadImage</code> to enable file upload</span>\n </div>\n )}\n\n {block.src && isActive && (\n <div className=\"flex flex-wrap gap-1.5 items-center\">\n <span className=\"text-xs text-gray-500 mr-1\">Size:</span>\n {IMAGE_SIZE_PRESETS.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n onClick={() => {\n if (preset.value === 'auto') {\n onChange({ imageWidth: undefined, imageHeight: undefined, imageWidthPercent: undefined });\n } else {\n onChange({ imageWidthPercent: preset.value, imageWidth: undefined, imageHeight: undefined });\n }\n }}\n className={`px-2 py-0.5 text-xs rounded border ${\n activePreset === preset.value\n ? 'bg-blue-600 text-white border-blue-600'\n : 'bg-white text-gray-600 border-gray-200 hover:border-gray-400'\n }`}\n >\n {preset.label}\n </button>\n ))}\n </div>\n )}\n\n {block.src && isActive && (\n <div className=\"flex flex-wrap gap-3 items-center text-sm\">\n <label className=\"flex items-center gap-1.5 text-gray-600\">\n <span className=\"text-xs shrink-0\">Width</span>\n <input\n type=\"number\"\n min={40}\n max={2000}\n placeholder=\"auto\"\n value={block.imageWidthPercent ? '' : block.imageWidth ?? ''}\n disabled={Boolean(block.imageWidthPercent)}\n onChange={(e) => {\n const v = e.target.value;\n if (!v) onChange({ imageWidth: undefined });\n else onChange({ imageWidth: parseInt(v, 10) || undefined, imageWidthPercent: undefined });\n }}\n className=\"w-20 border border-gray-200 rounded px-2 py-1 text-xs disabled:bg-gray-50\"\n />\n <span className=\"text-xs text-gray-400\">px</span>\n </label>\n <label className=\"flex items-center gap-1.5 text-gray-600\">\n <span className=\"text-xs shrink-0\">Height</span>\n <input\n type=\"number\"\n min={40}\n max={2000}\n placeholder=\"auto\"\n value={block.imageHeight ?? ''}\n onChange={(e) => {\n const v = e.target.value;\n if (!v) onChange({ imageHeight: undefined });\n else onChange({ imageHeight: parseInt(v, 10) || undefined, imageWidthPercent: undefined });\n }}\n className=\"w-20 border border-gray-200 rounded px-2 py-1 text-xs\"\n />\n <span className=\"text-xs text-gray-400\">px</span>\n </label>\n <span className=\"text-[10px] text-gray-400\">Drag corner to resize · Shift+drag for custom height</span>\n </div>\n )}\n\n <input\n type=\"url\"\n value={block.src || ''}\n onChange={(e) => onChange({ src: e.target.value })}\n onFocus={onFocus}\n placeholder=\"Image URL (https://...)\"\n className=\"w-full border border-gray-200 rounded px-3 py-2 text-sm\"\n />\n <input\n type=\"text\"\n value={block.alt || ''}\n onChange={(e) => onChange({ alt: e.target.value })}\n onFocus={onFocus}\n placeholder=\"Alt text (optional)\"\n className=\"w-full border border-gray-200 rounded px-3 py-2 text-sm\"\n />\n <input\n type=\"text\"\n value={block.caption || ''}\n onChange={(e) => onChange({ caption: e.target.value })}\n onFocus={onFocus}\n placeholder=\"Caption (optional)\"\n className=\"w-full border border-gray-200 rounded px-3 py-2 text-sm\"\n />\n </div>\n );\n}\n\nfunction SortableBlockShell({\n id,\n children,\n}: {\n id: string;\n children: (api: {\n setNodeRef: (node: HTMLElement | null) => void;\n style: React.CSSProperties;\n dragHandleProps: {\n listeners?: object;\n attributes?: DraggableAttributes;\n };\n }) => React.ReactNode;\n}) {\n const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });\n const style: React.CSSProperties = {\n transform: CSS.Transform.toString(transform),\n transition,\n };\n return <>{children({ setNodeRef, style, dragHandleProps: { listeners, attributes } })}</>;\n}\n\nexport default function BlockCanvas({\n blocks,\n onChange,\n activeId,\n onActiveIdChange,\n}: {\n blocks: BlogBlock[];\n onChange: (blocks: BlogBlock[]) => void;\n activeId: string | null;\n onActiveIdChange: (id: string | null) => void;\n}) {\n const { onUploadImage } = useEditorContext();\n const canUpload = Boolean(onUploadImage);\n const setActiveId = onActiveIdChange;\n const [slashMenu, setSlashMenu] = useState<{\n blockId: string;\n index: number;\n top: number;\n left: number;\n } | null>(null);\n const [focusListItem, setFocusListItem] = useState<{ blockId: string; index: number } | null>(null);\n\n const updateBlock = (id: string, patch: Partial<BlogBlock>) => {\n onChange(blocks.map((b) => (b.id === id ? { ...b, ...patch } : b)));\n };\n\n const handleListBackspace = (block: BlogBlock, liIndex: number) => {\n const items = [...(block.items || [''])];\n if (items.length > 1) {\n items.splice(liIndex, 1);\n updateBlock(block.id, { items });\n setFocusListItem({ blockId: block.id, index: Math.max(0, liIndex - 1) });\n return;\n }\n const html = items[0] || '';\n onChange(\n blocks.map((b, i) =>\n b.id === block.id ? { ...createBlock('paragraph'), id: b.id, html } : b,\n ),\n );\n setActiveId(block.id);\n };\n\n useEffect(() => {\n if (!focusListItem) return;\n const t = window.setTimeout(() => setFocusListItem(null), 50);\n return () => window.clearTimeout(t);\n }, [focusListItem, blocks]);\n\n const plainText = (b: BlogBlock) => (b.html || b.rawHtml || '').replace(/<[^>]+>/g, '');\n\n const transformBlock = (id: string, type: BlogBlockType) => {\n onChange(\n blocks.map((b) => {\n if (b.id !== id) return b;\n const text = plainText(b);\n const next = createBlock(type);\n if (type === 'heading') return { ...next, html: b.html || text, level: b.level || 2 };\n if (type === 'list') return { ...next, items: [b.html || text || ''], ordered: b.ordered };\n if (type === 'quote' || type === 'paragraph') return { ...next, html: b.html || text };\n if (type === 'code') return { ...next, html: text };\n if (type === 'embed') return { ...next, embedUrl: b.embedUrl || b.src || '' };\n if (type === 'image') return { ...next, src: b.src || '', alt: b.alt || '' };\n if (type === 'html') return { ...next, rawHtml: b.rawHtml || b.html || '<div></div>' };\n return next;\n }),\n );\n };\n\n const insertAfter = (index: number, type: BlogBlockType = 'paragraph') => {\n const next = [...blocks];\n next.splice(index + 1, 0, createBlock(type));\n onChange(next);\n setActiveId(next[index + 1].id);\n };\n\n const removeBlock = (id: string) => {\n if (blocks.length <= 1) {\n onChange([createBlock('paragraph')]);\n return;\n }\n onChange(blocks.filter((b) => b.id !== id));\n };\n\n const moveBlock = (index: number, dir: -1 | 1) => {\n const target = index + dir;\n if (target < 0 || target >= blocks.length) return;\n const next = [...blocks];\n [next[index], next[target]] = [next[target], next[index]];\n onChange(next);\n };\n\n const applyFormat = useCallback((cmd: string, value?: string) => {\n if (cmd === 'link') {\n const url = window.prompt('Enter URL');\n if (url) document.execCommand('createLink', false, url);\n return;\n }\n if (cmd === 'formatBlock' && value) {\n document.execCommand('formatBlock', false, value);\n return;\n }\n document.execCommand(cmd, false);\n }, []);\n\n const handleTextKeyDown = (e: React.KeyboardEvent, block: BlogBlock, index: number) => {\n const el = e.currentTarget as HTMLDivElement;\n const text = el.textContent || '';\n\n if (e.key === '/' && text === '') {\n e.preventDefault();\n const rect = el.getBoundingClientRect();\n setSlashMenu({\n blockId: block.id,\n index,\n top: rect.bottom + 6,\n left: rect.left,\n });\n return;\n }\n\n if (e.key === 'Enter' && !e.shiftKey && block.type === 'paragraph') {\n e.preventDefault();\n updateBlock(block.id, { html: el.innerHTML });\n insertAfter(index);\n }\n\n if (e.key === 'Backspace' && text === '' && blocks.length > 1) {\n e.preventDefault();\n removeBlock(block.id);\n const prev = blocks[index - 1];\n if (prev) setActiveId(prev.id);\n }\n };\n\n const pickSlashOption = (type: BlogBlockType) => {\n if (!slashMenu) return;\n transformBlock(slashMenu.blockId, type);\n setSlashMenu(null);\n };\n\n const handleBlockPaste = (\n e: React.ClipboardEvent<HTMLDivElement>,\n block: BlogBlock,\n blockIndex: number,\n onChangeHtml: (html: string) => void,\n ) => {\n const html = e.clipboardData.getData('text/html');\n const text = e.clipboardData.getData('text/plain');\n if (!html && !text) return;\n\n e.preventDefault();\n\n const escaped = text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\\n\\n/g, '</p><p>')\n .replace(/\\n/g, '<br>');\n const raw = html || (text ? `<p>${escaped}</p>` : '');\n const pastedBlocks = pastedHtmlToBlocks(raw);\n if (!pastedBlocks.length) return;\n\n const el = e.currentTarget;\n const isEmpty = !(el.textContent || '').trim();\n\n if (isEmpty && pastedBlocks.length === 1 && pastedBlocks[0].type !== 'paragraph') {\n updateBlock(block.id, { ...pastedBlocks[0], id: block.id });\n return;\n }\n\n if (isMultiBlockPaste(pastedBlocks)) {\n const next = [...blocks];\n const toInsert = pastedBlocks.map((b, i) => (i === 0 && isEmpty ? { ...b, id: block.id } : b));\n if (isEmpty) next.splice(blockIndex, 1, ...toInsert);\n else next.splice(blockIndex + 1, 0, ...pastedBlocks);\n onChange(next);\n setActiveId(toInsert[toInsert.length - 1].id);\n return;\n }\n\n const inline = inlineHtmlFromBlocks(pastedBlocks);\n if (!inline) return;\n\n insertHtmlAtCursor(inline);\n requestAnimationFrame(() => onChangeHtml(el.innerHTML));\n };\n\n const handleListPaste = (e: React.ClipboardEvent<HTMLDivElement>, onChangeHtml: (html: string) => void) => {\n const html = e.clipboardData.getData('text/html');\n const text = e.clipboardData.getData('text/plain');\n if (!html && !text) return;\n\n e.preventDefault();\n const escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n const raw = html || (text ? `<span>${escaped}</span>` : '');\n const pastedBlocks = pastedHtmlToBlocks(raw);\n const inline = inlineHtmlFromBlocks(pastedBlocks) || escaped;\n insertHtmlAtCursor(inline);\n requestAnimationFrame(() => onChangeHtml(e.currentTarget.innerHTML));\n };\n\n const uploadImage = async (blockId: string, file: File) => {\n if (!onUploadImage) return;\n const url = await onUploadImage(file);\n if (url) updateBlock(blockId, { src: url });\n };\n\n const { setNodeRef: setDropRef, isOver } = useDroppable({ id: 'canvas-drop' });\n\n return (\n <div\n ref={setDropRef}\n className={`max-w-[840px] mx-auto px-6 py-8 min-h-[240px] rounded-xl transition-colors ${\n isOver ? 'bg-green-50/50 ring-2 ring-dashed ring-[color-mix(in_srgb,var(--be-primary)_25%,transparent)]' : ''\n }`}\n >\n <SortableContext items={blocks.map((b) => b.id)} strategy={verticalListSortingStrategy}>\n {blocks.map((block, index) => {\n const isActive = activeId === block.id;\n const level = (block.level || 2) as HeadingLevel;\n const ListWrapper = block.ordered ? 'ol' : 'ul';\n\n return (\n <SortableBlockShell key={block.id} id={block.id}>\n {({ setNodeRef, style, dragHandleProps }) => (\n <div\n ref={setNodeRef}\n style={style}\n className={`relative group mb-4 pt-2 ${isActive ? 'ring-1 ring-blue-400 rounded-sm z-10' : ''}`}\n onClick={() => setActiveId(block.id)}\n >\n {isActive && (\n <BlockToolbar\n block={block}\n dragHandleProps={dragHandleProps}\n onTransform={(type) => transformBlock(block.id, type)}\n onSetHeadingLevel={(lvl) => updateBlock(block.id, { level: lvl })}\n onToggleOrderedList={() => updateBlock(block.id, { ordered: !block.ordered })}\n onMoveUp={() => moveBlock(index, -1)}\n onMoveDown={() => moveBlock(index, 1)}\n onDelete={() => removeBlock(block.id)}\n onFormat={applyFormat}\n canMoveUp={index > 0}\n canMoveDown={index < blocks.length - 1}\n />\n )}\n\n <div className=\"flex gap-2 items-start\">\n <button\n type=\"button\"\n onClick={() => insertAfter(index)}\n className=\"opacity-0 group-hover:opacity-100 mt-2 p-1 rounded bg-[#1e1e1e] text-white shrink-0 transition-opacity\"\n title=\"Add block\"\n >\n <Plus size={16} />\n </button>\n\n <div className=\"flex-1 min-w-0 py-1\">\n {block.type === 'paragraph' && (\n <RichBlock\n block={block}\n placeholder=\"Type / to choose a block — paste from Word to keep bold, headings & lists\"\n className=\"text-[16px] leading-relaxed text-gray-800 min-h-[28px]\"\n onChange={(html) => updateBlock(block.id, { html })}\n onFocus={() => setActiveId(block.id)}\n onKeyDown={(e) => handleTextKeyDown(e, block, index)}\n onPaste={(e) => handleBlockPaste(e, block, index, (html) => updateBlock(block.id, { html }))}\n />\n )}\n\n {block.type === 'heading' && (\n <RichBlock\n block={block}\n placeholder={BLOCK_LABELS.heading}\n className={`font-bold text-gray-900 min-h-[36px] ${HEADING_CLASSES[level]}`}\n onChange={(html) => updateBlock(block.id, { html })}\n onFocus={() => setActiveId(block.id)}\n onKeyDown={(e) => handleTextKeyDown(e, block, index)}\n onPaste={(e) => handleBlockPaste(e, block, index, (html) => updateBlock(block.id, { html }))}\n />\n )}\n\n {block.type === 'quote' && (\n <div className=\"border-l-4 border-gray-300 pl-4\">\n <RichBlock\n block={block}\n placeholder=\"Quote\"\n className=\"text-lg italic text-gray-600 min-h-[28px]\"\n onChange={(html) => updateBlock(block.id, { html })}\n onFocus={() => setActiveId(block.id)}\n onKeyDown={(e) => handleTextKeyDown(e, block, index)}\n onPaste={(e) => handleBlockPaste(e, block, index, (html) => updateBlock(block.id, { html }))}\n />\n </div>\n )}\n\n {block.type === 'list' && (\n <ListWrapper className={`${block.ordered ? 'list-decimal' : 'list-disc'} pl-6 space-y-2`}>\n {(block.items || ['']).map((item, liIndex) => (\n <ListItem\n key={`${block.id}-${liIndex}`}\n html={item}\n shouldFocus={focusListItem?.blockId === block.id && focusListItem.index === liIndex}\n onChange={(html) => {\n const items = [...(block.items || [''])];\n items[liIndex] = html;\n updateBlock(block.id, { items });\n }}\n onFocus={() => setActiveId(block.id)}\n onEnter={() => {\n const items = [...(block.items || [''])];\n items.splice(liIndex + 1, 0, '');\n updateBlock(block.id, { items });\n setFocusListItem({ blockId: block.id, index: liIndex + 1 });\n }}\n onBackspaceEmpty={() => handleListBackspace(block, liIndex)}\n onPaste={(e) =>\n handleListPaste(e, (html) => {\n const items = [...(block.items || [''])];\n items[liIndex] = html;\n updateBlock(block.id, { items });\n })\n }\n />\n ))}\n <li>\n <button\n type=\"button\"\n onClick={() => updateBlock(block.id, { items: [...(block.items || []), ''] })}\n className=\"text-sm text-blue-600 hover:underline\"\n >\n + Add list item\n </button>\n </li>\n </ListWrapper>\n )}\n\n {block.type === 'image' && (\n <ImageBlockEditor\n block={block}\n isActive={activeId === block.id}\n onChange={(patch) => updateBlock(block.id, patch)}\n onFocus={() => setActiveId(block.id)}\n onUpload={(file) => uploadImage(block.id, file)}\n canUpload={canUpload}\n />\n )}\n\n {block.type === 'embed' && (\n <div className=\"space-y-3\">\n <input\n type=\"url\"\n value={block.embedUrl || ''}\n onChange={(e) => updateBlock(block.id, { embedUrl: e.target.value })}\n placeholder=\"Embed URL (YouTube, Vimeo, Google Maps, etc.)\"\n className=\"w-full border border-gray-200 rounded px-3 py-2 text-sm\"\n />\n <div className=\"flex gap-3 items-center\">\n <label className=\"text-sm text-gray-500 shrink-0\">Height</label>\n <input\n type=\"number\"\n min={200}\n max={1200}\n value={block.embedHeight || 400}\n onChange={(e) => updateBlock(block.id, { embedHeight: parseInt(e.target.value, 10) || 400 })}\n className=\"w-24 border border-gray-200 rounded px-3 py-2 text-sm\"\n />\n <span className=\"text-xs text-gray-400\">px</span>\n </div>\n {block.embedUrl ? (\n <div className=\"rounded-lg overflow-hidden border border-gray-200 bg-gray-50\">\n <iframe\n src={block.embedUrl}\n width=\"100%\"\n height={block.embedHeight || 400}\n className=\"border-0\"\n title=\"Embed preview\"\n loading=\"lazy\"\n />\n </div>\n ) : (\n <p className=\"text-xs text-gray-400\">Paste iframe src URL — YouTube, Vimeo, Loom, maps, etc.</p>\n )}\n <details className=\"text-sm\">\n <summary className=\"cursor-pointer text-gray-500 hover:text-gray-700\">Advanced: raw iframe HTML</summary>\n <textarea\n value={block.rawHtml || ''}\n onChange={(e) => updateBlock(block.id, { rawHtml: e.target.value })}\n rows={4}\n placeholder='<iframe src=\"...\" width=\"100%\" height=\"400\"></iframe>'\n className=\"mt-2 w-full border border-gray-200 rounded px-3 py-2 text-xs font-mono\"\n />\n </details>\n </div>\n )}\n\n {block.type === 'html' && (\n <HtmlBlockEditor\n blockId={block.id}\n rawHtml={block.rawHtml || ''}\n onChange={(html) => updateBlock(block.id, { rawHtml: html })}\n onFocus={() => setActiveId(block.id)}\n />\n )}\n\n {block.type === 'code' && (\n <textarea\n value={block.html || ''}\n onChange={(e) => updateBlock(block.id, { html: e.target.value })}\n rows={6}\n placeholder=\"Paste code here...\"\n className=\"w-full border border-gray-200 rounded-lg px-4 py-3 text-sm font-mono bg-[#1e1e1e] text-green-400\"\n spellCheck={false}\n onFocus={() => setActiveId(block.id)}\n />\n )}\n\n {block.type === 'separator' && (\n <hr className=\"border-gray-300 my-4\" />\n )}\n </div>\n </div>\n\n {slashMenu?.blockId === block.id &&\n typeof document !== 'undefined' &&\n createPortal(\n <>\n <div className=\"fixed inset-0 z-[200]\" onClick={() => setSlashMenu(null)} />\n <div\n className=\"fixed z-[201] bg-white border border-gray-200 rounded-lg shadow-2xl py-2 w-[220px] max-h-[280px] overflow-y-auto\"\n style={{ top: slashMenu.top, left: slashMenu.left }}\n >\n <p className=\"px-3 pb-1 text-[11px] font-semibold text-gray-400 uppercase\">Blocks</p>\n {SLASH_OPTIONS.map((type) => (\n <button\n key={type}\n type=\"button\"\n onClick={() => pickSlashOption(type)}\n className=\"w-full text-left px-3 py-2 text-sm hover:bg-blue-50\"\n >\n {BLOCK_LABELS[type]}\n </button>\n ))}\n </div>\n </>,\n document.body,\n )}\n </div>\n )}\n </SortableBlockShell>\n );\n })}\n </SortableContext>\n {blocks.length === 0 && (\n <p className=\"text-center text-gray-400 text-sm py-12\">Drag blocks from the Block panel → or type / to add</p>\n )}\n </div>\n );\n}\n","import { htmlToBlocks, type BlogBlock } from './blog-blocks';\n\n/** Strip Word/Google Docs junk and keep semantic formatting. */\nexport function cleanPastedHtml(raw: string): string {\n if (!raw?.trim()) return '';\n\n let html = raw\n .replace(/<!--[\\s\\S]*?-->/g, '')\n .replace(/<\\?xml[\\s\\S]*?\\?>/gi, '')\n .replace(/<meta[\\s\\S]*?>/gi, '')\n .replace(/<link[\\s\\S]*?>/gi, '')\n .replace(/<o:p>\\s*<\\/o:p>/gi, '')\n .replace(/<\\/?o:[^>]*>/gi, '')\n .replace(/<\\/?w:[^>]*>/gi, '')\n .replace(/<\\/?m:[^>]*>/gi, '');\n\n if (typeof DOMParser === 'undefined') return html;\n\n const doc = new DOMParser().parseFromString(html, 'text/html');\n flattenSingleWrapper(doc.body);\n walkAndClean(doc.body);\n\n return doc.body.innerHTML.trim();\n}\n\nfunction flattenSingleWrapper(root: HTMLElement) {\n while (\n root.childNodes.length === 1 &&\n root.firstElementChild?.tagName === 'DIV' &&\n (root.firstElementChild as HTMLElement).childElementCount > 1\n ) {\n const div = root.firstElementChild as HTMLElement;\n while (div.firstChild) root.insertBefore(div.firstChild, div);\n root.removeChild(div);\n }\n}\n\nfunction wordParagraphHeadingTag(el: HTMLElement): string | null {\n const style = el.getAttribute('style') || '';\n const cls = el.getAttribute('class') || '';\n\n const outline = style.match(/mso-outline-level:\\s*(\\d)/i);\n if (outline) {\n const n = Math.min(6, Math.max(1, parseInt(outline[1], 10)));\n return `h${n}`;\n }\n\n if (/MsoTitle|Heading1/i.test(cls)) return 'h1';\n if (/Heading2/i.test(cls)) return 'h2';\n if (/Heading3/i.test(cls)) return 'h3';\n if (/Heading4/i.test(cls)) return 'h4';\n if (/Heading5/i.test(cls)) return 'h5';\n if (/Heading6/i.test(cls)) return 'h6';\n\n const fontSize = style.match(/font-size:\\s*([\\d.]+)pt/i);\n if (fontSize) {\n const pt = parseFloat(fontSize[1]);\n if (pt >= 22) return 'h1';\n if (pt >= 18) return 'h2';\n if (pt >= 15) return 'h3';\n if (pt >= 13) return 'h4';\n }\n\n const fw = style.match(/font-weight:\\s*(bold|[7-9]00)/i);\n if (fw && /Title/i.test(cls)) return 'h1';\n\n return null;\n}\n\nfunction wrapSemantic(el: HTMLElement, tag: string) {\n const wrapped = el.ownerDocument.createElement(tag);\n wrapped.innerHTML = el.innerHTML;\n el.replaceWith(wrapped);\n return wrapped;\n}\n\nconst KEEP_TAGS = new Set([\n 'p', 'br', 'strong', 'b', 'em', 'i', 'u', 's', 'strike', 'del', 'a',\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'sub', 'sup',\n 'img', 'figure', 'figcaption', 'table', 'thead', 'tbody', 'tr', 'th', 'td',\n 'hr', 'iframe', 'div', 'span',\n]);\n\nfunction walkAndClean(parent: HTMLElement) {\n const nodes = Array.from(parent.childNodes);\n\n for (const node of nodes) {\n if (node.nodeType === Node.TEXT_NODE) continue;\n if (node.nodeType !== Node.ELEMENT_NODE) {\n node.remove();\n continue;\n }\n\n const el = node as HTMLElement;\n let tag = el.tagName.toLowerCase();\n\n if (tag.includes(':')) {\n unwrap(el);\n continue;\n }\n\n if (tag === 'p') {\n const heading = wordParagraphHeadingTag(el);\n if (heading) {\n const h = el.ownerDocument.createElement(heading);\n h.innerHTML = el.innerHTML;\n el.replaceWith(h);\n walkAndClean(h);\n continue;\n }\n }\n\n if (tag === 'span') {\n const style = el.getAttribute('style') || '';\n let current: HTMLElement = el;\n if (/font-weight:\\s*(bold|[7-9]00)/i.test(style)) {\n current = wrapSemantic(current, 'strong') as HTMLElement;\n }\n if (/font-style:\\s*italic/i.test(style)) {\n current = wrapSemantic(current, 'em') as HTMLElement;\n }\n if (/text-decoration:\\s*underline/i.test(style) || /text-decoration-line:\\s*underline/i.test(style)) {\n current = wrapSemantic(current, 'u') as HTMLElement;\n }\n if (current === el) unwrap(el);\n else walkAndClean(current);\n continue;\n }\n\n if (tag === 'b') {\n const strong = el.ownerDocument.createElement('strong');\n strong.innerHTML = el.innerHTML;\n el.replaceWith(strong);\n walkAndClean(strong);\n continue;\n }\n\n if (tag === 'i') {\n const em = el.ownerDocument.createElement('em');\n em.innerHTML = el.innerHTML;\n el.replaceWith(em);\n walkAndClean(em);\n continue;\n }\n\n if (tag === 'div') {\n if (el.querySelector('table, ul, ol, h1, h2, h3, h4, h5, h6, img, iframe, blockquote, pre')) {\n unwrap(el);\n continue;\n }\n const p = el.ownerDocument.createElement('p');\n p.innerHTML = el.innerHTML;\n el.replaceWith(p);\n walkAndClean(p);\n continue;\n }\n\n el.removeAttribute('style');\n el.removeAttribute('class');\n el.removeAttribute('id');\n el.removeAttribute('lang');\n el.removeAttribute('align');\n el.removeAttribute('valign');\n\n if (tag === 'a') {\n const href = el.getAttribute('href');\n [...el.attributes].forEach((a) => {\n if (a.name !== 'href') el.removeAttribute(a.name);\n });\n if (!href || href.startsWith('file:')) {\n unwrap(el);\n continue;\n }\n }\n\n if (tag === 'img') {\n const src = el.getAttribute('src') || '';\n [...el.attributes].forEach((a) => el.removeAttribute(a.name));\n if (src && (src.startsWith('http') || src.startsWith('data:image') || src.startsWith('/'))) {\n el.setAttribute('src', src);\n if (!el.getAttribute('alt')) el.setAttribute('alt', '');\n } else {\n el.remove();\n continue;\n }\n }\n\n tag = el.tagName.toLowerCase();\n if (!KEEP_TAGS.has(tag)) {\n unwrap(el);\n continue;\n }\n\n walkAndClean(el);\n }\n}\n\nfunction unwrap(el: HTMLElement) {\n const parent = el.parentNode;\n if (!parent) return;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n parent.removeChild(el);\n}\n\nexport function insertHtmlAtCursor(html: string) {\n if (!html) return;\n document.execCommand('insertHTML', false, html);\n}\n\nexport function pastedHtmlToBlocks(raw: string): BlogBlock[] {\n const cleaned = cleanPastedHtml(raw);\n if (!cleaned) return [];\n return htmlToBlocks(cleaned);\n}\n\nexport function isMultiBlockPaste(blocks: BlogBlock[]): boolean {\n if (blocks.length > 1) return true;\n const b = blocks[0];\n if (!b) return false;\n return ['list', 'image', 'embed', 'html', 'separator', 'code'].includes(b.type);\n}\n\nexport function inlineHtmlFromBlocks(blocks: BlogBlock[]): string {\n if (!blocks.length) return '';\n const b = blocks[0];\n if (b.type === 'paragraph' || b.type === 'heading' || b.type === 'quote') return b.html || '';\n if (b.type === 'list') return (b.items || []).join('');\n return '';\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { DraggableAttributes } from '@dnd-kit/core';\nimport {\n ArrowDown,\n ArrowUp,\n Bold,\n ChevronDown,\n Code2,\n GripVertical,\n Heading,\n Image as ImageIcon,\n Italic,\n Link2,\n List,\n ListOrdered,\n Minus,\n Pilcrow,\n Quote,\n Trash2,\n Underline,\n Video,\n FileCode2,\n} from 'lucide-react';\nimport type { BlogBlock, BlogBlockType, HeadingLevel } from '../lib/blog-blocks';\nimport { BLOCK_LABELS, HEADING_LABELS } from '../lib/blog-blocks';\n\nconst TRANSFORM_OPTIONS: { type: BlogBlockType; icon: React.ReactNode; label?: string }[] = [\n { type: 'paragraph', icon: <Pilcrow size={16} /> },\n { type: 'heading', icon: <Heading size={16} /> },\n { type: 'list', icon: <List size={16} />, label: 'Bullet list' },\n { type: 'quote', icon: <Quote size={16} /> },\n { type: 'image', icon: <ImageIcon size={16} /> },\n { type: 'embed', icon: <Video size={16} /> },\n { type: 'html', icon: <FileCode2 size={16} /> },\n { type: 'code', icon: <Code2 size={16} /> },\n { type: 'separator', icon: <Minus size={16} /> },\n];\n\nfunction FloatingMenu({\n open,\n onClose,\n anchorRef,\n children,\n width = 200,\n}: {\n open: boolean;\n onClose: () => void;\n anchorRef: React.RefObject<HTMLElement | null>;\n children: React.ReactNode;\n width?: number;\n}) {\n const [pos, setPos] = useState({ top: 0, left: 0 });\n\n useEffect(() => {\n if (!open || !anchorRef.current) return;\n const rect = anchorRef.current.getBoundingClientRect();\n setPos({\n top: rect.bottom + 6,\n left: Math.min(rect.left, window.innerWidth - width - 12),\n });\n }, [open, anchorRef, width]);\n\n if (!open || typeof document === 'undefined') return null;\n\n return createPortal(\n <>\n <div className=\"fixed inset-0 z-[200]\" onClick={onClose} aria-hidden />\n <div\n className=\"fixed z-[201] bg-white text-gray-800 border border-gray-200 rounded-lg shadow-2xl py-2 max-h-[320px] overflow-y-auto\"\n style={{ top: pos.top, left: pos.left, width }}\n >\n {children}\n </div>\n </>,\n document.body,\n );\n}\n\nexport default function BlockToolbar({\n block,\n onTransform,\n onSetHeadingLevel,\n onToggleOrderedList,\n onMoveUp,\n onMoveDown,\n onDelete,\n onFormat,\n canMoveUp,\n canMoveDown,\n dragHandleProps,\n}: {\n block: BlogBlock;\n onTransform: (type: BlogBlockType) => void;\n onSetHeadingLevel: (level: HeadingLevel) => void;\n onToggleOrderedList: () => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onDelete: () => void;\n onFormat: (cmd: string, value?: string) => void;\n canMoveUp: boolean;\n canMoveDown: boolean;\n dragHandleProps?: {\n listeners?: object;\n attributes?: DraggableAttributes;\n };\n}) {\n const [showTransform, setShowTransform] = useState(false);\n const [showHeadings, setShowHeadings] = useState(false);\n const transformBtnRef = useRef<HTMLButtonElement>(null);\n const headingBtnRef = useRef<HTMLButtonElement>(null);\n\n const isTextBlock =\n block.type === 'paragraph' || block.type === 'heading' || block.type === 'quote' || block.type === 'code';\n\n const currentLabel = TRANSFORM_OPTIONS.find((o) => o.type === block.type);\n\n return (\n <>\n <div className=\"absolute -top-12 left-10 z-30 inline-flex w-max max-w-[min(100%,calc(100vw-3rem))] items-center gap-0.5 bg-[#1e1e1e] text-white rounded-md shadow-lg px-1 py-1 flex-wrap\">\n <button\n type=\"button\"\n className=\"p-1.5 hover:bg-white/10 rounded cursor-grab shrink-0\"\n title=\"Drag to reorder\"\n {...dragHandleProps?.attributes}\n {...dragHandleProps?.listeners}\n >\n <GripVertical size={16} />\n </button>\n\n <button\n ref={transformBtnRef}\n type=\"button\"\n onClick={() => {\n setShowHeadings(false);\n setShowTransform((v) => !v);\n }}\n className=\"flex items-center gap-1.5 px-2 py-1.5 hover:bg-white/10 rounded text-sm shrink-0\"\n >\n {currentLabel?.icon}\n <span className=\"hidden sm:inline text-xs\">{currentLabel?.label || BLOCK_LABELS[block.type]}</span>\n <ChevronDown size={14} />\n </button>\n\n {block.type === 'heading' && (\n <button\n ref={headingBtnRef}\n type=\"button\"\n onClick={() => {\n setShowTransform(false);\n setShowHeadings((v) => !v);\n }}\n className=\"flex items-center gap-1 px-2 py-1.5 hover:bg-white/10 rounded text-sm font-semibold shrink-0\"\n >\n H{block.level || 2}\n <ChevronDown size={14} />\n </button>\n )}\n\n {block.type === 'list' && (\n <button\n type=\"button\"\n onClick={onToggleOrderedList}\n className=\"p-1.5 hover:bg-white/10 rounded shrink-0\"\n title={block.ordered ? 'Bullet list' : 'Numbered list'}\n >\n {block.ordered ? <List size={15} /> : <ListOrdered size={15} />}\n </button>\n )}\n\n {isTextBlock && (\n <>\n <span className=\"w-px h-5 bg-white/20 mx-0.5 shrink-0\" />\n <button type=\"button\" onMouseDown={(e) => e.preventDefault()} onClick={() => onFormat('bold')} className=\"p-1.5 hover:bg-white/10 rounded shrink-0\" title=\"Bold\">\n <Bold size={15} />\n </button>\n <button type=\"button\" onMouseDown={(e) => e.preventDefault()} onClick={() => onFormat('italic')} className=\"p-1.5 hover:bg-white/10 rounded shrink-0\" title=\"Italic\">\n <Italic size={15} />\n </button>\n <button type=\"button\" onMouseDown={(e) => e.preventDefault()} onClick={() => onFormat('underline')} className=\"p-1.5 hover:bg-white/10 rounded shrink-0\" title=\"Underline\">\n <Underline size={15} />\n </button>\n <button type=\"button\" onMouseDown={(e) => e.preventDefault()} onClick={() => onFormat('link')} className=\"p-1.5 hover:bg-white/10 rounded shrink-0\" title=\"Link\">\n <Link2 size={15} />\n </button>\n </>\n )}\n\n <span className=\"w-px h-5 bg-white/20 mx-0.5 shrink-0\" />\n <button type=\"button\" disabled={!canMoveUp} onClick={onMoveUp} className=\"p-1.5 hover:bg-white/10 rounded disabled:opacity-30 shrink-0\" title=\"Move up\">\n <ArrowUp size={15} />\n </button>\n <button type=\"button\" disabled={!canMoveDown} onClick={onMoveDown} className=\"p-1.5 hover:bg-white/10 rounded disabled:opacity-30 shrink-0\" title=\"Move down\">\n <ArrowDown size={15} />\n </button>\n <button type=\"button\" onClick={onDelete} className=\"p-1.5 hover:bg-red-500/80 rounded shrink-0\" title=\"Delete block\">\n <Trash2 size={15} />\n </button>\n </div>\n\n <FloatingMenu open={showTransform} onClose={() => setShowTransform(false)} anchorRef={transformBtnRef} width={220}>\n <p className=\"px-3 pb-1 text-[11px] font-semibold text-gray-400 uppercase tracking-wide\">Transform to</p>\n {TRANSFORM_OPTIONS.map((opt) => (\n <button\n key={opt.type}\n type=\"button\"\n onClick={() => {\n onTransform(opt.type);\n setShowTransform(false);\n }}\n className={`w-full flex items-center gap-3 px-3 py-2 text-sm hover:bg-blue-50 ${\n block.type === opt.type ? 'bg-blue-50 text-blue-700' : ''\n }`}\n >\n {opt.icon}\n {opt.label || BLOCK_LABELS[opt.type]}\n </button>\n ))}\n </FloatingMenu>\n\n <FloatingMenu open={showHeadings} onClose={() => setShowHeadings(false)} anchorRef={headingBtnRef} width={160}>\n {([1, 2, 3, 4, 5, 6] as HeadingLevel[]).map((level) => (\n <button\n key={level}\n type=\"button\"\n onClick={() => {\n onSetHeadingLevel(level);\n setShowHeadings(false);\n }}\n className={`w-full text-left px-3 py-2 text-sm hover:bg-blue-50 ${\n block.level === level ? 'bg-blue-50 text-blue-700 font-semibold' : ''\n }`}\n >\n {HEADING_LABELS[level]}\n </button>\n ))}\n </FloatingMenu>\n </>\n );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { ChevronDown, ChevronUp, ImageIcon, Loader2 } from 'lucide-react';\nimport type { EditorDocument } from '../types';\nimport type { BlogBlock, BlogBlockType, HeadingLevel } from '../lib/blog-blocks';\nimport { BLOCK_LABELS, HEADING_LABELS } from '../lib/blog-blocks';\nimport BlockLibrary from './BlockLibrary';\nimport SeoPanel from './SeoPanel';\nimport { useEditorContext } from '../context';\n\nfunction Section({ title, children, defaultOpen = true }: { title: string; children: React.ReactNode; defaultOpen?: boolean }) {\n const [open, setOpen] = useState(defaultOpen);\n return (\n <div className=\"border-b border-gray-200\">\n <button type=\"button\" onClick={() => setOpen((v) => !v)} className=\"w-full flex items-center justify-between px-4 py-3 text-sm font-semibold text-gray-800 hover:bg-gray-50\">\n {title}\n {open ? <ChevronUp size={16} /> : <ChevronDown size={16} />}\n </button>\n {open && <div className=\"px-4 pb-4 space-y-3\">{children}</div>}\n </div>\n );\n}\n\nfunction BlockSettings({\n block,\n onChange,\n}: {\n block: BlogBlock;\n onChange: (patch: Partial<BlogBlock>) => void;\n}) {\n return (\n <div className=\"space-y-3 pt-2 border-t border-gray-100\">\n <p className=\"text-xs font-semibold text-gray-500 uppercase tracking-wide\">Selected block</p>\n <p className=\"text-sm font-medium text-gray-900\">{BLOCK_LABELS[block.type]}</p>\n\n {block.type === 'heading' && (\n <div className=\"space-y-1\">\n <label className=\"text-xs text-gray-500\">Heading level</label>\n <select\n value={block.level || 2}\n onChange={(e) => onChange({ level: parseInt(e.target.value, 10) as HeadingLevel })}\n className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-sm\"\n >\n {([1, 2, 3, 4, 5, 6] as HeadingLevel[]).map((lvl) => (\n <option key={lvl} value={lvl}>{HEADING_LABELS[lvl]}</option>\n ))}\n </select>\n </div>\n )}\n\n {block.type === 'list' && (\n <label className=\"flex items-center gap-2 text-sm text-gray-700\">\n <input type=\"checkbox\" checked={Boolean(block.ordered)} onChange={(e) => onChange({ ordered: e.target.checked })} />\n Numbered list\n </label>\n )}\n\n {block.type === 'image' && (\n <>\n <input\n type=\"url\"\n value={block.src || ''}\n onChange={(e) => onChange({ src: e.target.value })}\n placeholder=\"Image URL\"\n className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-xs\"\n />\n <input\n type=\"text\"\n value={block.alt || ''}\n onChange={(e) => onChange({ alt: e.target.value })}\n placeholder=\"Alt text\"\n className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-xs\"\n />\n <div className=\"grid grid-cols-2 gap-2\">\n <label className=\"text-xs text-gray-500\">\n Width (px)\n <input\n type=\"number\"\n min={40}\n placeholder=\"auto\"\n value={block.imageWidthPercent ? '' : block.imageWidth ?? ''}\n disabled={Boolean(block.imageWidthPercent)}\n onChange={(e) => {\n const v = e.target.value;\n if (!v) onChange({ imageWidth: undefined });\n else onChange({ imageWidth: parseInt(v, 10) || undefined, imageWidthPercent: undefined });\n }}\n className=\"mt-0.5 w-full border border-gray-200 rounded px-2 py-1 text-xs disabled:bg-gray-50\"\n />\n </label>\n <label className=\"text-xs text-gray-500\">\n Height (px)\n <input\n type=\"number\"\n min={40}\n placeholder=\"auto\"\n value={block.imageHeight ?? ''}\n onChange={(e) => {\n const v = e.target.value;\n if (!v) onChange({ imageHeight: undefined });\n else onChange({ imageHeight: parseInt(v, 10) || undefined, imageWidthPercent: undefined });\n }}\n className=\"mt-0.5 w-full border border-gray-200 rounded px-2 py-1 text-xs\"\n />\n </label>\n </div>\n <select\n value={block.imageWidthPercent ?? 'custom'}\n onChange={(e) => {\n const v = e.target.value;\n if (v === 'custom') return;\n if (v === 'auto') onChange({ imageWidth: undefined, imageHeight: undefined, imageWidthPercent: undefined });\n else onChange({ imageWidthPercent: parseInt(v, 10), imageWidth: undefined, imageHeight: undefined });\n }}\n className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-xs\"\n >\n <option value=\"auto\">Auto size</option>\n <option value=\"25\">25% width</option>\n <option value=\"50\">50% width</option>\n <option value=\"75\">75% width</option>\n <option value=\"100\">100% width</option>\n <option value=\"custom\">Custom (px)</option>\n </select>\n </>\n )}\n\n {block.type === 'embed' && (\n <input\n type=\"url\"\n value={block.embedUrl || ''}\n onChange={(e) => onChange({ embedUrl: e.target.value })}\n placeholder=\"Embed URL\"\n className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-xs\"\n />\n )}\n </div>\n );\n}\n\nexport default function PostSidebar({\n post,\n contentHtml,\n onChange,\n onAddBlock,\n activeBlock,\n onUpdateBlock,\n seoMode,\n onCloseSeo,\n}: {\n post: EditorDocument;\n contentHtml: string;\n onChange: (patch: Partial<EditorDocument>) => void;\n onAddBlock: (type: BlogBlockType) => void;\n activeBlock?: BlogBlock;\n onUpdateBlock?: (patch: Partial<BlogBlock>) => void;\n seoMode?: boolean;\n onCloseSeo?: () => void;\n}) {\n const { onUploadImage } = useEditorContext();\n const canUpload = Boolean(onUploadImage);\n const [tab, setTab] = useState<'post' | 'block'>('post');\n const [uploading, setUploading] = useState(false);\n const [tagInput, setTagInput] = useState(post.tags.join(', '));\n\n const uploadFeatured = async (file: File) => {\n if (!onUploadImage) return;\n setUploading(true);\n try {\n const url = await onUploadImage(file);\n if (url) onChange({ featuredImage: url });\n } finally {\n setUploading(false);\n }\n };\n\n return (\n <aside className=\"w-[300px] shrink-0 border-l border-gray-200 bg-white flex flex-col h-full overflow-hidden\">\n {seoMode ? (\n <SeoPanel post={post} contentHtml={contentHtml} onChange={onChange} onClose={onCloseSeo ?? (() => {})} />\n ) : (\n <>\n <div className=\"flex border-b border-gray-200 sticky top-0 bg-white z-10 shrink-0\">\n <button\n type=\"button\"\n onClick={() => setTab('post')}\n className={`flex-1 py-3 text-sm font-semibold ${tab === 'post' ? 'be-text-primary border-b-2 be-border-primary' : 'text-gray-500 hover:text-gray-700'}`}\n >\n Post\n </button>\n <button\n type=\"button\"\n onClick={() => setTab('block')}\n className={`flex-1 py-3 text-sm font-semibold ${tab === 'block' ? 'be-text-primary border-b-2 be-border-primary' : 'text-gray-500 hover:text-gray-700'}`}\n >\n Block\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto\">\n {tab === 'post' && (\n <>\n <Section title=\"Featured image\">\n {post.featuredImage ? (\n <div className=\"space-y-2\">\n <img src={post.featuredImage} alt=\"\" className=\"w-full rounded border border-gray-200 object-cover aspect-video\" />\n <button type=\"button\" onClick={() => onChange({ featuredImage: '' })} className=\"text-xs text-red-500 hover:underline\">Remove image</button>\n </div>\n ) : canUpload ? (\n <label className=\"flex flex-col items-center justify-center h-32 border border-gray-200 rounded cursor-pointer be-hover-border-primary hover:bg-gray-50\">\n {uploading ? <Loader2 size={20} className=\"animate-spin text-gray-400\" /> : <ImageIcon size={24} className=\"text-gray-400 mb-1\" />}\n <span className=\"text-xs text-gray-500\">Set featured image</span>\n <input type=\"file\" accept=\"image/*\" className=\"hidden\" onChange={(e) => e.target.files?.[0] && uploadFeatured(e.target.files[0])} disabled={uploading} />\n </label>\n ) : (\n <p className=\"text-xs text-gray-400 text-center py-4 border border-dashed border-gray-200 rounded\">\n Pass <code className=\"bg-gray-100 px-1 rounded\">onUploadImage</code> to enable uploads\n </p>\n )}\n </Section>\n\n <Section title=\"Excerpt\">\n <textarea\n value={post.excerpt}\n onChange={(e) => onChange({ excerpt: e.target.value })}\n rows={3}\n placeholder=\"Short summary for blog cards & SEO fallback\"\n className=\"w-full border border-gray-200 rounded px-3 py-2 text-sm resize-none focus:outline-none focus:ring-1 be-ring-primary\"\n />\n </Section>\n\n <Section title=\"Post settings\">\n <div className=\"space-y-3 text-sm\">\n <div>\n <label className=\"text-xs text-gray-500 block mb-1\">Status</label>\n <select value={post.status} onChange={(e) => onChange({ status: e.target.value as 'draft' | 'published' })} className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-sm\">\n <option value=\"draft\">Draft</option>\n <option value=\"published\">Published</option>\n </select>\n </div>\n <div>\n <label className=\"text-xs text-gray-500 block mb-1\">Publish date</label>\n <input type=\"datetime-local\" value={post.publishedAt.slice(0, 16)} onChange={(e) => onChange({ publishedAt: new Date(e.target.value).toISOString() })} className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-xs\" />\n </div>\n <div>\n <label className=\"text-xs text-gray-500 block mb-1\">Permalink / Slug</label>\n <input value={post.slug} onChange={(e) => onChange({ slug: e.target.value })} className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-xs\" />\n </div>\n <div>\n <label className=\"text-xs text-gray-500 block mb-1\">Author</label>\n <input value={post.author} onChange={(e) => onChange({ author: e.target.value })} className=\"w-full border border-gray-200 rounded px-2 py-1.5 text-sm\" placeholder=\"Author name\" />\n </div>\n </div>\n </Section>\n\n <Section title=\"Tags\" defaultOpen>\n <input\n value={tagInput}\n onChange={(e) => {\n setTagInput(e.target.value);\n onChange({ tags: e.target.value.split(',').map((t) => t.trim()).filter(Boolean) });\n }}\n placeholder=\"ai, startup, product\"\n className=\"w-full border border-gray-200 rounded px-3 py-2 text-sm focus:outline-none focus:ring-1 be-ring-primary\"\n />\n {post.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 pt-1\">\n {post.tags.map((tag) => (\n <span key={tag} className=\"text-xs bg-gray-100 text-gray-700 px-2 py-0.5 rounded-full\">{tag}</span>\n ))}\n </div>\n )}\n <p className=\"text-xs text-gray-400\">Separate with commas.</p>\n </Section>\n </>\n )}\n\n {tab === 'block' && (\n <div className=\"p-4 space-y-4\">\n <BlockLibrary onAddBlock={onAddBlock} />\n {activeBlock && onUpdateBlock && <BlockSettings block={activeBlock} onChange={onUpdateBlock} />}\n {!activeBlock && (\n <p className=\"text-xs text-gray-400 border-t border-gray-100 pt-3\">Click a block in the editor to see its settings here.</p>\n )}\n </div>\n )}\n </div>\n </>\n )}\n </aside>\n );\n}\n","'use client';\n\nimport { useDraggable } from '@dnd-kit/core';\nimport {\n Code2,\n FileCode2,\n Heading,\n Image as ImageIcon,\n List,\n Minus,\n Pilcrow,\n Quote,\n Video,\n} from 'lucide-react';\nimport type { BlogBlockType } from '../lib/blog-blocks';\nimport { BLOCK_LABELS } from '../lib/blog-blocks';\n\nexport const BLOCK_LIBRARY: { type: BlogBlockType; icon: React.ReactNode; desc: string }[] = [\n { type: 'paragraph', icon: <Pilcrow size={18} />, desc: 'Start with plain text' },\n { type: 'heading', icon: <Heading size={18} />, desc: 'H1–H6 section title' },\n { type: 'list', icon: <List size={18} />, desc: 'Bullet or numbered list' },\n { type: 'quote', icon: <Quote size={18} />, desc: 'Highlighted quote' },\n { type: 'image', icon: <ImageIcon size={18} />, desc: 'Upload or URL image' },\n { type: 'embed', icon: <Video size={18} />, desc: 'YouTube, iframe embed' },\n { type: 'html', icon: <FileCode2 size={18} />, desc: 'Custom HTML block' },\n { type: 'code', icon: <Code2 size={18} />, desc: 'Code snippet' },\n { type: 'separator', icon: <Minus size={18} />, desc: 'Horizontal divider line' },\n];\n\nfunction DraggableBlockItem({\n type,\n icon,\n label,\n desc,\n onClick,\n}: {\n type: BlogBlockType;\n icon: React.ReactNode;\n label: string;\n desc: string;\n onClick: () => void;\n}) {\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({\n id: `library-${type}`,\n data: { source: 'library', type },\n });\n\n return (\n <button\n ref={setNodeRef}\n type=\"button\"\n onClick={onClick}\n className={`w-full flex items-start gap-3 p-3 rounded-lg border border-gray-200 bg-white be-hover-border-primary hover:bg-green-50/40 text-left transition-colors cursor-grab active:cursor-grabbing ${\n isDragging ? 'opacity-40' : ''\n }`}\n {...listeners}\n {...attributes}\n >\n <span className=\"mt-0.5 text-gray-600 shrink-0\">{icon}</span>\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium text-gray-900\">{label}</span>\n <span className=\"block text-[11px] text-gray-500 mt-0.5 leading-snug\">{desc}</span>\n </span>\n </button>\n );\n}\n\nexport default function BlockLibrary({ onAddBlock }: { onAddBlock: (type: BlogBlockType) => void }) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-xs text-gray-500 px-1\">Drag into editor or click to add at the end.</p>\n <div className=\"space-y-2\">\n {BLOCK_LIBRARY.map((item) => (\n <DraggableBlockItem\n key={item.type}\n type={item.type}\n icon={item.icon}\n label={BLOCK_LABELS[item.type]}\n desc={item.desc}\n onClick={() => onAddBlock(item.type)}\n />\n ))}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { Check, X } from 'lucide-react';\nimport type { EditorDocument } from '../types';\nimport {\n computeSeoScore,\n descriptionLengthColor,\n getSeoPreview,\n titleLengthColor,\n} from '../lib/blog-seo';\nimport { useEditorContext } from '../context';\n\nexport default function SeoPanel({\n post,\n contentHtml,\n onChange,\n onClose,\n}: {\n post: EditorDocument;\n contentHtml: string;\n onChange: (patch: Partial<EditorDocument>) => void;\n onClose: () => void;\n}) {\n const { siteName, baseUrl } = useEditorContext();\n const seo = computeSeoScore(post, contentHtml);\n const preview = getSeoPreview(post, siteName, baseUrl);\n const titleLen = (post.metaTitle || post.title).length;\n const descLen = (post.metaDescription || post.excerpt).length;\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"sticky top-0 bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between z-10 shrink-0\">\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-gray-900\">SEO Settings</h2>\n <p className=\"text-[11px] text-gray-500 truncate\">Search preview & meta</p>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <span\n className={`text-xs font-bold px-2 py-0.5 rounded-full ${\n seo.score >= 70 ? 'bg-green-100 text-green-700' : seo.score >= 40 ? 'bg-amber-100 text-amber-700' : 'bg-red-100 text-red-700'\n }`}\n >\n {seo.score}/100\n </span>\n <button type=\"button\" onClick={onClose} className=\"p-1.5 hover:bg-gray-100 rounded-lg text-gray-500\" aria-label=\"Close SEO panel\">\n <X size={18} />\n </button>\n </div>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n <div>\n <p className=\"text-[11px] font-semibold text-gray-500 uppercase tracking-wide mb-2\">Google Preview</p>\n <div className=\"rounded-lg border border-gray-200 p-3 bg-gray-50 space-y-1\">\n <p className=\"text-[#1a0dab] text-sm font-medium leading-snug line-clamp-2\">{preview.title}</p>\n <p className=\"text-[#006621] text-xs truncate\">{preview.url}</p>\n <p className=\"text-gray-600 text-xs leading-relaxed line-clamp-4\">{preview.description}</p>\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-gray-700\">SEO Title</label>\n <input\n value={post.metaTitle || ''}\n onChange={(e) => onChange({ metaTitle: e.target.value })}\n placeholder={post.title || 'Defaults to post title'}\n className=\"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 be-ring-primary\"\n />\n <div className=\"h-1.5 rounded-full bg-gray-100 overflow-hidden\">\n <div className={`h-full transition-all ${titleLengthColor(titleLen)}`} style={{ width: `${Math.min(100, (titleLen / 60) * 100)}%` }} />\n </div>\n <p className=\"text-[10px] text-gray-400\">{titleLen} / 60 chars</p>\n </div>\n\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-gray-700\">Meta Description</label>\n <textarea\n value={post.metaDescription || ''}\n onChange={(e) => onChange({ metaDescription: e.target.value })}\n placeholder={post.excerpt || 'Defaults to excerpt'}\n rows={4}\n className=\"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm resize-none focus:outline-none focus:ring-1 be-ring-primary\"\n />\n <div className=\"h-1.5 rounded-full bg-gray-100 overflow-hidden\">\n <div className={`h-full transition-all ${descriptionLengthColor(descLen)}`} style={{ width: `${Math.min(100, (descLen / 160) * 100)}%` }} />\n </div>\n <p className=\"text-[10px] text-gray-400\">{descLen} / 160 chars</p>\n </div>\n\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-gray-700\">Focus Keyword</label>\n <input\n value={post.focusKeyword || ''}\n onChange={(e) => onChange({ focusKeyword: e.target.value })}\n placeholder=\"e.g. AI machine learning\"\n className=\"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 be-ring-primary\"\n />\n </div>\n\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium text-gray-700\">Permalink / Slug</label>\n <input\n value={post.slug}\n onChange={(e) => onChange({ slug: e.target.value })}\n className=\"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 be-ring-primary\"\n />\n </div>\n\n <div className=\"border-t border-gray-100 pt-3\">\n <p className=\"text-xs font-semibold text-gray-700 mb-2\">Basic SEO Checklist</p>\n <div className=\"space-y-2\">\n {seo.checks.map((check) => (\n <div key={check.id} className=\"flex items-start gap-2 text-xs\">\n {check.passed ? (\n <Check size={14} className=\"text-green-600 shrink-0 mt-0.5\" />\n ) : (\n <X size={14} className=\"text-red-400 shrink-0 mt-0.5\" />\n )}\n <span className={check.passed ? 'text-gray-700' : 'text-gray-500'}>{check.label}</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_lucide_react","import_core","import_sortable","import_react","import_react_dom","import_lucide_react","import_react","import_jsx_runtime","ImageIcon","import_jsx_runtime","import_react","import_lucide_react","import_core","import_lucide_react","import_jsx_runtime","ImageIcon","import_lucide_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
@@ -0,0 +1,143 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { CSSProperties } from 'react';
3
+
4
+ interface EditorDocument {
5
+ id: string;
6
+ slug: string;
7
+ title: string;
8
+ excerpt: string;
9
+ content: string;
10
+ featuredImage: string;
11
+ author: string;
12
+ publishedAt: string;
13
+ tags: string[];
14
+ status: 'draft' | 'published';
15
+ metaTitle?: string;
16
+ metaDescription?: string;
17
+ focusKeyword?: string;
18
+ }
19
+ type OnUploadImage = (file: File) => Promise<string>;
20
+ interface EditorTheme {
21
+ primary: string;
22
+ primaryHover: string;
23
+ primaryMuted: string;
24
+ primaryBorder: string;
25
+ background: string;
26
+ surface: string;
27
+ successText: string;
28
+ }
29
+ interface BlogEditorProps {
30
+ initial: EditorDocument;
31
+ originalSlug?: string;
32
+ /** Called when user saves or publishes. Return optional slug if it changed. */
33
+ onSave: (document: EditorDocument, options: {
34
+ publish?: boolean;
35
+ contentHtml: string;
36
+ }) => Promise<{
37
+ slug?: string;
38
+ } | void>;
39
+ /** Fired after a successful save (e.g. for client-side navigation). */
40
+ onNavigate?: (path: string) => void;
41
+ backHref?: string;
42
+ previewUrl?: (slug: string) => string;
43
+ /**
44
+ * Handle image uploads (featured image + image blocks).
45
+ * You receive the `File` — upload anywhere (S3, Cloudinary, your API) and return the public URL string.
46
+ *
47
+ * @example
48
+ * onUploadImage={async (file) => {
49
+ * const form = new FormData();
50
+ * form.append('file', file);
51
+ * const res = await fetch('/api/upload', { method: 'POST', body: form });
52
+ * const { url } = await res.json();
53
+ * return url;
54
+ * }}
55
+ */
56
+ onUploadImage?: OnUploadImage;
57
+ /** @deprecated Use `onUploadImage` instead */
58
+ uploadFile?: OnUploadImage;
59
+ siteName?: string;
60
+ baseUrl?: string;
61
+ theme?: Partial<EditorTheme>;
62
+ newPostSlug?: string;
63
+ className?: string;
64
+ }
65
+ type SaveResult = {
66
+ slug?: string;
67
+ } | void;
68
+
69
+ declare function BlogEditor({ theme, onUploadImage, uploadFile, siteName, baseUrl, ...props }: BlogEditorProps): react_jsx_runtime.JSX.Element;
70
+
71
+ interface EditorContextValue {
72
+ onUploadImage?: OnUploadImage;
73
+ theme: EditorTheme;
74
+ siteName: string;
75
+ baseUrl: string;
76
+ }
77
+ declare function EditorProvider({ children, onUploadImage, theme, siteName, baseUrl, }: {
78
+ children: React.ReactNode;
79
+ onUploadImage?: OnUploadImage;
80
+ theme?: Partial<EditorTheme>;
81
+ siteName?: string;
82
+ baseUrl?: string;
83
+ }): react_jsx_runtime.JSX.Element;
84
+ declare function useEditorContext(): EditorContextValue;
85
+
86
+ declare const defaultTheme: EditorTheme;
87
+ declare function resolveTheme(partial?: Partial<EditorTheme>): EditorTheme;
88
+ declare function themeToCssVars(theme: EditorTheme): CSSProperties;
89
+
90
+ type BlogBlockType = 'paragraph' | 'heading' | 'list' | 'quote' | 'image' | 'embed' | 'html' | 'code' | 'separator';
91
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
92
+ interface BlogBlock {
93
+ id: string;
94
+ type: BlogBlockType;
95
+ html?: string;
96
+ level?: HeadingLevel;
97
+ items?: string[];
98
+ ordered?: boolean;
99
+ src?: string;
100
+ alt?: string;
101
+ caption?: string;
102
+ imageWidth?: number;
103
+ imageHeight?: number;
104
+ imageWidthPercent?: number;
105
+ embedUrl?: string;
106
+ embedHeight?: number;
107
+ rawHtml?: string;
108
+ }
109
+ declare const BLOCK_LABELS: Record<BlogBlockType, string>;
110
+ declare const HEADING_LABELS: Record<HeadingLevel, string>;
111
+ declare function createBlock(type: BlogBlockType): BlogBlock;
112
+ declare function htmlToBlocks(html: string): BlogBlock[];
113
+ declare function blocksToHtml(blocks: BlogBlock[]): string;
114
+ declare function slugifyTitle(title: string): string;
115
+ declare const HEADING_CLASSES: Record<HeadingLevel, string>;
116
+
117
+ /** Strip Word/Google Docs junk and keep semantic formatting. */
118
+ declare function cleanPastedHtml(raw: string): string;
119
+ declare function insertHtmlAtCursor(html: string): void;
120
+ declare function pastedHtmlToBlocks(raw: string): BlogBlock[];
121
+ declare function isMultiBlockPaste(blocks: BlogBlock[]): boolean;
122
+ declare function inlineHtmlFromBlocks(blocks: BlogBlock[]): string;
123
+
124
+ interface SeoCheck {
125
+ id: string;
126
+ label: string;
127
+ passed: boolean;
128
+ }
129
+ interface SeoScore {
130
+ score: number;
131
+ checks: SeoCheck[];
132
+ }
133
+ declare function getSeoPreview(post: EditorDocument, siteName?: string, baseUrl?: string): {
134
+ title: string;
135
+ description: string;
136
+ url: string;
137
+ siteName: string;
138
+ };
139
+ declare function computeSeoScore(post: EditorDocument, contentHtml?: string): SeoScore;
140
+ declare function titleLengthColor(len: number): "bg-gray-200" | "bg-amber-400" | "bg-green-500";
141
+ declare function descriptionLengthColor(len: number): "bg-gray-200" | "bg-amber-400" | "bg-green-500";
142
+
143
+ export { BLOCK_LABELS, type BlogEditorProps as BlockEditorProps, type BlogBlock, type BlogBlockType, BlogEditor, type BlogEditorProps, type EditorDocument, EditorProvider, type EditorTheme, HEADING_CLASSES, HEADING_LABELS, type HeadingLevel, type OnUploadImage, type SaveResult, type SeoCheck, type SeoScore, blocksToHtml, cleanPastedHtml, computeSeoScore, createBlock, defaultTheme, descriptionLengthColor, getSeoPreview, htmlToBlocks, inlineHtmlFromBlocks, insertHtmlAtCursor, isMultiBlockPaste, pastedHtmlToBlocks, resolveTheme, slugifyTitle, themeToCssVars, titleLengthColor, useEditorContext };