infinity serch

This commit is contained in:
jze9
2026-05-19 17:48:35 +05:00
parent 57ac3fc317
commit eb4e71ee77
17 changed files with 694 additions and 150 deletions

View File

@@ -73,6 +73,9 @@ export default function App() {
const articleLoadedRef = useRef(false)
const doSaveRef = useRef(null) // always points to latest doSave
// Loaded article data — fetched independently of editor lifecycle
const [articleData, setArticleData] = useState(null)
/* ── Editor ── */
const editor = useEditor({
extensions: [
@@ -84,7 +87,14 @@ export default function App() {
Color,
Highlight.configure({ multicolor: true }),
TextAlign.configure({ types: ['heading', 'paragraph', 'image'] }),
Image.configure({ allowBase64: false }),
Image.extend({
addAttributes() {
return {
...this.parent?.(),
style: { default: null },
}
},
}).configure({ allowBase64: false }),
Video,
Link.configure({ openOnClick: false, HTMLAttributes: { target: '_blank', rel: 'noopener noreferrer' } }),
Table.configure({ resizable: true }),
@@ -105,45 +115,51 @@ export default function App() {
// Keep editorRef current every render so doSave never uses a stale instance
editorRef.current = editor
/* ── Load categories once on mount ── */
/* ── Load categories + article data on mount (independent of editor) ── */
useEffect(() => {
api.getCategories(TOKEN).then(setCategories).catch(() => {})
if (!IS_NEW) {
api.getArticle(ARTICLE_ID, TOKEN).then(setArticleData).catch(() => {})
}
}, [])
/* ── Load article once the editor is ready ── */
/* ── Apply article data once BOTH editor AND data are ready ── */
useEffect(() => {
if (!editor || IS_NEW || articleLoadedRef.current) return
if (!editor || !articleData || articleLoadedRef.current) return
articleLoadedRef.current = true
api.getArticle(ARTICLE_ID, TOKEN)
.then(data => {
setMeta({
id: data.id,
title: data.title,
slug: data.slug,
excerpt: data.excerpt || '',
cover_url: data.cover_url || null,
source_url: data.source_url || null,
font_family: data.font_family || 'Merriweather',
category_id: data.category?.id || null,
tag_names: (data.tags || []).map(t => t.name),
status: data.status,
})
const html = data.content?.startsWith('<')
? data.content
: marked.parse(data.content || '')
const isFullDoc = /^\s*<!DOCTYPE|^\s*<html/i.test(html)
if (isFullDoc) {
setRawHtml(html)
editor.commands.setContent('', false)
} else {
setRawHtml(null)
editor.commands.setContent(html, false)
}
setSaveStatus('saved')
})
.catch(() => {})
}, [editor])
setMeta({
id: articleData.id,
title: articleData.title,
slug: articleData.slug,
excerpt: articleData.excerpt || '',
cover_url: articleData.cover_url || null,
source_url: articleData.source_url || null,
font_family: articleData.font_family || 'Merriweather',
category_id: articleData.category?.id || null,
tag_names: (articleData.tags || []).map(t => t.name),
status: articleData.status,
})
const html = articleData.content?.startsWith('<')
? articleData.content
: marked.parse(articleData.content || '')
const isFullDoc = /^\s*<!DOCTYPE|^\s*<html/i.test(html)
// Use setTimeout to ensure React has committed meta state before setContent
setTimeout(() => {
const ed = editorRef.current
if (!ed) return
if (isFullDoc) {
setRawHtml(html)
ed.commands.setContent('', false)
} else {
setRawHtml(null)
ed.commands.setContent(html, false)
}
setSaveStatus('saved')
}, 0)
}, [editor, articleData])
/* ── Save ─────────────────────────────────────────────────────────────────
Uses editorRef + metaRef so this callback is stable (no deps that change).