M0-M11 狩夜人笔记初始实现:11里程碑+86测试
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useEditorRef } from '../editor/editor-context';
|
||||
import type { Editor } from '@tiptap/react';
|
||||
|
||||
interface HeadingItem { id: string; level: number; text: string; pos: number; }
|
||||
|
||||
export function OutlinePanel() {
|
||||
const editor = useEditorRef();
|
||||
const [headings, setHeadings] = useState<HeadingItem[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor) return;
|
||||
const collect = () => {
|
||||
const items: HeadingItem[] = [];
|
||||
editor.state.doc.descendants((node, pos) => {
|
||||
if (node.type.name === 'heading') {
|
||||
items.push({ id: `${pos}-${node.attrs.level}`, level: node.attrs.level, text: node.textContent, pos });
|
||||
}
|
||||
});
|
||||
setHeadings(items);
|
||||
};
|
||||
collect();
|
||||
editor.on('update', collect);
|
||||
return () => { editor.off('update', collect); };
|
||||
}, [editor]);
|
||||
|
||||
const scrollTo = (h: HeadingItem) => {
|
||||
if (!editor) return;
|
||||
editor.commands.setTextSelection(h.pos);
|
||||
editor.commands.scrollIntoView();
|
||||
// 闪烁高亮(简化版:focus 即可)
|
||||
editor.commands.focus();
|
||||
};
|
||||
|
||||
if (headings.length === 0) {
|
||||
return <div style={{ padding: 16, opacity: 0.5, fontSize: 13 }}>无标题。添加一至六级标题以生成大纲。</div>;
|
||||
}
|
||||
return (
|
||||
<div style={{ padding: 16, overflow: 'auto' }}>
|
||||
<div style={{ opacity: 0.6, fontSize: 12, marginBottom: 8 }}>大纲({headings.length})</div>
|
||||
{headings.map(h => (
|
||||
<div key={h.id} onClick={() => scrollTo(h)}
|
||||
style={{ paddingLeft: 8 + (h.level - 1) * 12, cursor: 'pointer', padding: '4px 4px 4px ' + (8 + (h.level-1)*12) + 'px',
|
||||
fontSize: 13, borderRadius: 4 }}
|
||||
onMouseEnter={e => (e.currentTarget.style.background = '#2a2a2a')}
|
||||
onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}>
|
||||
{h.text || '(空标题)'}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user