add formula support in two pathes
This commit is contained in:
@@ -4,6 +4,8 @@ import mdx from '@astrojs/mdx';
|
||||
import vue from '@astrojs/vue';
|
||||
import tailwind from '@astrojs/tailwind';
|
||||
import react from '@astrojs/react';
|
||||
import remarkMath from 'remark-math';
|
||||
import rehypeKatex from 'rehype-katex';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
@@ -24,6 +26,8 @@ export default defineConfig({
|
||||
theme: 'github-dark',
|
||||
wrap: true,
|
||||
},
|
||||
remarkPlugins: [remarkMath],
|
||||
rehypePlugins: [rehypeKatex],
|
||||
},
|
||||
vite: {
|
||||
ssr: {
|
||||
|
||||
@@ -296,6 +296,61 @@ import TypewriterText from '../components/react/TypewriterText';
|
||||
- `loop`:是否循环播放(可选,默认为 false)
|
||||
- `style`:自定义样式(可选)
|
||||
|
||||
#### MathFlipCard 数学公式翻转卡片
|
||||
|
||||
一个专门用于展示 LaTeX 数学公式的翻转卡片组件。正面显示渲染后的公式,背面显示 LaTeX 源码。
|
||||
|
||||
```mdx
|
||||
import MathFlipCard from '../components/react/MathFlipCard';
|
||||
|
||||
<MathFlipCard
|
||||
latex="E = mc^2"
|
||||
client:visible
|
||||
/>
|
||||
```
|
||||
|
||||
**属性说明**:
|
||||
- `latex`:LaTeX 公式字符串
|
||||
- `displayMode`:是否为块级公式(可选,默认为 true)
|
||||
- `className`:自定义 CSS 类名(可选)
|
||||
|
||||
**示例**:
|
||||
|
||||
```mdx
|
||||
---
|
||||
title: 数学公式展示
|
||||
description: 使用翻转卡片展示数学公式
|
||||
pubDate: 2024-01-20
|
||||
tags: [数学, LaTeX]
|
||||
---
|
||||
|
||||
import MathFlipCard from '../components/react/MathFlipCard';
|
||||
|
||||
# 数学公式展示
|
||||
|
||||
## 质能方程
|
||||
|
||||
<MathFlipCard latex="E = mc^2" client:load />
|
||||
|
||||
## 麦克斯韦方程组
|
||||
|
||||
<MathFlipCard latex="\nabla \cdot \mathbf{E} = \frac{\rho}{\varepsilon_0}" client:load />
|
||||
|
||||
## 薛定谔方程
|
||||
|
||||
<MathFlipCard latex="i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \left[-\frac{\hbar^2}{2m}\nabla^2 + V(\mathbf{r},t)\right]\Psi(\mathbf{r},t)" client:load />
|
||||
|
||||
## 矩阵运算
|
||||
|
||||
<MathFlipCard latex="\begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}" client:load />
|
||||
```
|
||||
|
||||
**特点**:
|
||||
- 点击"显示 LaTeX"按钮可查看公式源码
|
||||
- 点击"显示公式"按钮返回渲染结果
|
||||
- 支持 KaTeX 的所有语法
|
||||
- 适合教学和技术文档
|
||||
|
||||
### 在文章中使用
|
||||
|
||||
在 MDX 文章中导入并使用这些组件:
|
||||
|
||||
173
package-lock.json
generated
173
package-lock.json
generated
@@ -12,13 +12,14 @@
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@astrojs/tailwind": "^5.1.5",
|
||||
"@astrojs/vue": "^5.1.4",
|
||||
"@myriaddreamin/typst-ts-renderer": "^0.7.0-rc2",
|
||||
"@myriaddreamin/typst.ts": "^0.7.0-rc2",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"astro": "^5.17.1",
|
||||
"katex": "^0.16.33",
|
||||
"marked": "^17.0.3",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"vue": "^3.5.29"
|
||||
}
|
||||
@@ -1642,33 +1643,6 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@myriaddreamin/typst-ts-renderer": {
|
||||
"version": "0.7.0-rc2",
|
||||
"resolved": "https://registry.npmjs.org/@myriaddreamin/typst-ts-renderer/-/typst-ts-renderer-0.7.0-rc2.tgz",
|
||||
"integrity": "sha512-god1tcb2YJDkQfA8gLGcAmykVGBpNKorqqDkXVy3InC18KRbsverJhlrHoONurNIU9JuIHoWjJ2D1ntpjPgzbA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@myriaddreamin/typst.ts": {
|
||||
"version": "0.7.0-rc2",
|
||||
"resolved": "https://registry.npmjs.org/@myriaddreamin/typst.ts/-/typst.ts-0.7.0-rc2.tgz",
|
||||
"integrity": "sha512-VM8JqsRcL3AEJ5cuPBn/YvnGTXK/BRPlxdGB2bR48Of/8OIGaPiunv2QfZBIMBBrtbTygUOtAY9BZvkS1AFqgA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"idb": "^7.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@myriaddreamin/typst-ts-renderer": "^0.7.0-rc2",
|
||||
"@myriaddreamin/typst-ts-web-compiler": "^0.7.0-rc2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@myriaddreamin/typst-ts-renderer": {
|
||||
"optional": true
|
||||
},
|
||||
"@myriaddreamin/typst-ts-web-compiler": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -2246,6 +2220,12 @@
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/katex": {
|
||||
"version": "0.16.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz",
|
||||
"integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/mdast": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
||||
@@ -4140,6 +4120,21 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-dom": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz",
|
||||
"integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"hastscript": "^9.0.0",
|
||||
"web-namespaces": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
|
||||
@@ -4158,6 +4153,22 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html-isomorphic": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz",
|
||||
"integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"hast-util-from-dom": "^5.0.0",
|
||||
"hast-util-from-html": "^2.0.0",
|
||||
"unist-util-remove-position": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-parse5": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz",
|
||||
@@ -4409,12 +4420,6 @@
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/idb": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
|
||||
"integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/import-meta-resolve": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz",
|
||||
@@ -4715,6 +4720,31 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/katex": {
|
||||
"version": "0.16.33",
|
||||
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.33.tgz",
|
||||
"integrity": "sha512-q3N5u+1sY9Bu7T4nlXoiRBXWfwSefNGoKeOwekV+gw0cAXQlz2Ww6BLcmBxVDeXBMUDQv6fK5bcNaJLxob3ZQA==",
|
||||
"funding": [
|
||||
"https://opencollective.com/katex",
|
||||
"https://github.com/sponsors/katex"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^8.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"katex": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/katex/node_modules/commander": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
@@ -4977,6 +5007,25 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-math": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz",
|
||||
"integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"longest-streak": "^3.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.1.0",
|
||||
"unist-util-remove-position": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz",
|
||||
@@ -5328,6 +5377,25 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-math": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz",
|
||||
"integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/katex": "^0.16.0",
|
||||
"devlop": "^1.0.0",
|
||||
"katex": "^0.16.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-mdx-expression": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz",
|
||||
@@ -6691,6 +6759,25 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-katex": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz",
|
||||
"integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/katex": "^0.16.0",
|
||||
"hast-util-from-html-isomorphic": "^2.0.0",
|
||||
"hast-util-to-text": "^4.0.0",
|
||||
"katex": "^0.16.0",
|
||||
"unist-util-visit-parents": "^6.0.0",
|
||||
"vfile": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-parse": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz",
|
||||
@@ -6769,6 +6856,22 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-math": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz",
|
||||
"integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-math": "^3.0.0",
|
||||
"micromark-extension-math": "^3.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-mdx": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz",
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@astrojs/tailwind": "^5.1.5",
|
||||
"@astrojs/vue": "^5.1.4",
|
||||
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"astro": "^5.17.1",
|
||||
"katex": "^0.16.33",
|
||||
"marked": "^17.0.3",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"vue": "^3.5.29"
|
||||
}
|
||||
|
||||
147
src/components/react/MathFlipCard.tsx
Normal file
147
src/components/react/MathFlipCard.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import katex from 'katex';
|
||||
|
||||
interface MathFlipCardProps {
|
||||
latex: string;
|
||||
displayMode?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function MathFlipCard({
|
||||
latex,
|
||||
displayMode = true,
|
||||
className = ''
|
||||
}: MathFlipCardProps) {
|
||||
const [isFlipped, setIsFlipped] = useState(false);
|
||||
const mathContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (mathContainerRef.current && !isFlipped) {
|
||||
try {
|
||||
katex.render(latex, mathContainerRef.current, {
|
||||
displayMode: displayMode,
|
||||
throwOnError: false,
|
||||
trust: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('KaTeX rendering error:', error);
|
||||
if (mathContainerRef.current) {
|
||||
mathContainerRef.current.textContent = latex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [latex, displayMode, isFlipped]);
|
||||
|
||||
const containerStyle: React.CSSProperties = {
|
||||
perspective: '1000px',
|
||||
width: '100%',
|
||||
minHeight: displayMode ? '120px' : '60px',
|
||||
position: 'relative',
|
||||
};
|
||||
|
||||
const innerStyle: React.CSSProperties = {
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
minHeight: 'inherit',
|
||||
transformStyle: 'preserve-3d',
|
||||
transition: 'transform 0.6s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
transform: isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)',
|
||||
};
|
||||
|
||||
const faceStyle = (isFront: boolean): React.CSSProperties => ({
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
minHeight: 'inherit',
|
||||
backfaceVisibility: 'hidden',
|
||||
borderRadius: '0.75rem',
|
||||
padding: displayMode ? '1.5rem' : '0.75rem 1rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: 'var(--color-muted, #f1f5f9)',
|
||||
border: '1px solid var(--color-border, #e2e8f0)',
|
||||
transform: isFront ? 'rotateY(0deg)' : 'rotateY(180deg)',
|
||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
|
||||
});
|
||||
|
||||
const codeStyle: React.CSSProperties = {
|
||||
fontFamily: 'var(--font-mono, "JetBrains Mono", monospace)',
|
||||
fontSize: displayMode ? '0.9rem' : '0.85rem',
|
||||
color: 'var(--color-foreground, #1e293b)',
|
||||
background: 'transparent',
|
||||
wordBreak: 'break-word',
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
};
|
||||
|
||||
const buttonStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
bottom: '0.5rem',
|
||||
right: '0.5rem',
|
||||
padding: '0.25rem 0.75rem',
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 500,
|
||||
color: 'var(--primary-500, #0ea5e9)',
|
||||
background: 'transparent',
|
||||
border: '1px solid var(--primary-500, #0ea5e9)',
|
||||
borderRadius: '0.375rem',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s ease',
|
||||
zIndex: 10,
|
||||
};
|
||||
|
||||
const handleButtonClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setIsFlipped(!isFlipped);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={containerStyle} className={className}>
|
||||
<div style={innerStyle}>
|
||||
<div style={faceStyle(true)}>
|
||||
<div
|
||||
ref={mathContainerRef}
|
||||
style={{
|
||||
color: 'var(--color-foreground, #1e293b)',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
style={buttonStyle}
|
||||
onClick={handleButtonClick}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = 'var(--primary-500, #0ea5e9)';
|
||||
e.currentTarget.style.color = 'white';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'transparent';
|
||||
e.currentTarget.style.color = 'var(--primary-500, #0ea5e9)';
|
||||
}}
|
||||
>
|
||||
显示 LaTeX
|
||||
</button>
|
||||
</div>
|
||||
<div style={faceStyle(false)}>
|
||||
<pre style={codeStyle}>{latex}</pre>
|
||||
<button
|
||||
style={buttonStyle}
|
||||
onClick={handleButtonClick}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = 'var(--primary-500, #0ea5e9)';
|
||||
e.currentTarget.style.color = 'white';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'transparent';
|
||||
e.currentTarget.style.color = 'var(--primary-500, #0ea5e9)';
|
||||
}}
|
||||
>
|
||||
显示公式
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
116
src/content/blog/latex-test.mdx
Normal file
116
src/content/blog/latex-test.mdx
Normal file
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: 'LaTeX 公式渲染测试'
|
||||
description: '测试 LaTeX 数学公式渲染功能'
|
||||
pubDate: 2026-03-01
|
||||
author: 'NovaBlog Team'
|
||||
category: '测试'
|
||||
tags: ['测试', 'LaTeX', '数学']
|
||||
---
|
||||
|
||||
import MathFlipCard from '../../components/react/MathFlipCard';
|
||||
|
||||
# LaTeX 公式渲染测试
|
||||
|
||||
## 行内公式
|
||||
|
||||
这是一个行内公式:$E = mc^2$,爱因斯坦的质能方程。
|
||||
|
||||
勾股定理:$a^2 + b^2 = c^2$
|
||||
|
||||
## 块级公式
|
||||
|
||||
高斯积分:
|
||||
|
||||
$$
|
||||
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
|
||||
$$
|
||||
|
||||
## 翻转卡片公式展示
|
||||
|
||||
下面使用翻转卡片展示公式,点击"显示 LaTeX"按钮可以查看源码:
|
||||
|
||||
### 质能方程
|
||||
|
||||
<MathFlipCard latex="E = mc^2" client:load />
|
||||
|
||||
### 麦克斯韦方程组
|
||||
|
||||
<MathFlipCard latex="\nabla \cdot \mathbf{E} = \frac{\rho}{\varepsilon_0}" client:load />
|
||||
|
||||
### 薛定谔方程
|
||||
|
||||
<MathFlipCard latex="i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \left[-\frac{\hbar^2}{2m}\nabla^2 + V(\mathbf{r},t)\right]\Psi(\mathbf{r},t)" client:load />
|
||||
|
||||
### 傅里叶变换
|
||||
|
||||
<MathFlipCard latex="\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x) e^{-2\pi i x \xi} dx" client:load />
|
||||
|
||||
### 矩阵运算
|
||||
|
||||
<MathFlipCard latex="\begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}" client:load />
|
||||
|
||||
## 传统公式展示(对比)
|
||||
|
||||
麦克斯韦方程组:
|
||||
|
||||
$$
|
||||
\nabla \cdot \mathbf{E} = \frac{\rho}{\varepsilon_0}
|
||||
$$
|
||||
|
||||
$$
|
||||
\nabla \cdot \mathbf{B} = 0
|
||||
$$
|
||||
|
||||
$$
|
||||
\nabla \times \mathbf{E} = -\frac{\partial \mathbf{B}}{\partial t}
|
||||
$$
|
||||
|
||||
$$
|
||||
\nabla \times \mathbf{B} = \mu_0 \mathbf{J} + \mu_0 \varepsilon_0 \frac{\partial \mathbf{E}}{\partial t}
|
||||
$$
|
||||
|
||||
## 复杂公式
|
||||
|
||||
薛定谔方程:
|
||||
|
||||
$$
|
||||
i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \left[-\frac{\hbar^2}{2m}\nabla^2 + V(\mathbf{r},t)\right]\Psi(\mathbf{r},t)
|
||||
$$
|
||||
|
||||
傅里叶变换:
|
||||
|
||||
$$
|
||||
\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x) e^{-2\pi i x \xi} dx
|
||||
$$
|
||||
|
||||
矩阵:
|
||||
|
||||
$$
|
||||
\begin{pmatrix}
|
||||
a & b \\
|
||||
c & d
|
||||
\end{pmatrix}
|
||||
\begin{pmatrix}
|
||||
x \\
|
||||
y
|
||||
\end{pmatrix}
|
||||
=
|
||||
\begin{pmatrix}
|
||||
ax + by \\
|
||||
cx + dy
|
||||
\end{pmatrix}
|
||||
$$
|
||||
|
||||
求和与积分:
|
||||
|
||||
$$
|
||||
\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
|
||||
$$
|
||||
|
||||
$$
|
||||
\prod_{i=1}^{n} i = n!
|
||||
$$
|
||||
|
||||
## 测试完成
|
||||
|
||||
如果你能看到以上公式正确渲染,说明 LaTeX 公式支持已经成功配置!
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: React 动效组件展示
|
||||
description: 展示 NovaBlog 中可用的 React 动效 HTML 组件,包括悬浮卡片、打字机效果、翻转卡片和粒子背景
|
||||
description: 展示 NovaBlog 中可用的 React 动效 HTML 组件,包括悬浮卡片、打字机效果、翻转卡片、粒子背景和数学公式卡片
|
||||
pubDate: 2024-01-20
|
||||
author: NovaBlog
|
||||
tags: [React, 动效, 组件, 教程]
|
||||
@@ -12,6 +12,7 @@ import AnimatedCard from '../../components/react/AnimatedCard';
|
||||
import TypewriterText from '../../components/react/TypewriterText';
|
||||
import FlipCard from '../../components/react/FlipCard';
|
||||
import ParticleBackground from '../../components/react/ParticleBackground';
|
||||
import MathFlipCard from '../../components/react/MathFlipCard';
|
||||
|
||||
# React 动效组件展示
|
||||
|
||||
@@ -134,6 +135,53 @@ NovaBlog 支持在 MDX 中直接使用 React 组件,实现丰富的交互动
|
||||
</div>
|
||||
</ParticleBackground>
|
||||
|
||||
## 📐 数学公式翻转卡片 (MathFlipCard)
|
||||
|
||||
专门用于展示 LaTeX 数学公式的翻转卡片组件。正面显示渲染后的公式,点击"显示 LaTeX"按钮可以查看源码。
|
||||
|
||||
### 质能方程
|
||||
|
||||
<MathFlipCard latex="E = mc^2" client:load />
|
||||
|
||||
### 麦克斯韦方程组
|
||||
|
||||
<MathFlipCard latex="\nabla \cdot \mathbf{E} = \frac{\rho}{\varepsilon_0}" client:load />
|
||||
|
||||
### 薛定谔方程
|
||||
|
||||
<MathFlipCard latex="i\hbar\frac{\partial}{\partial t}\Psi(\mathbf{r},t) = \left[-\frac{\hbar^2}{2m}\nabla^2 + V(\mathbf{r},t)\right]\Psi(\mathbf{r},t)" client:load />
|
||||
|
||||
### 傅里叶变换
|
||||
|
||||
<MathFlipCard latex="\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x) e^{-2\pi i x \xi} dx" client:load />
|
||||
|
||||
### 矩阵运算
|
||||
|
||||
<MathFlipCard latex="\begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}" client:load />
|
||||
|
||||
### 使用方式
|
||||
|
||||
```tsx
|
||||
import MathFlipCard from '../../components/react/MathFlipCard';
|
||||
|
||||
<MathFlipCard
|
||||
latex="E = mc^2"
|
||||
displayMode={true} // 可选,默认为 true
|
||||
client:load
|
||||
/>
|
||||
```
|
||||
|
||||
**属性说明**:
|
||||
- `latex`:LaTeX 公式字符串
|
||||
- `displayMode`:是否为块级公式(可选,默认为 true)
|
||||
- `className`:自定义 CSS 类名(可选)
|
||||
|
||||
**特点**:
|
||||
- 点击"显示 LaTeX"按钮可查看公式源码
|
||||
- 点击"显示公式"按钮返回渲染结果
|
||||
- 支持 KaTeX 的所有语法
|
||||
- 适合教学和技术文档
|
||||
|
||||
## 📝 如何在文章中使用
|
||||
|
||||
### 1. 导入组件
|
||||
@@ -208,5 +256,6 @@ NovaBlog 提供了灵活的组件系统,让你可以在 Markdown 中嵌入丰
|
||||
- ⌨️ **动态文字**:打字机、滚动、闪烁效果
|
||||
- ✨ **背景特效**:粒子、波浪、光效
|
||||
- 🎮 **交互功能**:计数器、表单、游戏
|
||||
- 📐 **数学公式**:翻转卡片展示 LaTeX 公式
|
||||
|
||||
快去尝试创建属于你自己的动效组件吧! 🚀
|
||||
@@ -1,202 +0,0 @@
|
||||
---
|
||||
title: Typst 学术排版展示
|
||||
description: 展示 NovaBlog 中 Typst 的高级排版能力,包括数学公式、矩阵等学术排版
|
||||
pubDate: 2024-01-25
|
||||
author: NovaBlog
|
||||
tags: [Typst, 排版,数学公式,学术写作]
|
||||
category: 教程
|
||||
heroImage: /images/hello-world.jpg
|
||||
---
|
||||
|
||||
# Typst 学术排版展示
|
||||
|
||||
Typst 是一款现代化的排版系统,专为学术写作和技术文档设计。本文将展示 NovaBlog 中 Typst 的数学公式排版能力。
|
||||
|
||||
## 📐 基础数学公式
|
||||
|
||||
### 积分公式
|
||||
|
||||
```
|
||||
$ integral_0^infinity e^(-x^2) dif x = sqrt(pi) / 2 $
|
||||
```
|
||||
|
||||
### 极限与导数
|
||||
|
||||
```
|
||||
$ lim_(x arrow 0) frac(sin x, x) = 1 $
|
||||
```
|
||||
|
||||
```
|
||||
$ frac(dif f, dif x) = lim_(h arrow 0) frac(f(x + h) - f(x), h) $
|
||||
```
|
||||
|
||||
### 微积分基本定理
|
||||
|
||||
```
|
||||
$ integral_a^b f(x) dif x = F(b) - F(a) $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔢 矩阵与线性代数
|
||||
|
||||
### 基础矩阵
|
||||
|
||||
```
|
||||
$ A = mat(1, 2, 3; 4, 5, 6; 7, 8, 9) $
|
||||
```
|
||||
|
||||
### 行列式展开
|
||||
|
||||
```
|
||||
$ det(A) = sum_(i=1)^n a_(1i) dot (-1)^(1+i) dot M_(1i) $
|
||||
```
|
||||
|
||||
### 特征值方程
|
||||
|
||||
```
|
||||
$ det(A - lambda I) = 0 $
|
||||
```
|
||||
|
||||
### 二次型
|
||||
|
||||
```
|
||||
$ Q(x) = x^T A x = sum_(i,j) a_(ij) x_i x_j $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 统计学与概率论
|
||||
|
||||
### 贝叶斯定理
|
||||
|
||||
```
|
||||
$ P(A | B) = frac(P(B | A) dot P(A), P(B)) $
|
||||
```
|
||||
|
||||
### 正态分布
|
||||
|
||||
```
|
||||
$ X tilde N(mu, sigma^2) arrow.f P(x) = frac(1, sigma sqrt(2 pi)) e^(-frac((x-mu)^2, 2 sigma^2)) $
|
||||
```
|
||||
|
||||
### 期望与方差
|
||||
|
||||
```
|
||||
$ E[X] = sum_(i=1)^n x_i p_i quad Var(X) = E[X^2] - (E[X])^2 $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧮 复杂嵌套表达式
|
||||
|
||||
### 巴塞尔问题
|
||||
|
||||
```
|
||||
$ sum_(n=1)^infinity frac(1, n^2) = frac(pi^2, 6) $
|
||||
```
|
||||
|
||||
### 欧拉恒等式
|
||||
|
||||
```
|
||||
$ e^(i pi) + 1 = 0 $
|
||||
```
|
||||
|
||||
### Gamma 函数
|
||||
|
||||
```
|
||||
$ Gamma(z) = integral_0^infinity t^(z-1) e^(-t) dif t $
|
||||
```
|
||||
|
||||
### 斯特林公式
|
||||
|
||||
```
|
||||
$ n! tilde sqrt(2 pi n) (n/e)^n $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 物理学公式
|
||||
|
||||
### 麦克斯韦方程组
|
||||
|
||||
```
|
||||
$ nabla dot E = frac(rho, epsilon_0) $
|
||||
```
|
||||
|
||||
```
|
||||
$ nabla dot B = 0 $
|
||||
```
|
||||
|
||||
```
|
||||
$ nabla times E = -frac(partial B, partial t) $
|
||||
```
|
||||
|
||||
```
|
||||
$ nabla times B = mu_0 J + mu_0 epsilon_0 frac(partial E, partial t) $
|
||||
```
|
||||
|
||||
### 狭义相对论
|
||||
|
||||
```
|
||||
$ E = m c^2 $
|
||||
```
|
||||
|
||||
```
|
||||
$ t' = frac(t, sqrt(1 - v^2/c^2)) = gamma t $
|
||||
```
|
||||
|
||||
```
|
||||
$ gamma = frac(1, sqrt(1 - v^2/c^2)) $
|
||||
```
|
||||
|
||||
### 薛定谔方程
|
||||
|
||||
```
|
||||
$ i hbar frac(partial psi, partial t) = H^ psi $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔬 化学方程式
|
||||
|
||||
```
|
||||
$ 6 CO_2 + 6 H_2 O arrow.r C_6 H_12 O_6 + 6 O_2 $
|
||||
```
|
||||
|
||||
```
|
||||
$ CH_4 + 2 O_2 arrow.r CO_2 + 2 H_2 O $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📐 集合论
|
||||
|
||||
```
|
||||
$ A union B = { x | x in A text( 或 ) x in B } $
|
||||
```
|
||||
|
||||
```
|
||||
$ A intersect B = { x | x in A text( 且 ) x in B } $
|
||||
```
|
||||
|
||||
```
|
||||
$ A setminus B = { x | x in A text( 且 ) x notin B } $
|
||||
```
|
||||
|
||||
```
|
||||
$ P(A) = { S | S subset.eq A } $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
NovaBlog 曾经通过 TypstBlock 组件支持专业的数学公式排版,适合:
|
||||
|
||||
- 📐 **数学博客**:微积分、线性代数、概率统计
|
||||
- ⚡ **物理笔记**:经典力学、电磁学、量子力学
|
||||
- 🔬 **化学公式**:化学反应方程式
|
||||
- 📊 **学术论文**:复杂的数学推导和证明
|
||||
|
||||
由于技术原因,Typst 支持已暂时移除。
|
||||
@@ -57,6 +57,13 @@ const socialImageURL = image.startsWith('http') ? image : new URL(image, site).h
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!-- KaTeX CSS for LaTeX Math Rendering -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/katex@0.16.33/dist/katex.min.css"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
<!-- Dark Mode Script (防止闪烁) -->
|
||||
<script is:inline>
|
||||
const theme = (() => {
|
||||
|
||||
Reference in New Issue
Block a user