chore: land tree view-state, vault, Pi module split, and repo hygiene
Persist PageTree expand state via control-plane view-state and align chevron/DOM with restored expansion; keep Sidex-style shallow page-tree scan and drop the unused recursive scanner that only added cargo noise. Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi into a module package, and retire Hermes/ACP/OpenHub recycle + root harness evidence from the index while gitignoring recycle and local diag dumps. Archive superseded design/bugs docs under old/, point architecture at ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor regressions so the working tree can stay clean.
This commit is contained in:
@@ -389,6 +389,21 @@ export const localMarkdownRelativePathFromDocumentId = (documentId) => {
|
||||
return decodeLocalIdSegment(segment).replace(/^\/+/, '');
|
||||
};
|
||||
|
||||
export const localMarkdownRelativePathFromDocumentsHref = (href) => {
|
||||
const value = String(href || '').trim();
|
||||
if (!value) return '';
|
||||
let url = null;
|
||||
try {
|
||||
url = new URL(value, window.location?.origin || 'http://127.0.0.1:3000');
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
if (!url.pathname.startsWith('/documents/')) return '';
|
||||
const segment = decodeURIComponent(url.pathname.slice('/documents/'.length));
|
||||
if (!segment.startsWith('local-md:')) return '';
|
||||
return localMarkdownRelativePathFromDocumentId(segment);
|
||||
};
|
||||
|
||||
export const localMarkdownDocumentIdFromRelativePath = (relativePath) => {
|
||||
const normalized = String(relativePath || '').trim().replace(/^\/+/, '');
|
||||
if (!normalized) return '';
|
||||
@@ -440,7 +455,12 @@ export const normalizeLocalPageRelativePath = (value, context) => {
|
||||
if (!text || text.startsWith('#')) return '';
|
||||
if (text.startsWith('/documents/')) return text;
|
||||
if (text.startsWith('/api/') || text.startsWith('http://') || text.startsWith('https://') || text.startsWith('mailto:')) return '';
|
||||
const baseDir = text.startsWith('/') ? '' : localMarkdownDirectoryFromDocumentId(context?.documentId);
|
||||
const currentPath = localMarkdownRelativePathFromDocumentId(context?.documentId);
|
||||
const textPath = text.replace(/^\/+/, '');
|
||||
const currentTop = currentPath.split('/').filter(Boolean)[0] || '';
|
||||
const textTop = textPath.split('/').filter(Boolean)[0] || '';
|
||||
const looksRootRelative = Boolean(currentTop && textTop && currentTop === textTop);
|
||||
const baseDir = text.startsWith('/') || looksRootRelative ? '' : localMarkdownDirectoryFromDocumentId(context?.documentId);
|
||||
const parts = (baseDir ? `${baseDir}/${text}` : text)
|
||||
.replace(/\\/g, '/')
|
||||
.split('/');
|
||||
@@ -752,6 +772,32 @@ export const tiptapNodeToEditorBlock = (node, index) => {
|
||||
childBlockIds: [],
|
||||
};
|
||||
}
|
||||
if (node?.type === 'paragraph') {
|
||||
const children = Array.isArray(node?.content) ? node.content : [];
|
||||
if (children.length === 1 && children[0]?.type === 'text') {
|
||||
const textNode = children[0];
|
||||
const linkMark = Array.isArray(textNode.marks)
|
||||
? textNode.marks.find((mark) => {
|
||||
const className = String(mark?.attrs?.class || '');
|
||||
return mark?.type === 'link' && className.split(/\s+/).includes('mnote-page-block-link');
|
||||
})
|
||||
: null;
|
||||
if (linkMark?.attrs?.href) {
|
||||
const href = String(linkMark.attrs.href || '').trim();
|
||||
const sourcePath = localMarkdownRelativePathFromDocumentsHref(href) || unwrapMarkdownLinkTarget(href);
|
||||
return {
|
||||
blockId,
|
||||
blockType: 'page_reference',
|
||||
props: {
|
||||
title: String(textNode.text || '').trim() || '页面',
|
||||
sourcePath,
|
||||
},
|
||||
contentNodes: inlineTextNodes(node),
|
||||
childBlockIds: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node?.type === 'paragraph') return { blockId, blockType: 'paragraph', props: {}, contentNodes: inlineTextNodes(node), childBlockIds: [] };
|
||||
if (node?.type === 'heading') {
|
||||
const level = Math.max(1, Math.min(6, Number(node?.attrs?.level || 1) || 1));
|
||||
@@ -795,6 +841,11 @@ export const legacyBlocksFromEditorDocument = (editorDocument) => (
|
||||
? { language: block.props?.language || null }
|
||||
: block.blockType === 'mindmap'
|
||||
? mindmapPropsFromAttrs(block.props || {}, block.blockId)
|
||||
: block.blockType === 'page_reference'
|
||||
? {
|
||||
title: block.props?.title || flattenText(block.contentNodes || []) || '页面',
|
||||
sourcePath: block.props?.sourcePath || block.props?.source_path || block.props?.href || '',
|
||||
}
|
||||
: block.blockType === 'image'
|
||||
? { ...(block.props || {}) }
|
||||
: block.blockType === 'toc'
|
||||
|
||||
Reference in New Issue
Block a user