92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import React, { useMemo } from 'react';
|
|
import { DocumentBlock } from '../../../types/block';
|
|
import katex from 'katex';
|
|
import { Calculator } from 'lucide-react';
|
|
|
|
interface MathBlockViewProps {
|
|
block: DocumentBlock;
|
|
}
|
|
|
|
export const MathBlockView: React.FC<MathBlockViewProps> = ({ block }) => {
|
|
const renderedHtml = useMemo(() => {
|
|
try {
|
|
const cleanContent = block.content.trim().replace(/^\\?\$+/, '').replace(/\$+$/, '');
|
|
return katex.renderToString(cleanContent, {
|
|
displayMode: true,
|
|
throwOnError: false,
|
|
});
|
|
} catch (err: any) {
|
|
return `<span style="color:var(--danger)">LaTeX 解析错误: ${err.message}</span>`;
|
|
}
|
|
}, [block.content]);
|
|
|
|
const caption = block.properties?.caption || '关键计算判据与物理算法模型';
|
|
// 提取公式右侧序号简写,例如 "式 (3-1)" 提取为 "(3-1)"
|
|
const formulaTag = block.numbering ? block.numbering.replace(/^式\s*/, '') : '';
|
|
|
|
return (
|
|
<div style={{ margin: '18px 0', display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
|
<div
|
|
style={{
|
|
padding: '16px 20px',
|
|
borderRadius: 'var(--r-md)',
|
|
background: 'var(--bg-subtle)',
|
|
border: '1px solid var(--border)',
|
|
overflowX: 'auto',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
boxShadow: 'var(--shadow-xs)',
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
<div
|
|
dangerouslySetInnerHTML={{ __html: renderedHtml }}
|
|
style={{
|
|
fontSize: '15px',
|
|
color: 'var(--text-strong)',
|
|
maxWidth: '100%',
|
|
}}
|
|
/>
|
|
|
|
{/* 国际工程/学术规范:公式右侧常驻对齐编号 */}
|
|
{formulaTag && (
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
right: '18px',
|
|
color: 'var(--text-muted)',
|
|
fontFamily: 'var(--font-mono)',
|
|
fontSize: '12.5px',
|
|
fontWeight: 600,
|
|
userSelect: 'none',
|
|
}}
|
|
title="公式章节编号"
|
|
>
|
|
{formulaTag}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 题注与完整编号 */}
|
|
<div
|
|
style={{
|
|
fontSize: '11px',
|
|
fontWeight: 600,
|
|
color: 'var(--text-muted)',
|
|
textAlign: 'center',
|
|
letterSpacing: '0.3px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: '4px',
|
|
}}
|
|
>
|
|
<Calculator size={12} color="var(--brand-500)" />
|
|
<span>{block.numbering ? `${block.numbering} ` : ''}</span>
|
|
<span>{caption}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|