feat: latex rendering with katex

This commit is contained in:
moonmd
2024-12-07 14:25:19 -08:00
committed by Pionxzh
parent 3cfe3e249b
commit 972175e362
7 changed files with 258 additions and 147 deletions

View File

@@ -45,6 +45,8 @@
"mdast-util-to-markdown": "^1.5.0",
"micromark-extension-gfm": "^2.0.3",
"preact": "^10.17.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^12.3.1",
"sanitize-filename": "^1.6.3",
"sentinel-js": "^0.0.7",
@@ -56,12 +58,15 @@
"@commitlint/config-conventional": "^18.6.2",
"@pionxzh/eslint-config": "^1.0.1",
"@preact/preset-vite": "^2.8.3",
"@types/katex": "^0.16.7",
"@types/mdast": "^3.0.15",
"@types/node": "^20.11.20",
"@types/unist": "^2.0.10",
"eslint": "^8.57.0",
"husky": "^9.0.11",
"katex": "^0.16.11",
"lint-staged": "^15.2.7",
"react": "^18.3.1",
"typescript": "^5.5.2",
"vite": "^5.3.2"
},

298
pnpm-lock.yaml generated
View File

@@ -7,13 +7,13 @@ settings:
dependencies:
'@headlessui/react':
specifier: ^1.7.14
version: 1.7.14(react-dom@18.2.0)(react@18.2.0)
version: 1.7.14(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-dialog':
specifier: ^1.0.3
version: 1.0.3(react-dom@18.2.0)(react@18.2.0)
version: 1.0.3(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-hover-card':
specifier: ^1.0.5
version: 1.0.5(react-dom@18.2.0)(react@18.2.0)
version: 1.0.5(react-dom@18.3.1)(react@18.3.1)
eventemitter3:
specifier: ^5.0.1
version: 5.0.1
@@ -53,9 +53,15 @@ dependencies:
preact:
specifier: ^10.17.1
version: 10.17.1
react:
specifier: ^18.3.1
version: 18.3.1
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-i18next:
specifier: ^12.3.1
version: 12.3.1(i18next@22.5.1)(react-dom@18.2.0)(react@18.2.0)
version: 12.3.1(i18next@22.5.1)(react-dom@18.3.1)(react@18.3.1)
sanitize-filename:
specifier: ^1.6.3
version: 1.6.3
@@ -82,6 +88,9 @@ devDependencies:
'@preact/preset-vite':
specifier: ^2.8.3
version: 2.8.3(@babel/core@7.23.2)(preact@10.17.1)(vite@5.3.2)
'@types/katex':
specifier: ^0.16.7
version: 0.16.7
'@types/mdast':
specifier: ^3.0.15
version: 3.0.15
@@ -97,6 +106,9 @@ devDependencies:
husky:
specifier: ^9.0.11
version: 9.0.11
katex:
specifier: ^0.16.11
version: 0.16.11
lint-staged:
specifier: ^15.2.7
version: 15.2.7
@@ -792,21 +804,21 @@ packages:
'@floating-ui/core': 0.7.3
dev: false
/@floating-ui/react-dom@0.7.2(react-dom@18.2.0)(react@18.2.0):
/@floating-ui/react-dom@0.7.2(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
dependencies:
'@floating-ui/dom': 0.5.4
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
use-isomorphic-layout-effect: 1.1.2(react@18.2.0)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
use-isomorphic-layout-effect: 1.1.2(react@18.3.1)
transitivePeerDependencies:
- '@types/react'
dev: false
/@headlessui/react@1.7.14(react-dom@18.2.0)(react@18.2.0):
/@headlessui/react@1.7.14(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-znzdq9PG8rkwcu9oQ2FwIy0ZFtP9Z7ycS+BAqJ3R5EIqC/0bJGvhT7193rFf+45i9nnPsYvCQVW4V/bB9Xc+gA==}
engines: {node: '>=10'}
peerDependencies:
@@ -814,8 +826,8 @@ packages:
react-dom: ^16 || ^17 || ^18
dependencies:
client-only: 0.0.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@humanwhocodes/config-array@0.11.14:
@@ -996,37 +1008,37 @@ packages:
'@babel/runtime': 7.21.0
dev: false
/@radix-ui/react-arrow@1.0.2(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-arrow@1.0.2(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-compose-refs@1.0.0(react@18.2.0):
/@radix-ui/react-compose-refs@1.0.0(react@18.3.1):
resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
react: 18.2.0
react: 18.3.1
dev: false
/@radix-ui/react-context@1.0.0(react@18.2.0):
/@radix-ui/react-context@1.0.0(react@18.3.1):
resolution: {integrity: sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
react: 18.2.0
react: 18.3.1
dev: false
/@radix-ui/react-dialog@1.0.3(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-dialog@1.0.3(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-owNhq36kNPqC2/a+zJRioPg6HHnTn5B/sh/NjTY8r4W9g1L5VJlrzZIVcBr7R9Mg8iLjVmh6MGgMlfoVf/WO/A==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
@@ -1034,26 +1046,26 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-context': 1.0.0(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.0.3(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-focus-guards': 1.0.0(react@18.2.0)
'@radix-ui/react-focus-scope': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-id': 1.0.0(react@18.2.0)
'@radix-ui/react-portal': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-slot': 1.0.1(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.0(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
'@radix-ui/react-context': 1.0.0(react@18.3.1)
'@radix-ui/react-dismissable-layer': 1.0.3(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-focus-guards': 1.0.0(react@18.3.1)
'@radix-ui/react-focus-scope': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-id': 1.0.0(react@18.3.1)
'@radix-ui/react-portal': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-presence': 1.0.0(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-slot': 1.0.1(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.0.0(react@18.3.1)
aria-hidden: 1.2.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-remove-scroll: 2.5.5(react@18.2.0)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-remove-scroll: 2.5.5(react@18.3.1)
transitivePeerDependencies:
- '@types/react'
dev: false
/@radix-ui/react-dismissable-layer@1.0.3(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-dismissable-layer@1.0.3(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
@@ -1061,38 +1073,38 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
'@radix-ui/react-use-escape-keydown': 1.0.2(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
'@radix-ui/react-use-escape-keydown': 1.0.2(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-focus-guards@1.0.0(react@18.2.0):
/@radix-ui/react-focus-guards@1.0.0(react@18.3.1):
resolution: {integrity: sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
react: 18.2.0
react: 18.3.1
dev: false
/@radix-ui/react-focus-scope@1.0.2(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-focus-scope@1.0.2(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-spwXlNTfeIprt+kaEWE/qYuYT3ZAqJiAGjN/JgdvgVDTu8yc+HuX+WOWXrKliKnLnwck0F6JDkqIERncnih+4A==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-hover-card@1.0.5(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-hover-card@1.0.5(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-jXRuZEkxSWdHZbVyL0J46cm7pQjmOMpwJEFKY+VqAJnV+FxS+zIZExI1OCeIiDwCBzUy6If1FfouOsfqBxr86g==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
@@ -1100,156 +1112,156 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-context': 1.0.0(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.0.3(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-popper': 1.1.1(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-portal': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.0(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
'@radix-ui/react-context': 1.0.0(react@18.3.1)
'@radix-ui/react-dismissable-layer': 1.0.3(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-popper': 1.1.1(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-portal': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-presence': 1.0.0(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.0.0(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
transitivePeerDependencies:
- '@types/react'
dev: false
/@radix-ui/react-id@1.0.0(react@18.2.0):
/@radix-ui/react-id@1.0.0(react@18.3.1):
resolution: {integrity: sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0)
react: 18.2.0
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1)
react: 18.3.1
dev: false
/@radix-ui/react-popper@1.1.1(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-popper@1.1.1(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@floating-ui/react-dom': 0.7.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-arrow': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-context': 1.0.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0)
'@radix-ui/react-use-rect': 1.0.0(react@18.2.0)
'@radix-ui/react-use-size': 1.0.0(react@18.2.0)
'@floating-ui/react-dom': 0.7.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-arrow': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
'@radix-ui/react-context': 1.0.0(react@18.3.1)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1)
'@radix-ui/react-use-rect': 1.0.0(react@18.3.1)
'@radix-ui/react-use-size': 1.0.0(react@18.3.1)
'@radix-ui/rect': 1.0.0
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
transitivePeerDependencies:
- '@types/react'
dev: false
/@radix-ui/react-portal@1.0.2(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-portal@1.0.2(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-swu32idoCW7KA2VEiUZGBSu9nB6qwGdV6k6HYhUoOo3M1FFpD+VgLzUqtt3mwL1ssz7r2x8MggpLSQach2Xy/Q==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.3.1)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-presence@1.0.0(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-presence@1.0.0(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-primitive@1.0.2(react-dom@18.2.0)(react@18.2.0):
/@radix-ui/react-primitive@1.0.2(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-slot': 1.0.1(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@radix-ui/react-slot': 1.0.1(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@radix-ui/react-slot@1.0.1(react@18.2.0):
/@radix-ui/react-slot@1.0.1(react@18.3.1):
resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
react: 18.2.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.3.1)
react: 18.3.1
dev: false
/@radix-ui/react-use-callback-ref@1.0.0(react@18.2.0):
/@radix-ui/react-use-callback-ref@1.0.0(react@18.3.1):
resolution: {integrity: sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
react: 18.2.0
react: 18.3.1
dev: false
/@radix-ui/react-use-controllable-state@1.0.0(react@18.2.0):
/@radix-ui/react-use-controllable-state@1.0.0(react@18.3.1):
resolution: {integrity: sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
react: 18.2.0
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
react: 18.3.1
dev: false
/@radix-ui/react-use-escape-keydown@1.0.2(react@18.2.0):
/@radix-ui/react-use-escape-keydown@1.0.2(react@18.3.1):
resolution: {integrity: sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
react: 18.2.0
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
react: 18.3.1
dev: false
/@radix-ui/react-use-layout-effect@1.0.0(react@18.2.0):
/@radix-ui/react-use-layout-effect@1.0.0(react@18.3.1):
resolution: {integrity: sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
react: 18.2.0
react: 18.3.1
dev: false
/@radix-ui/react-use-rect@1.0.0(react@18.2.0):
/@radix-ui/react-use-rect@1.0.0(react@18.3.1):
resolution: {integrity: sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/rect': 1.0.0
react: 18.2.0
react: 18.3.1
dev: false
/@radix-ui/react-use-size@1.0.0(react@18.2.0):
/@radix-ui/react-use-size@1.0.0(react@18.3.1):
resolution: {integrity: sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0)
react: 18.2.0
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1)
react: 18.3.1
dev: false
/@radix-ui/rect@1.0.0:
@@ -1440,6 +1452,10 @@ packages:
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
dev: true
/@types/katex@0.16.7:
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
dev: true
/@types/mdast@3.0.15:
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
dependencies:
@@ -2012,6 +2028,11 @@ packages:
engines: {node: '>=18'}
dev: true
/commander@8.3.0:
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
engines: {node: '>= 12'}
dev: true
/comment-parser@1.4.0:
resolution: {integrity: sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==}
engines: {node: '>= 12.0.0'}
@@ -3786,6 +3807,13 @@ packages:
set-immediate-shim: 1.0.1
dev: false
/katex@0.16.11:
resolution: {integrity: sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==}
hasBin: true
dependencies:
commander: 8.3.0
dev: true
/kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
@@ -4845,17 +4873,17 @@ packages:
engines: {node: '>=8'}
dev: true
/react-dom@18.2.0(react@18.2.0):
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
/react-dom@18.3.1(react@18.3.1):
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
peerDependencies:
react: ^18.2.0
react: ^18.3.1
dependencies:
loose-envify: 1.4.0
react: 18.2.0
scheduler: 0.23.0
react: 18.3.1
scheduler: 0.23.2
dev: false
/react-i18next@12.3.1(i18next@22.5.1)(react-dom@18.2.0)(react@18.2.0):
/react-i18next@12.3.1(i18next@22.5.1)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-5v8E2XjZDFzK7K87eSwC7AJcAkcLt5xYZ4+yTPDAW1i7C93oOY1dnr4BaQM7un4Hm+GmghuiPvevWwlca5PwDA==}
peerDependencies:
i18next: '>= 19.0.0'
@@ -4871,15 +4899,15 @@ packages:
'@babel/runtime': 7.21.0
html-parse-stringify: 3.0.1
i18next: 22.5.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
/react-remove-scroll-bar@2.3.4(react@18.2.0):
/react-remove-scroll-bar@2.3.4(react@18.3.1):
resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==}
engines: {node: '>=10'}
peerDependencies:
@@ -4889,12 +4917,12 @@ packages:
'@types/react':
optional: true
dependencies:
react: 18.2.0
react-style-singleton: 2.2.1(react@18.2.0)
react: 18.3.1
react-style-singleton: 2.2.1(react@18.3.1)
tslib: 2.5.0
dev: false
/react-remove-scroll@2.5.5(react@18.2.0):
/react-remove-scroll@2.5.5(react@18.3.1):
resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
engines: {node: '>=10'}
peerDependencies:
@@ -4904,15 +4932,15 @@ packages:
'@types/react':
optional: true
dependencies:
react: 18.2.0
react-remove-scroll-bar: 2.3.4(react@18.2.0)
react-style-singleton: 2.2.1(react@18.2.0)
react: 18.3.1
react-remove-scroll-bar: 2.3.4(react@18.3.1)
react-style-singleton: 2.2.1(react@18.3.1)
tslib: 2.5.0
use-callback-ref: 1.3.0(react@18.2.0)
use-sidecar: 1.1.2(react@18.2.0)
use-callback-ref: 1.3.0(react@18.3.1)
use-sidecar: 1.1.2(react@18.3.1)
dev: false
/react-style-singleton@2.2.1(react@18.2.0):
/react-style-singleton@2.2.1(react@18.3.1):
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
engines: {node: '>=10'}
peerDependencies:
@@ -4924,12 +4952,12 @@ packages:
dependencies:
get-nonce: 1.0.1
invariant: 2.2.4
react: 18.2.0
react: 18.3.1
tslib: 2.5.0
dev: false
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
/react@18.3.1:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
dependencies:
loose-envify: 1.4.0
@@ -5170,8 +5198,8 @@ packages:
truncate-utf8-bytes: 1.0.2
dev: false
/scheduler@0.23.0:
resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
/scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
dependencies:
loose-envify: 1.4.0
dev: false
@@ -5696,7 +5724,7 @@ packages:
resolution: {integrity: sha512-12c4Vi40DHVdZ/8mOLjZjp0asCzM6hi8Gj116fpImRP1FN4gBMCtMi9XhLNOmre/FEQYNqHbZmX8iyYAtIcy8Q==}
dev: false
/use-callback-ref@1.3.0(react@18.2.0):
/use-callback-ref@1.3.0(react@18.3.1):
resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==}
engines: {node: '>=10'}
peerDependencies:
@@ -5706,11 +5734,11 @@ packages:
'@types/react':
optional: true
dependencies:
react: 18.2.0
react: 18.3.1
tslib: 2.5.0
dev: false
/use-isomorphic-layout-effect@1.1.2(react@18.2.0):
/use-isomorphic-layout-effect@1.1.2(react@18.3.1):
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
peerDependencies:
'@types/react': '*'
@@ -5719,10 +5747,10 @@ packages:
'@types/react':
optional: true
dependencies:
react: 18.2.0
react: 18.3.1
dev: false
/use-sidecar@1.1.2(react@18.2.0):
/use-sidecar@1.1.2(react@18.3.1):
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
engines: {node: '>=10'}
peerDependencies:
@@ -5733,7 +5761,7 @@ packages:
optional: true
dependencies:
detect-node-es: 1.1.0
react: 18.2.0
react: 18.3.1
tslib: 2.5.0
dev: false

View File

@@ -397,12 +397,13 @@ async function fetchConversations(offset = 0, limit = 20): Promise<ApiConversati
export async function fetchAllConversations(): Promise<ApiConversationItem[]> {
const conversations: ApiConversationItem[] = []
const limit = 20
const limit = 100
let offset = 0
while (true) {
const result = await fetchConversations(offset, limit)
conversations.push(...result.items)
if (offset + limit >= result.total) break
if (offset + limit >= 1000) break
offset += limit
}
return conversations

View File

@@ -63,7 +63,7 @@ export async function exportAllToHtml(fileNameFormat: string, apiConversations:
level: 9,
},
})
downloadFile('chatgpt-export.zip', 'application/zip', blob)
downloadFile('chatgpt-export-html.zip', 'application/zip', blob)
return true
}
@@ -75,6 +75,8 @@ function conversationToHtml(conversation: ConversationResult, avatar: string, me
const timeStampHtml = ScriptStorage.get<boolean>(KEY_TIMESTAMP_HTML) ?? false
const timeStamp24H = ScriptStorage.get<boolean>(KEY_TIMESTAMP_24H) ?? false
const LatexRegex = /(\s\$\$.+?\$\$\s|\s\$.+?\$\s|\\\[.+?\\\]|\\\(.+?\\\))|(^\$$[\S\s]+?^\$$)|(^\$\$[\S\s]+?^\$\$\$)/gm
const conversationHtml = conversationNodes.map(({ message }) => {
if (!message || !message.content) return null
@@ -107,12 +109,39 @@ function conversationToHtml(conversation: ConversationResult, avatar: string, me
let postSteps: Array<(input: string) => string> = []
if (message.author.role === 'assistant') {
postSteps = [...postSteps, input => transformFootNotes(input, message.metadata)]
postSteps.push((input) => {
const matches = input.match(LatexRegex)
// Skip code block as the following steps can potentially break the code
const isCodeBlock = /```/.test(input)
if (!isCodeBlock && matches) {
let index = 0
input = input.replace(LatexRegex, () => {
// Replace it with `╬${index}╬` to avoid processing from ruining the formula
return `${index++}`
})
input = input
.replace(/^\\\[(.+)\\\]$/gm, '$$$$$1$$$$')
.replace(/\\\[/g, '$$')
.replace(/\\\]/g, '$$')
.replace(/\\\(/g, '$')
.replace(/\\\)/g, '$')
}
let transformed = toHtml(fromMarkdown(input))
if (!isCodeBlock && matches) {
// Replace `╬${index}╬` back to the original latex
transformed = transformed.replace(/╬(\d+)╬/g, (_, index) => {
return matches[+index]
})
}
return transformed
})
}
if (message.author.role === 'user') {
postSteps = [...postSteps, input => `<p>${escapeHtml(input)}</p>`]
}
else {
postSteps = [...postSteps, input => toHtml(fromMarkdown(input))]
postSteps = [...postSteps, input => `<p class="no-katex">${escapeHtml(input)}</p>`]
}
const postProcess = (input: string) => postSteps.reduce((acc, fn) => fn(acc), input)
const content = transformContent(message.content, message.metadata, postProcess)
@@ -260,7 +289,7 @@ function transformContent(
}).join('\n') || ''
}
default:
return postProcess('[Unsupported Content]')
return postProcess(`[Unsupported Content: ${content.content_type} ]`)
}
}

View File

@@ -100,7 +100,7 @@ export async function exportAllToJson(fileNameFormat: string, apiConversations:
level: 9,
},
})
downloadFile('chatgpt-export.zip', 'application/zip', blob)
downloadFile('chatgpt-export-json.zip', 'application/zip', blob)
return true
}

View File

@@ -58,7 +58,7 @@ export async function exportAllToMarkdown(fileNameFormat: string, apiConversatio
level: 9,
},
})
downloadFile('chatgpt-export.zip', 'application/zip', blob)
downloadFile('chatgpt-export-markdown.zip', 'application/zip', blob)
return true
}
@@ -141,9 +141,7 @@ function conversationToMarkdown(conversation: ConversationResult, metaList?: Exp
.replace(/\\\]/g, '$')
.replace(/\\\(/g, '$')
.replace(/\\\)/g, '$')
const matches = input.match(LatexRegex)
// Skip code block as the following steps can potentially break the code
const isCodeBlock = /```/.test(input)
if (!isCodeBlock && matches) {

View File

@@ -10,6 +10,55 @@
<script>
hljs.highlightAll()
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.3/katex.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.3/katex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.3/contrib/auto-render.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\\[", right: "\\]", display: true },
{ left: "\\(", right: "\\)", display: false }
],
throwOnError: false,
ignoredClasses: ["no-katex"],
preProcess: function(math) {
return `\\displaystyle \\Large ${math}`;
}
});
document.querySelectorAll('.katex').forEach(function(el) {
const parent = el.parentNode;
const grandparent = parent.parentNode;
if (grandparent.tagName === 'P' && isOnlyContent(grandparent, parent)) {
el.style.width = '100%';
el.style.display = 'block';
el.style.textAlign = 'center';
parent.style.textAlign = 'center';
} else {
el.style.display = 'inline-block';
el.style.width = 'fit-content';
}
});
function isOnlyContent(parent, element) {
let onlyKaTeX = true;
parent.childNodes.forEach(function(child) {
console.log(child.textContent);
if (child !== element) {
if (child.nodeType === Node.TEXT_NODE) {
if (child.textContent.trim().length > 0) {
onlyKaTeX = false;
}
} else if (child.nodeType === Node.ELEMENT_NODE) {
onlyKaTeX = false;
}
}
});
return onlyKaTeX;
}
});
</script>
<style>
:root {
@@ -497,6 +546,7 @@
font-size: 0.8rem;
color: #acacbe
}
</style>
</head>
@@ -525,7 +575,7 @@
</h1>
<div class="conversation-export">
<p>Exported by
<a href="https://github.com/pionxzh/chatgpt-exporter">ChatGPT Exporter</a>
<a href="https://github.com/pionxzh/chatgpt-exporter.git">ChatGPT Exporter</a>
at {{time}}</p>
</div>
{{details}}