创作视图增加编辑栏
This commit is contained in:
@@ -1462,7 +1462,6 @@ ${previewHtml}
|
||||
hybridPreviewArticleRef={hybridPreviewArticleRef}
|
||||
hybridPreviewRef={hybridPreviewRef}
|
||||
hybridPreviewShellRef={hybridPreviewShellRef}
|
||||
hybridEditorViewRef={hybridEditorViewRef}
|
||||
hybridLinePulse={hybridLinePulse}
|
||||
previewHtml={previewHtml}
|
||||
baseFilePath={activeTab?.filePath ?? null}
|
||||
|
||||
@@ -23,7 +23,6 @@ type ContentAreaProps = {
|
||||
hybridPreviewArticleRef: React.RefObject<HTMLElement | null>
|
||||
hybridPreviewRef: React.RefObject<HTMLDivElement | null>
|
||||
hybridPreviewShellRef: React.RefObject<HTMLDivElement | null>
|
||||
hybridEditorViewRef: React.RefObject<EditorView | null>
|
||||
hybridLinePulse: { seq: number; topPx: number } | null
|
||||
previewHtml: string
|
||||
baseFilePath: string | null
|
||||
@@ -73,7 +72,7 @@ export function ContentArea(props: ContentAreaProps): React.ReactElement {
|
||||
editorMountKey, editorRef,
|
||||
readPreviewArticleRef, readPreviewOuterRef,
|
||||
hybridPreviewArticleRef, hybridPreviewRef, hybridPreviewShellRef,
|
||||
hybridEditorViewRef, hybridLinePulse,
|
||||
hybridLinePulse,
|
||||
previewHtml, baseFilePath, activeId, resolveRelativePath,
|
||||
onOpenMarkdown, onOpenExternal,
|
||||
onDrop, onDragOver, onDragLeave,
|
||||
@@ -109,7 +108,7 @@ export function ContentArea(props: ContentAreaProps): React.ReactElement {
|
||||
if (article) scrollArticleToQuery(article, searchQuery)
|
||||
return
|
||||
}
|
||||
hybridEditorViewRef.current?.searchText?.(searchQuery)
|
||||
editorRef.current?.searchText(searchQuery)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -151,7 +150,7 @@ export function ContentArea(props: ContentAreaProps): React.ReactElement {
|
||||
) : null}
|
||||
|
||||
<section className={`content${dragOver ? ' content-drag-over' : ''}`} onDrop={onDrop} onDragOver={onDragOver} onDragLeave={onDragLeave}>
|
||||
{viewMode === 'hybrid' && activeTab ? (
|
||||
{(viewMode === 'hybrid' || viewMode === 'live') && activeTab ? (
|
||||
<MarkdownFormatToolbar editorRef={editorRef} />
|
||||
) : null}
|
||||
{viewMode === 'read' ? (
|
||||
|
||||
@@ -11,11 +11,15 @@ function ensureMermaid(): void {
|
||||
theme: 'neutral',
|
||||
securityLevel: 'loose',
|
||||
fontFamily: 'inherit',
|
||||
flowchart: { useMaxWidth: true, htmlLabels: true, wrappingWidth: 180 },
|
||||
sequence: { useMaxWidth: true, wrap: true, width: 150 },
|
||||
er: { useMaxWidth: true },
|
||||
gantt: { useMaxWidth: true },
|
||||
mindmap: { useMaxWidth: true }
|
||||
themeVariables: {
|
||||
fontSize: '15px',
|
||||
fontFamily: 'inherit'
|
||||
},
|
||||
flowchart: { useMaxWidth: false, htmlLabels: true, wrappingWidth: 220 },
|
||||
sequence: { useMaxWidth: false, wrap: true, width: 200 },
|
||||
er: { useMaxWidth: false },
|
||||
gantt: { useMaxWidth: false },
|
||||
mindmap: { useMaxWidth: false }
|
||||
})
|
||||
mermaidInited = true
|
||||
}
|
||||
@@ -69,7 +73,12 @@ async function renderMermaidIn(root: HTMLElement, isStale: () => boolean): Promi
|
||||
if (!root.isConnected || !wrap.isConnected) return
|
||||
host.innerHTML = svg
|
||||
bindFunctions?.(host)
|
||||
tuneMermaidDiagram(host, wrap)
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
tuneMermaidDiagram(host, wrap)
|
||||
observeMermaidWrap(wrap, host)
|
||||
})
|
||||
})
|
||||
wrap.dataset.mermaidRendered = '1'
|
||||
} catch (err) {
|
||||
if (isStale()) return
|
||||
@@ -81,14 +90,58 @@ async function renderMermaidIn(root: HTMLElement, isStale: () => boolean): Promi
|
||||
}
|
||||
}
|
||||
|
||||
function diagramAvailableWidth(wrap: HTMLElement): number {
|
||||
let w = wrap.clientWidth
|
||||
if (w < 80) {
|
||||
const shell = wrap.closest('.preview-shell, .live-line-shell, .hybrid-preview-shell')
|
||||
if (shell instanceof HTMLElement) w = shell.clientWidth
|
||||
if (w < 80 && wrap.parentElement) w = wrap.parentElement.clientWidth
|
||||
}
|
||||
return Math.max(320, Math.min(w - 48, 1100))
|
||||
}
|
||||
|
||||
function tuneMermaidDiagram(host: HTMLElement, wrap: HTMLElement): void {
|
||||
const svg = host.querySelector('svg')
|
||||
if (!svg) return
|
||||
|
||||
svg.style.transform = ''
|
||||
svg.style.transformOrigin = ''
|
||||
host.style.minHeight = ''
|
||||
|
||||
const availW = diagramAvailableWidth(wrap)
|
||||
if (availW < 80) return
|
||||
|
||||
const vb = svg.viewBox?.baseVal
|
||||
let naturalW = vb?.width ?? 0
|
||||
let naturalH = vb?.height ?? 0
|
||||
if (!naturalW || !naturalH) {
|
||||
try {
|
||||
const bb = svg.getBBox()
|
||||
naturalW = bb.width
|
||||
naturalH = bb.height
|
||||
} catch {
|
||||
const r = svg.getBoundingClientRect()
|
||||
naturalW = r.width
|
||||
naturalH = r.height
|
||||
}
|
||||
}
|
||||
if (!naturalW || !naturalH) return
|
||||
|
||||
const targetW = availW
|
||||
const targetH = (naturalH / naturalW) * targetW
|
||||
|
||||
svg.setAttribute('width', String(Math.round(targetW)))
|
||||
svg.setAttribute('height', String(Math.round(targetH)))
|
||||
svg.style.width = `${Math.round(targetW)}px`
|
||||
svg.style.maxWidth = '100%'
|
||||
svg.style.height = 'auto'
|
||||
svg.removeAttribute('width')
|
||||
svg.removeAttribute('height')
|
||||
svg.style.display = 'block'
|
||||
svg.style.margin = '0 auto'
|
||||
|
||||
host.style.width = '100%'
|
||||
host.style.overflowX = naturalW > availW * 1.05 ? 'auto' : 'hidden'
|
||||
host.style.overflowY = 'hidden'
|
||||
host.style.minHeight = `${Math.ceil(targetH) + 8}px`
|
||||
|
||||
host.querySelectorAll('foreignObject').forEach((fo) => {
|
||||
fo.setAttribute('overflow', 'visible')
|
||||
@@ -97,27 +150,27 @@ function tuneMermaidDiagram(host: HTMLElement, wrap: HTMLElement): void {
|
||||
inner.style.wordBreak = 'break-word'
|
||||
inner.style.overflowWrap = 'anywhere'
|
||||
inner.style.whiteSpace = 'normal'
|
||||
inner.style.maxWidth = '100%'
|
||||
inner.style.lineHeight = '1.35'
|
||||
inner.style.fontSize = '13px'
|
||||
inner.style.lineHeight = '1.4'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const vb = svg.viewBox?.baseVal
|
||||
const svgW = vb?.width || svg.getBoundingClientRect().width
|
||||
const maxW = Math.max(120, wrap.clientWidth - 24)
|
||||
if (svgW > maxW && maxW > 0) {
|
||||
const scale = maxW / svgW
|
||||
const svgH = vb?.height || svg.getBoundingClientRect().height
|
||||
host.style.width = '100%'
|
||||
host.style.overflowX = 'auto'
|
||||
host.style.overflowY = 'hidden'
|
||||
svg.style.display = 'block'
|
||||
svg.style.margin = '0 auto'
|
||||
svg.style.transform = `scale(${scale})`
|
||||
svg.style.transformOrigin = 'top center'
|
||||
host.style.minHeight = `${Math.ceil(svgH * scale) + 8}px`
|
||||
}
|
||||
type WrapWithObserver = HTMLElement & { __mermaidRO?: ResizeObserver }
|
||||
|
||||
function observeMermaidWrap(wrap: WrapWithObserver, host: HTMLElement): void {
|
||||
wrap.__mermaidRO?.disconnect()
|
||||
const ro = new ResizeObserver(() => {
|
||||
requestAnimationFrame(() => tuneMermaidDiagram(host, wrap))
|
||||
})
|
||||
ro.observe(wrap)
|
||||
wrap.__mermaidRO = ro
|
||||
}
|
||||
|
||||
function disconnectMermaidObservers(root: HTMLElement): void {
|
||||
root.querySelectorAll<WrapWithObserver>('.md-diagram-wrap').forEach((wrap) => {
|
||||
wrap.__mermaidRO?.disconnect()
|
||||
delete wrap.__mermaidRO
|
||||
})
|
||||
}
|
||||
|
||||
function escapeHtml(s: string): string {
|
||||
@@ -262,6 +315,7 @@ export function PreviewArticle({
|
||||
|
||||
return () => {
|
||||
renderGenRef.current += 1
|
||||
disconnectMermaidObservers(root)
|
||||
}
|
||||
}, [html])
|
||||
|
||||
|
||||
@@ -1774,7 +1774,8 @@ html[data-bg='22'] .app-root {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
text-align: center;
|
||||
contain: layout style;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.preview .md-diagram-wrap pre.mermaid {
|
||||
@@ -1804,8 +1805,11 @@ html[data-bg='22'] .app-root {
|
||||
|
||||
.preview .md-diagram-wrap .mermaid-render-host svg {
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.preview .md-diagram-wrap .mermaid-render-host svg foreignObject {
|
||||
@@ -2574,6 +2578,11 @@ html[data-bg='22'] .app-root {
|
||||
.live-block-preview-inner .md-code-wrap,
|
||||
.live-block-preview-inner .md-diagram-wrap {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.live-block-preview-inner .md-diagram-wrap {
|
||||
padding: 20px 16px 24px;
|
||||
}
|
||||
|
||||
.live-block--preview .live-block-preview-inner a {
|
||||
|
||||
Reference in New Issue
Block a user