@bytechain.cn/colamd 1.5.0 → 1.5.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.trae/specs/optimize-theme-loading/checklist.md +20 -0
- package/.trae/specs/optimize-theme-loading/spec.md +103 -0
- package/.trae/specs/optimize-theme-loading/tasks.md +40 -0
- package/CHANGELOG.md +323 -0
- package/CLAUDE.md +56 -0
- package/README.md +422 -26
- package/README_CN.md +480 -28
- package/android/app/build/.npmkeep +0 -0
- package/android/app/build.gradle +76 -0
- package/android/app/capacitor.build.gradle +24 -0
- package/android/app/proguard-rules.pro +21 -0
- package/android/app/release.keystore +0 -0
- package/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +26 -0
- package/android/app/src/main/AndroidManifest.xml +64 -0
- package/android/app/src/main/java/cn/bytechain/colamd/MainActivity.java +180 -0
- package/android/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- package/android/app/src/main/res/drawable/splash.png +0 -0
- package/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
- package/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +34 -0
- package/android/app/src/main/res/layout/activity_main.xml +12 -0
- package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
- package/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
- package/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
- package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
- package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
- package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/android/app/src/main/res/values/ic_launcher_background.xml +4 -0
- package/android/app/src/main/res/values/strings.xml +7 -0
- package/android/app/src/main/res/values/styles.xml +22 -0
- package/android/app/src/main/res/xml/file_paths.xml +5 -0
- package/android/app/src/main/res/xml/network_security_config.xml +8 -0
- package/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +18 -0
- package/android/build.gradle +29 -0
- package/android/capacitor.settings.gradle +21 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/android/gradle.properties +22 -0
- package/android/gradlew +248 -0
- package/android/gradlew.bat +92 -0
- package/android/settings.gradle +5 -0
- package/android/variables.gradle +16 -0
- package/bytechain.cn-colamd-1.5.1-beta.2.tgz +0 -0
- package/capacitor.config.js +29 -0
- package/capacitor.config.ts +30 -0
- package/demo.md +191 -484
- package/dist/main/index.js +77 -46
- package/dist/renderer/assets/{arc-tTbbM8LO.js → arc-CPdeInCG.js} +1 -1
- package/dist/renderer/assets/{architectureDiagram-3BPJPVTR-CEgYow6c.js → architectureDiagram-3BPJPVTR-BAbnaR9G.js} +4 -3
- package/dist/renderer/assets/{blockDiagram-GPEHLZMM-LHyVtPwW.js → blockDiagram-GPEHLZMM-CYSWjnJg.js} +5 -4
- package/dist/renderer/assets/{c4Diagram-AAUBKEIU-C1P1eJrf.js → c4Diagram-AAUBKEIU-Rb1tstnr.js} +3 -2
- package/dist/renderer/assets/{channel-upve91Tq.js → channel-DpG2A6fE.js} +1 -1
- package/dist/renderer/assets/{chunk-2J33WTMH-lag2vhq9.js → chunk-2J33WTMH-DFc0Jxy_.js} +1 -1
- package/dist/renderer/assets/{chunk-4BX2VUAB-BXJ8Ggh-.js → chunk-4BX2VUAB-BhRxDTNn.js} +1 -1
- package/dist/renderer/assets/{chunk-55IACEB6-CiBpxRa1.js → chunk-55IACEB6-DEgMVBk8.js} +1 -1
- package/dist/renderer/assets/{chunk-727SXJPM-ODeKQFXC.js → chunk-727SXJPM-bjBIfiz8.js} +5 -5
- package/dist/renderer/assets/{chunk-AQP2D5EJ-BK7xJolB.js → chunk-AQP2D5EJ-DwQMzTzD.js} +3 -3
- package/dist/renderer/assets/{chunk-FMBD7UC4-BxpCZPtz.js → chunk-FMBD7UC4-CkphwJzs.js} +1 -1
- package/dist/renderer/assets/{chunk-ND2GUHAM-CqqaU9Ue.js → chunk-ND2GUHAM-oU09z4y4.js} +1 -1
- package/dist/renderer/assets/{chunk-QZHKN3VN-Biq_K124.js → chunk-QZHKN3VN-rCbVuPBn.js} +1 -1
- package/dist/renderer/assets/{classDiagram-v2-Q7XG4LA2-Cq95X99o.js → classDiagram-4FO5ZUOK-DGS2faoM.js} +7 -6
- package/dist/renderer/assets/{classDiagram-4FO5ZUOK-Cq95X99o.js → classDiagram-v2-Q7XG4LA2-DGS2faoM.js} +7 -6
- package/dist/renderer/assets/{cose-bilkent-S5V4N54A-XasiD0bu.js → cose-bilkent-S5V4N54A-iqY6-EwA.js} +2 -1
- package/dist/renderer/assets/{dagre-BM42HDAG-Nq84Gfx4.js → dagre-BM42HDAG-5t3X5sDa.js} +4 -3
- package/dist/renderer/assets/{diagram-2AECGRRQ-DwuB1GWt.js → diagram-2AECGRRQ-DzHiYDPh.js} +4 -3
- package/dist/renderer/assets/{diagram-5GNKFQAL-C2tgeI1h.js → diagram-5GNKFQAL-BiNv6Keq.js} +5 -4
- package/dist/renderer/assets/{diagram-KO2AKTUF-D5KzjNBc.js → diagram-KO2AKTUF-ClzeDG6f.js} +4 -3
- package/dist/renderer/assets/{diagram-LMA3HP47-C12xHS1c.js → diagram-LMA3HP47-CGkw7wII.js} +4 -3
- package/dist/renderer/assets/{diagram-OG6HWLK6-CnxI9oEa.js → diagram-OG6HWLK6-Dl-Hyk1_.js} +5 -4
- package/dist/renderer/assets/{erDiagram-TEJ5UH35-D_uPaKwn.js → erDiagram-TEJ5UH35-BxUN79Qb.js} +5 -4
- package/dist/renderer/assets/{flowDiagram-I6XJVG4X-B6q_1-tE.js → flowDiagram-I6XJVG4X-CzFk-KNI.js} +7 -6
- package/dist/renderer/assets/{ganttDiagram-6RSMTGT7-CFo7ifF9.js → ganttDiagram-6RSMTGT7-C2xl6Igx.js} +3 -2
- package/dist/renderer/assets/{gitGraphDiagram-PVQCEYII-WSexHTnq.js → gitGraphDiagram-PVQCEYII-_fn7XCa7.js} +5 -4
- package/dist/renderer/assets/{graph-DyX_9f6d.js → graph-CDoHYrHm.js} +1 -1
- package/dist/renderer/assets/index-B4uDgADr.js +530 -0
- package/dist/renderer/assets/index-CBcVpA3d.js +30 -0
- package/dist/renderer/assets/index-CGj1spkU.js +27 -0
- package/dist/renderer/assets/{index-dyHEFYvY.css → index-CeFpoCKV.css} +443 -400
- package/dist/renderer/assets/index-D4CPFkph.js +9 -0
- package/dist/renderer/assets/{index-DW7LS8C1.js → index-DAlXyxzt.js} +1183 -346
- package/dist/renderer/assets/index-DxOzbfR-.js +110 -0
- package/dist/renderer/assets/index-Y89U1ptl.js +9 -0
- package/dist/renderer/assets/{infoDiagram-5YYISTIA-DaeJdLRq.js → infoDiagram-5YYISTIA-DL6XIxLz.js} +3 -2
- package/dist/renderer/assets/{ishikawaDiagram-YF4QCWOH-DDCZc35f.js → ishikawaDiagram-YF4QCWOH-BUZLjRo-.js} +2 -1
- package/dist/renderer/assets/{journeyDiagram-JHISSGLW-BEdmpAgl.js → journeyDiagram-JHISSGLW-C4rH_mQM.js} +5 -4
- package/dist/renderer/assets/{kanban-definition-UN3LZRKU-BEFtQcFb.js → kanban-definition-UN3LZRKU-DRbrBcWV.js} +3 -2
- package/dist/renderer/assets/{layout-CAJgQHdw.js → layout-DZl4n4qu.js} +2 -2
- package/dist/renderer/assets/{linear-B2ggJ8Am.js → linear-B0Krxg21.js} +1 -1
- package/dist/renderer/assets/{mindmap-definition-RKZ34NQL-DSxVgHB5.js → mindmap-definition-RKZ34NQL-DdmPsWrn.js} +4 -3
- package/dist/renderer/assets/{pieDiagram-4H26LBE5-CwYoJBuL.js → pieDiagram-4H26LBE5-BPZLqwG0.js} +5 -4
- package/dist/renderer/assets/preload-helper-tXtZnHb0.js +88 -0
- package/dist/renderer/assets/{quadrantDiagram-W4KKPZXB-CST9Fvg9.js → quadrantDiagram-W4KKPZXB-Dr-oWRk9.js} +3 -2
- package/dist/renderer/assets/{requirementDiagram-4Y6WPE33-DtrH52jS.js → requirementDiagram-4Y6WPE33-B6QZd0lo.js} +4 -3
- package/dist/renderer/assets/{sankeyDiagram-5OEKKPKP-ca1tPzJ_.js → sankeyDiagram-5OEKKPKP-Cyl9ojEt.js} +2 -1
- package/dist/renderer/assets/{sequenceDiagram-3UESZ5HK-Dfp1EJZ7.js → sequenceDiagram-3UESZ5HK-D48Yr9T6.js} +4 -3
- package/dist/renderer/assets/{stateDiagram-AJRCARHV-Bha2QoNB.js → stateDiagram-AJRCARHV-qyb8ETsa.js} +7 -6
- package/dist/renderer/assets/{stateDiagram-v2-BHNVJYJU-DWgFUYu1.js → stateDiagram-v2-BHNVJYJU-DmDOyyrJ.js} +5 -4
- package/dist/renderer/assets/{timeline-definition-PNZ67QCA-C3h_-OTj.js → timeline-definition-PNZ67QCA-C-KQxTi1.js} +3 -2
- package/dist/renderer/assets/{vennDiagram-CIIHVFJN-DFzjSrZi.js → vennDiagram-CIIHVFJN-BdaZlnH-.js} +2 -1
- package/dist/renderer/assets/{wardley-L42UT6IY-Cx-VbqoS.js → wardley-L42UT6IY-b-_GPpqL.js} +1 -1
- package/dist/renderer/assets/{wardleyDiagram-YWT4CUSO-S2D9XqX6.js → wardleyDiagram-YWT4CUSO-B2hBE-EE.js} +4 -3
- package/dist/renderer/assets/web-BKE0SH0E.js +36 -0
- package/dist/renderer/assets/web-CBsFp24u.js +564 -0
- package/dist/renderer/assets/web-Dc8YgoHP.js +24 -0
- package/dist/renderer/assets/web-TfDzToU7.js +58 -0
- package/dist/renderer/assets/{xychartDiagram-2RQKCTM6-Cfxigbts.js → xychartDiagram-2RQKCTM6-CSvswDTY.js} +3 -2
- package/dist/renderer/index.html +62 -3
- package/docs/academic-demo.md +566 -0
- package/docs/demo.html +748 -0
- package/docs/demo.md +546 -0
- package/docs/demo.pdf +0 -0
- package/docs/theme-paradigm.md +658 -0
- package/electron-builder.yml +7 -0
- package/electron.vite.config.js +31 -0
- package/electron.vite.config.ts +1 -1
- package/ios/App/App/AppDelegate.swift +49 -0
- package/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png +0 -0
- package/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- package/ios/App/App/Assets.xcassets/Contents.json +6 -0
- package/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json +23 -0
- package/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
- package/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
- package/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
- package/ios/App/App/Base.lproj/LaunchScreen.storyboard +32 -0
- package/ios/App/App/Base.lproj/Main.storyboard +19 -0
- package/ios/App/App/Info.plist +49 -0
- package/ios/App/App.xcodeproj/project.pbxproj +408 -0
- package/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/App/Podfile +28 -0
- package/package.json +23 -3
- package/resources/templates/slides/template-forest-ink.html +540 -0
- package/scripts/generate-icons.js +102 -0
- package/src/main/index.ts +87 -63
- package/src/preload/index.d.ts +51 -0
- package/src/preload/index.js +70 -0
- package/src/renderer/capacitor-api.ts +713 -0
- package/src/renderer/editor/editor.ts +87 -4
- package/src/renderer/editor/plugins/index.ts +24 -32
- package/src/renderer/editor/plugins/math-plugin.ts +1 -1
- package/src/renderer/editor/plugins/mermaid-plugin-custom.css +13 -398
- package/src/renderer/editor/plugins/mermaid-plugin.ts +62 -71
- package/src/renderer/editor/plugins/themes/base/dark.css +23 -0
- package/src/renderer/editor/plugins/themes/base/elegant.css +32 -0
- package/src/renderer/editor/plugins/themes/base/light.css +20 -0
- package/src/renderer/editor/plugins/themes/base/newsprint.css +27 -0
- package/src/renderer/editor/plugins/themes/components/mermaid/academic.css +43 -0
- package/src/renderer/editor/plugins/themes/components/mermaid/dark.css +20 -0
- package/src/renderer/editor/plugins/themes/components/mermaid/elegant.css +24 -0
- package/src/renderer/editor/plugins/themes/components/mermaid/light.css +21 -0
- package/src/renderer/editor/plugins/themes/components/mermaid/newsprint.css +26 -0
- package/src/renderer/editor/plugins/themes/components/mermaid/variables.css +592 -0
- package/src/renderer/editor/plugins/themes/foundation.css +143 -0
- package/src/renderer/editor/plugins/themes/theme-manager.ts +92 -0
- package/src/renderer/env.d.ts +4 -1
- package/src/renderer/index.html +59 -1
- package/src/renderer/main.ts +432 -57
- package/src/renderer/mobile.css +429 -0
- package/themes/README.md +3 -0
- package/themes/academic-paper.css +1321 -0
- package/themes/elegant.css +14 -7
- package/themes/forest-ink.css +664 -0
- package/themes/pixso-design.css +1261 -0
- package/themes/swiss-design.css +596 -0
- package/themes/template.css +498 -0
- package/tsconfig.main.json +1 -0
- package/tsconfig.main.tsbuildinfo +1 -0
- package/tsconfig.preload.json +1 -0
- package/tsconfig.preload.tsbuildinfo +1 -0
- package/tsconfig.renderer.json +1 -0
- package/tsconfig.renderer.tsbuildinfo +1 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/.trae/documents/fix-mermaid-colors-and-sankey.md +0 -50
- package/src/renderer/themes/theme-manager.ts +0 -40
- /package/src/renderer/{themes → editor/plugins/themes}/base.css +0 -0
package/src/renderer/main.ts
CHANGED
|
@@ -1,10 +1,84 @@
|
|
|
1
|
-
import { createEditor, getMarkdown, getHTML, setMarkdown, togglePluginMode } from './editor/editor'
|
|
2
|
-
import { applyTheme, loadSavedTheme } from './themes/theme-manager'
|
|
1
|
+
import { createEditor, getMarkdown, getHTML, getLiveHTML, setMarkdown, togglePluginMode } from './editor/editor'
|
|
2
|
+
import { applyTheme, loadSavedTheme, setCachedCustomTheme } from './editor/plugins/themes/theme-manager'
|
|
3
3
|
import { getAllPlugins, togglePlugin, findPluginBySelector, findExportCapabilities } from './editor/plugins'
|
|
4
|
-
import './
|
|
4
|
+
import './editor/plugins/math-plugin'
|
|
5
|
+
import './editor/plugins/mermaid-plugin'
|
|
6
|
+
import { createCapacitorAPI } from './capacitor-api'
|
|
7
|
+
import './editor/plugins/themes/base.css'
|
|
8
|
+
import './mobile.css'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Show a brief toast notification. Used for save/export feedback.
|
|
12
|
+
*/
|
|
13
|
+
function showToast(message: string, duration = 2000): void {
|
|
14
|
+
const existing = document.querySelector('.cola-toast')
|
|
15
|
+
if (existing) existing.remove()
|
|
16
|
+
|
|
17
|
+
const toast = document.createElement('div')
|
|
18
|
+
toast.className = 'cola-toast'
|
|
19
|
+
toast.textContent = message
|
|
20
|
+
toast.style.cssText =
|
|
21
|
+
'position:fixed;top:56px;left:50%;transform:translateX(-50%);' +
|
|
22
|
+
'background:rgba(0,0,0,0.8);color:#fff;padding:10px 20px;' +
|
|
23
|
+
'border-radius:8px;font-size:14px;z-index:9999;pointer-events:none;'
|
|
24
|
+
document.body.appendChild(toast)
|
|
25
|
+
|
|
26
|
+
setTimeout(() => {
|
|
27
|
+
toast.style.opacity = '0'
|
|
28
|
+
toast.style.transition = 'opacity 0.3s'
|
|
29
|
+
setTimeout(() => toast.remove(), 300)
|
|
30
|
+
}, duration)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 调用原生桥接层检查是否有通过文件管理器 Intent 待打开的文件。
|
|
35
|
+
* 使用 pull 模式:JS 主动向 Java 查询,避免注入时序问题。
|
|
36
|
+
*/
|
|
37
|
+
function checkAndOpenPendingFile(api?: any): void {
|
|
38
|
+
const bridge = (window as any).ColaMDNative
|
|
39
|
+
if (!bridge || typeof bridge.checkPendingFile !== 'function') return
|
|
40
|
+
try {
|
|
41
|
+
const result = bridge.checkPendingFile()
|
|
42
|
+
if (result && result !== 'null') {
|
|
43
|
+
const data = JSON.parse(result)
|
|
44
|
+
if (data && data.content) {
|
|
45
|
+
setContent(data.content)
|
|
46
|
+
if (data.name && api?.setCurrentFile) {
|
|
47
|
+
api.setCurrentFile(data.name)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (e) { /* ignore */ }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 轮询原生桥接层,获取待打开的文件。
|
|
56
|
+
* Android onNewIntent 在 WebView 重载前触发,需要轮询等待。
|
|
57
|
+
*/
|
|
58
|
+
function processPendingIntentFile(api?: any): void {
|
|
59
|
+
checkAndOpenPendingFile(api)
|
|
60
|
+
}
|
|
5
61
|
|
|
6
|
-
|
|
7
|
-
|
|
62
|
+
// Eagerly load all plugin modules for side-effect registration (registerPluginModule)
|
|
63
|
+
const _pluginRegistry = import.meta.glob<{ default?: unknown }>('./editor/plugins/*-plugin.ts', { eager: true })
|
|
64
|
+
Object.keys(_pluginRegistry)
|
|
65
|
+
|
|
66
|
+
/** Call ensureRendered on all enabled plugins that support it. Used before export. */
|
|
67
|
+
async function ensureAllPluginsRendered(): Promise<void> {
|
|
68
|
+
for (const p of getAllPlugins()) {
|
|
69
|
+
if (p.enabled && p.ensureRendered) await p.ensureRendered()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Re-render nodes of plugins that react to theme changes (e.g. mermaid). */
|
|
74
|
+
function refreshThemeSensitivePlugins(): void {
|
|
75
|
+
for (const p of getAllPlugins()) {
|
|
76
|
+
if (p.enabled && p.nodeTypes && p.onThemeChange) {
|
|
77
|
+
togglePluginMode(p.nodeTypes, 'raw')
|
|
78
|
+
requestAnimationFrame(() => togglePluginMode(p.nodeTypes, 'rendered'))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
8
82
|
|
|
9
83
|
function isSlidesContent(content: string): boolean {
|
|
10
84
|
return /^---\s*\n[\s\S]*?(kicker|chip):/m.test(content)
|
|
@@ -45,36 +119,92 @@ function getContent(): string {
|
|
|
45
119
|
return getMarkdown()
|
|
46
120
|
}
|
|
47
121
|
|
|
122
|
+
function syncRawEdits(): void {
|
|
123
|
+
document.querySelectorAll('.math-block-raw, .math-inline-raw, .mermaid-source').forEach((el) => {
|
|
124
|
+
if ((el as HTMLElement).matches(':focus')) (el as HTMLElement).blur()
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function restoreRenderedMode(api: any): void {
|
|
129
|
+
for (const p of getAllPlugins()) {
|
|
130
|
+
if (!p.enabled) {
|
|
131
|
+
p.enabled = true
|
|
132
|
+
togglePluginMode(p.nodeTypes || [], 'rendered')
|
|
133
|
+
api.syncPluginState(p.id, true)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
48
138
|
async function init(): Promise<void> {
|
|
49
|
-
const api = window.electronAPI
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
139
|
+
const api = window.electronAPI || await createCapacitorAPI()
|
|
140
|
+
|
|
141
|
+
let editorReady = false
|
|
142
|
+
let pendingFileContent: string | null = null
|
|
143
|
+
|
|
144
|
+
// Register file-open listener AS EARLY AS POSSIBLE
|
|
145
|
+
api.onFileOpened((data) => {
|
|
146
|
+
if (editorReady) {
|
|
147
|
+
setContent(data.content)
|
|
148
|
+
} else {
|
|
149
|
+
pendingFileContent = data.content
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
let savedTheme = loadSavedTheme()
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
if (savedTheme.startsWith('custom:')) {
|
|
157
|
+
const fileName = savedTheme.slice(7)
|
|
158
|
+
const css = await api.loadThemeCSS(fileName)
|
|
159
|
+
if (css) {
|
|
160
|
+
setCachedCustomTheme(fileName, css)
|
|
161
|
+
applyTheme(savedTheme)
|
|
162
|
+
} else {
|
|
163
|
+
applyTheme('elegant')
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
applyTheme(savedTheme)
|
|
167
|
+
}
|
|
168
|
+
} catch (e) {
|
|
169
|
+
console.error('Theme initialization failed, falling back to elegant:', e)
|
|
170
|
+
applyTheme('elegant')
|
|
57
171
|
}
|
|
58
172
|
|
|
59
|
-
|
|
173
|
+
try {
|
|
174
|
+
await createEditor('editor')
|
|
175
|
+
} catch (e) {
|
|
176
|
+
console.error('Editor initialization failed:', e)
|
|
177
|
+
}
|
|
178
|
+
editorReady = true
|
|
179
|
+
|
|
180
|
+
if (pendingFileContent !== null) {
|
|
181
|
+
setContent(pendingFileContent)
|
|
182
|
+
pendingFileContent = null
|
|
183
|
+
}
|
|
60
184
|
|
|
61
|
-
// Run plugin init hooks (mermaid initialize, etc.)
|
|
62
185
|
for (const p of getAllPlugins()) p.onInit?.()
|
|
186
|
+
checkAndOpenPendingFile(api)
|
|
63
187
|
|
|
64
|
-
// Send plugin list to main process for menu
|
|
65
188
|
api.registerPlugins(getAllPlugins().map((p) => ({ id: p.id, name: p.name, enabled: p.enabled })))
|
|
66
189
|
|
|
67
|
-
// Handle plugin toggle from menu
|
|
68
190
|
api.onMenuTogglePlugin((id) => {
|
|
69
|
-
togglePlugin(id)
|
|
70
191
|
const p = getAllPlugins().find((x) => x.id === id)
|
|
71
192
|
if (p) {
|
|
193
|
+
togglePlugin(id, !p.enabled)
|
|
72
194
|
const mode = p.enabled ? 'rendered' : 'raw'
|
|
73
|
-
togglePluginMode(p.nodeTypes, mode)
|
|
195
|
+
togglePluginMode(p.nodeTypes || [], mode)
|
|
74
196
|
api.syncPluginState(p.id, p.enabled)
|
|
75
197
|
}
|
|
76
198
|
})
|
|
77
199
|
|
|
200
|
+
// ─── Mobile menu setup ───
|
|
201
|
+
setupMobileMenu(api, savedTheme)
|
|
202
|
+
|
|
203
|
+
// Continuously check for Intent files (Android only, APP already running)
|
|
204
|
+
if (!window.electronAPI) {
|
|
205
|
+
setInterval(() => processPendingIntentFile(api), 3000)
|
|
206
|
+
}
|
|
207
|
+
|
|
78
208
|
// Slides button — open as slides
|
|
79
209
|
slidesBtnEl().addEventListener('click', () => api.openAsSlides(getContent()))
|
|
80
210
|
|
|
@@ -83,39 +213,43 @@ async function init(): Promise<void> {
|
|
|
83
213
|
if (result) setContent(result.content)
|
|
84
214
|
})
|
|
85
215
|
|
|
86
|
-
function syncRawEdits(): void {
|
|
87
|
-
document.querySelectorAll('.math-block-raw, .math-inline-raw, .mermaid-source').forEach((el) => {
|
|
88
|
-
if ((el as HTMLElement).matches(':focus')) (el as HTMLElement).blur()
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function restoreRenderedMode(): void {
|
|
93
|
-
for (const p of getAllPlugins()) {
|
|
94
|
-
if (!p.enabled) {
|
|
95
|
-
p.enabled = true
|
|
96
|
-
togglePluginMode(p.nodeTypes, 'rendered')
|
|
97
|
-
api.syncPluginState(p.id, true)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
216
|
api.onMenuSave(async () => {
|
|
103
217
|
syncRawEdits()
|
|
104
218
|
const ok = await api.saveFile(getContent())
|
|
105
|
-
if (ok)
|
|
219
|
+
if (ok) {
|
|
220
|
+
showToast('Saved')
|
|
221
|
+
restoreRenderedMode(api)
|
|
222
|
+
} else {
|
|
223
|
+
showToast('Save failed')
|
|
224
|
+
}
|
|
106
225
|
})
|
|
107
226
|
api.onMenuSaveAs(async () => {
|
|
108
227
|
syncRawEdits()
|
|
109
228
|
const ok = await api.saveFileAs(getContent())
|
|
110
|
-
if (ok)
|
|
229
|
+
if (ok) {
|
|
230
|
+
showToast('Saved')
|
|
231
|
+
restoreRenderedMode(api)
|
|
232
|
+
} else {
|
|
233
|
+
showToast('Save cancelled or failed')
|
|
234
|
+
}
|
|
111
235
|
})
|
|
112
236
|
api.onMenuExportPDF(async () => {
|
|
113
237
|
syncRawEdits()
|
|
114
|
-
restoreRenderedMode()
|
|
115
|
-
await
|
|
116
|
-
await
|
|
238
|
+
restoreRenderedMode(api)
|
|
239
|
+
await ensureAllPluginsRendered()
|
|
240
|
+
await new Promise(r => setTimeout(r, 300))
|
|
241
|
+
await api.exportPDF(buildExportHTML())
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
document.querySelectorAll('.mermaid-loading, .mermaid-error')
|
|
244
|
+
.forEach(el => (el as HTMLElement).style.display = 'none')
|
|
245
|
+
}, 1000)
|
|
117
246
|
})
|
|
118
|
-
api.onMenuExportHTML(() => {
|
|
247
|
+
api.onMenuExportHTML(async () => {
|
|
248
|
+
syncRawEdits()
|
|
249
|
+
restoreRenderedMode(api)
|
|
250
|
+
await ensureAllPluginsRendered()
|
|
251
|
+
await new Promise(r => setTimeout(r, 200))
|
|
252
|
+
|
|
119
253
|
const s = getComputedStyle(document.body)
|
|
120
254
|
const v = (name: string) => s.getPropertyValue(name).trim()
|
|
121
255
|
const bgColor = v('--bg-color')
|
|
@@ -126,6 +260,7 @@ async function init(): Promise<void> {
|
|
|
126
260
|
const codeBg = v('--code-bg')
|
|
127
261
|
const codeBlockBg = v('--code-block-bg')
|
|
128
262
|
const codeBlockText = v('--code-block-text') || textColor
|
|
263
|
+
const mermaidBg = v('--mermaid-background') || bgColor
|
|
129
264
|
const blockquoteBorder = v('--blockquote-border')
|
|
130
265
|
const blockquoteBg = v('--blockquote-bg') || 'transparent'
|
|
131
266
|
const tableHeaderBg = v('--table-header-bg')
|
|
@@ -161,19 +296,18 @@ th{background:${tableHeaderBg};font-weight:600}
|
|
|
161
296
|
hr{border:none;border-top:2px solid ${borderColor};margin:2em 0}
|
|
162
297
|
img{max-width:100%}
|
|
163
298
|
::selection{background:${selectionBg}}
|
|
164
|
-
.math-inline{display:inline;padding:2px 4px;border-radius:3px;background:${
|
|
165
|
-
.math-block{display:block;padding:16px;margin:1em 0;border-radius:6px;background:${
|
|
166
|
-
.mermaid-block{display:block;padding:16px;margin:1em 0;border-radius:6px;background:${
|
|
299
|
+
.math-inline{display:inline;padding:2px 4px;border-radius:3px;background:${mermaidBg}}
|
|
300
|
+
.math-block{display:block;padding:16px;margin:1em 0;border-radius:6px;background:${mermaidBg};text-align:center;overflow-x:auto}
|
|
301
|
+
.mermaid-block{display:block;padding:16px;margin:1em 0;border-radius:6px;background:${mermaidBg};border:1px solid ${borderColor}}
|
|
167
302
|
.mermaid-preview{display:flex;justify-content:center;align-items:center}
|
|
168
303
|
.mermaid-preview svg{max-width:100%;height:auto}
|
|
169
304
|
.mermaid-preview svg .label text,.mermaid-preview svg .nodeLabel text,.mermaid-preview svg .state-title,.mermaid-preview svg .state-description,.mermaid-preview svg .pieTitleText,.mermaid-preview svg .titleText{transform:translateY(-2px)}.mermaid-preview svg .nodeLabel,.mermaid-preview svg .edgeLabel{display:inline-block;position:relative;top:-2px}
|
|
170
305
|
</style>
|
|
171
|
-
</head><body>${
|
|
306
|
+
</head><body>${getLiveHTML()}</body></html>`
|
|
172
307
|
api.exportHTML(html)
|
|
173
308
|
})
|
|
174
309
|
|
|
175
310
|
api.onNewFile(() => { exitSourceMode(); setMarkdown('') })
|
|
176
|
-
api.onFileOpened((data) => setContent(data.content))
|
|
177
311
|
api.onFileChanged((content) => {
|
|
178
312
|
if (sourceModeActive) {
|
|
179
313
|
sourceEl().value = content
|
|
@@ -181,20 +315,25 @@ img{max-width:100%}
|
|
|
181
315
|
setMarkdown(content)
|
|
182
316
|
}
|
|
183
317
|
})
|
|
184
|
-
|
|
318
|
+
let pendingThemeChange: string | null = null
|
|
319
|
+
let themeChangeTimer: ReturnType<typeof setTimeout> | null = null
|
|
320
|
+
|
|
321
|
+
function applyThemeChange(theme: string): void {
|
|
322
|
+
pendingThemeChange = null
|
|
185
323
|
applyTheme(theme)
|
|
186
|
-
// Notify all plugins of theme change
|
|
187
324
|
for (const p of getAllPlugins()) p.onThemeChange?.(theme)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
325
|
+
refreshThemeSensitivePlugins()
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
api.onSetTheme((theme) => {
|
|
329
|
+
if (themeChangeTimer) clearTimeout(themeChangeTimer)
|
|
330
|
+
pendingThemeChange = theme
|
|
331
|
+
themeChangeTimer = setTimeout(() => {
|
|
332
|
+
if (pendingThemeChange) applyThemeChange(pendingThemeChange)
|
|
333
|
+
}, 50)
|
|
195
334
|
})
|
|
196
335
|
api.onSetCustomCSS((css) => {
|
|
197
|
-
const theme = loadSavedTheme()
|
|
336
|
+
const theme = pendingThemeChange || loadSavedTheme()
|
|
198
337
|
applyTheme(theme, css)
|
|
199
338
|
})
|
|
200
339
|
|
|
@@ -216,7 +355,10 @@ img{max-width:100%}
|
|
|
216
355
|
|
|
217
356
|
api.onMenuImportTheme(async () => {
|
|
218
357
|
const result = await api.loadCustomTheme()
|
|
219
|
-
if (result)
|
|
358
|
+
if (result) {
|
|
359
|
+
setCachedCustomTheme(result.name, result.css)
|
|
360
|
+
applyTheme(`custom:${result.name}`)
|
|
361
|
+
}
|
|
220
362
|
})
|
|
221
363
|
|
|
222
364
|
const agentDot = document.getElementById('agent-dot')
|
|
@@ -300,4 +442,237 @@ img{max-width:100%}
|
|
|
300
442
|
})
|
|
301
443
|
}
|
|
302
444
|
|
|
445
|
+
/**
|
|
446
|
+
* 初始化移动端侧边栏菜单的交互逻辑。
|
|
447
|
+
* 包括菜单开关、主题切换、插件开关、文件操作等。
|
|
448
|
+
* @param api 平台 API(Electron 或 Capacitor)
|
|
449
|
+
* @param currentTheme 当前激活的主题名称
|
|
450
|
+
*/
|
|
451
|
+
function setupMobileMenu(api: any, currentTheme: string): void {
|
|
452
|
+
const menuEl = document.getElementById('mobile-menu')!
|
|
453
|
+
const menuBtn = document.getElementById('menu-btn')!
|
|
454
|
+
const closeBtn = document.getElementById('menu-close-btn')
|
|
455
|
+
const overlay = document.getElementById('menu-overlay')
|
|
456
|
+
if (!menuEl || !menuBtn) return
|
|
457
|
+
|
|
458
|
+
function openMenu(): void {
|
|
459
|
+
menuEl.classList.add('open')
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function closeMenu(): void {
|
|
463
|
+
menuEl.classList.remove('open')
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
menuBtn.addEventListener('click', openMenu)
|
|
467
|
+
closeBtn?.addEventListener('click', closeMenu)
|
|
468
|
+
overlay?.addEventListener('click', closeMenu)
|
|
469
|
+
|
|
470
|
+
// 主题列表
|
|
471
|
+
const themes = [
|
|
472
|
+
{ key: 'light', label: 'Light' },
|
|
473
|
+
{ key: 'dark', label: 'Dark' },
|
|
474
|
+
{ key: 'elegant', label: 'Elegant' },
|
|
475
|
+
{ key: 'newsprint', label: 'Newsprint' },
|
|
476
|
+
]
|
|
477
|
+
|
|
478
|
+
const themeListEl = document.getElementById('menu-theme-list')
|
|
479
|
+
if (themeListEl) {
|
|
480
|
+
themeListEl.innerHTML = themes.map((t) =>
|
|
481
|
+
`<div class="menu-theme-item${t.key === currentTheme ? ' active' : ''}" data-theme="${t.key}">${t.label}</div>`
|
|
482
|
+
).join('')
|
|
483
|
+
|
|
484
|
+
themeListEl.querySelectorAll('.menu-theme-item').forEach((el) => {
|
|
485
|
+
el.addEventListener('click', () => {
|
|
486
|
+
const theme = (el as HTMLElement).dataset.theme!
|
|
487
|
+
applyTheme(theme)
|
|
488
|
+
for (const p of getAllPlugins()) p.onThemeChange?.(theme)
|
|
489
|
+
refreshThemeSensitivePlugins()
|
|
490
|
+
themeListEl.querySelectorAll('.menu-theme-item').forEach((e) => e.classList.remove('active'))
|
|
491
|
+
el.classList.add('active')
|
|
492
|
+
closeMenu()
|
|
493
|
+
})
|
|
494
|
+
})
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 插件列表
|
|
498
|
+
const pluginsSection = document.getElementById('menu-plugins-section')
|
|
499
|
+
const pluginListEl = document.getElementById('menu-plugin-list')
|
|
500
|
+
const plugins = getAllPlugins()
|
|
501
|
+
if (pluginsSection && pluginListEl && plugins.length > 0) {
|
|
502
|
+
pluginsSection.style.display = ''
|
|
503
|
+
pluginListEl.innerHTML = plugins.map((p) =>
|
|
504
|
+
`<div class="menu-plugin-item" data-plugin-id="${p.id}"><span>${p.name}</span><div class="menu-plugin-toggle${p.enabled ? ' on' : ''}"></div></div>`
|
|
505
|
+
).join('')
|
|
506
|
+
|
|
507
|
+
pluginListEl.querySelectorAll('.menu-plugin-item').forEach((el) => {
|
|
508
|
+
el.addEventListener('click', () => {
|
|
509
|
+
const id = (el as HTMLElement).dataset.pluginId!
|
|
510
|
+
const p = getAllPlugins().find((x) => x.id === id)
|
|
511
|
+
if (p) {
|
|
512
|
+
togglePlugin(id, !p.enabled)
|
|
513
|
+
const mode = p.enabled ? 'rendered' : 'raw'
|
|
514
|
+
togglePluginMode(p.nodeTypes || [], mode)
|
|
515
|
+
api.syncPluginState(p.id, p.enabled)
|
|
516
|
+
const toggle = el.querySelector('.menu-plugin-toggle')
|
|
517
|
+
toggle?.classList.toggle('on', p.enabled)
|
|
518
|
+
}
|
|
519
|
+
})
|
|
520
|
+
})
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// 菜单操作按钮
|
|
524
|
+
menuEl.querySelectorAll('.menu-item').forEach((el) => {
|
|
525
|
+
el.addEventListener('click', async () => {
|
|
526
|
+
const action = (el as HTMLElement).dataset.action
|
|
527
|
+
if (!action) return
|
|
528
|
+
closeMenu()
|
|
529
|
+
|
|
530
|
+
switch (action) {
|
|
531
|
+
case 'new':
|
|
532
|
+
exitSourceMode()
|
|
533
|
+
setMarkdown('')
|
|
534
|
+
break
|
|
535
|
+
case 'open': {
|
|
536
|
+
const result = await api.openFile()
|
|
537
|
+
if (result) setContent(result.content)
|
|
538
|
+
break
|
|
539
|
+
}
|
|
540
|
+
case 'save':
|
|
541
|
+
syncRawEdits()
|
|
542
|
+
{
|
|
543
|
+
const ok = await api.saveFile(getContent())
|
|
544
|
+
if (ok) {
|
|
545
|
+
showToast('Saved')
|
|
546
|
+
restoreRenderedMode(api)
|
|
547
|
+
} else {
|
|
548
|
+
showToast('Save failed')
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
break
|
|
552
|
+
case 'save-as':
|
|
553
|
+
syncRawEdits()
|
|
554
|
+
{
|
|
555
|
+
const ok = await api.saveFileAs(getContent())
|
|
556
|
+
if (ok) {
|
|
557
|
+
showToast('Saved')
|
|
558
|
+
restoreRenderedMode(api)
|
|
559
|
+
} else {
|
|
560
|
+
showToast('Save cancelled or failed')
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
break
|
|
564
|
+
case 'export-pdf':
|
|
565
|
+
syncRawEdits()
|
|
566
|
+
restoreRenderedMode(api)
|
|
567
|
+
await ensureAllPluginsRendered()
|
|
568
|
+
await new Promise(r => setTimeout(r, 300))
|
|
569
|
+
await api.exportPDF(buildExportHTML())
|
|
570
|
+
setTimeout(() => {
|
|
571
|
+
document.querySelectorAll('.mermaid-loading, .mermaid-error')
|
|
572
|
+
.forEach(el => (el as HTMLElement).style.display = 'none')
|
|
573
|
+
}, 1000)
|
|
574
|
+
break
|
|
575
|
+
case 'export-html':
|
|
576
|
+
syncRawEdits()
|
|
577
|
+
restoreRenderedMode(api)
|
|
578
|
+
await ensureAllPluginsRendered()
|
|
579
|
+
await new Promise(r => setTimeout(r, 200))
|
|
580
|
+
api.exportHTML(buildExportHTML())
|
|
581
|
+
break
|
|
582
|
+
case 'export-slides':
|
|
583
|
+
await api.exportSlides(getContent())
|
|
584
|
+
break
|
|
585
|
+
case 'new-slides': {
|
|
586
|
+
const template = await api.newSlides()
|
|
587
|
+
if (template) enterSourceMode(template)
|
|
588
|
+
break
|
|
589
|
+
}
|
|
590
|
+
case 'open-as-slides':
|
|
591
|
+
await api.openAsSlides(getContent())
|
|
592
|
+
break
|
|
593
|
+
case 'import-theme': {
|
|
594
|
+
const result = await api.loadCustomTheme()
|
|
595
|
+
if (result) {
|
|
596
|
+
setCachedCustomTheme(result.name, result.css)
|
|
597
|
+
applyTheme(`custom:${result.name}`)
|
|
598
|
+
}
|
|
599
|
+
break
|
|
600
|
+
}
|
|
601
|
+
case 'about':
|
|
602
|
+
api.openExternal('https://github.com/byteuser1977/ColaMD-extend')
|
|
603
|
+
break
|
|
604
|
+
case 'exit':
|
|
605
|
+
try {
|
|
606
|
+
const { App } = await import('@capacitor/app')
|
|
607
|
+
await App.exitApp()
|
|
608
|
+
} catch {
|
|
609
|
+
window.close()
|
|
610
|
+
}
|
|
611
|
+
break
|
|
612
|
+
}
|
|
613
|
+
})
|
|
614
|
+
})
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* 构建导出用的 HTML 字符串,包含当前主题样式。
|
|
619
|
+
* @returns 完整的 HTML 文档字符串
|
|
620
|
+
*/
|
|
621
|
+
function buildExportHTML(): string {
|
|
622
|
+
const s = getComputedStyle(document.body)
|
|
623
|
+
const v = (name: string) => s.getPropertyValue(name).trim()
|
|
624
|
+
const bgColor = v('--bg-color')
|
|
625
|
+
const textColor = v('--text-color')
|
|
626
|
+
const textMuted = v('--text-muted')
|
|
627
|
+
const borderColor = v('--border-color')
|
|
628
|
+
const linkColor = v('--link-color')
|
|
629
|
+
const codeBg = v('--code-bg')
|
|
630
|
+
const codeBlockBg = v('--code-block-bg')
|
|
631
|
+
const codeBlockText = v('--code-block-text') || textColor
|
|
632
|
+
const mermaidBg = v('--mermaid-background') || bgColor
|
|
633
|
+
const blockquoteBorder = v('--blockquote-border')
|
|
634
|
+
const blockquoteBg = v('--blockquote-bg') || 'transparent'
|
|
635
|
+
const tableHeaderBg = v('--table-header-bg')
|
|
636
|
+
const selectionBg = v('--selection-bg')
|
|
637
|
+
|
|
638
|
+
const editor = document.querySelector('#editor .ProseMirror')
|
|
639
|
+
const fontFamily = editor ? getComputedStyle(editor).fontFamily : '-apple-system,BlinkMacSystemFont,sans-serif'
|
|
640
|
+
|
|
641
|
+
const getElColor = (selector: string, fallback: string): string => {
|
|
642
|
+
const el = document.querySelector(`#editor .ProseMirror ${selector}`)
|
|
643
|
+
return el ? getComputedStyle(el).color : fallback
|
|
644
|
+
}
|
|
645
|
+
const strongColor = getElColor('strong', textColor)
|
|
646
|
+
const codeColor = getElColor('code', textColor)
|
|
647
|
+
|
|
648
|
+
return `<!DOCTYPE html>
|
|
649
|
+
<html><head><meta charset="utf-8"><title>ColaMD Export</title>
|
|
650
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.46/dist/katex.min.css">
|
|
651
|
+
<style>
|
|
652
|
+
body{max-width:780px;margin:40px auto;padding:20px;font-family:${fontFamily};line-height:1.75;background:${bgColor};color:${textColor}}
|
|
653
|
+
h1{font-size:2em;font-weight:700;border-bottom:1px solid ${borderColor};padding-bottom:.3em}
|
|
654
|
+
h2{font-size:1.5em;font-weight:600;border-bottom:1px solid ${borderColor};padding-bottom:.25em}
|
|
655
|
+
h3{font-size:1.25em;font-weight:600}
|
|
656
|
+
strong{color:${strongColor}}
|
|
657
|
+
a{color:${linkColor};text-decoration:none}
|
|
658
|
+
code{background:${codeBg};color:${codeColor};padding:2px 6px;border-radius:3px;font-size:.875em;font-family:'SF Mono','Fira Code',Menlo,monospace}
|
|
659
|
+
pre{background:${codeBlockBg};color:${codeBlockText};padding:16px;border-radius:6px;overflow-x:auto;margin:1em 0}
|
|
660
|
+
pre code{background:none;padding:0;color:inherit}
|
|
661
|
+
blockquote{border-left:4px solid ${blockquoteBorder};background:${blockquoteBg};padding-left:16px;margin:1em 0;color:${textMuted}}
|
|
662
|
+
table{border-collapse:collapse;width:100%;margin:1em 0}
|
|
663
|
+
th,td{border:1px solid ${borderColor};padding:8px 12px}
|
|
664
|
+
th{background:${tableHeaderBg};font-weight:600}
|
|
665
|
+
hr{border:none;border-top:2px solid ${borderColor};margin:2em 0}
|
|
666
|
+
img{max-width:100%}
|
|
667
|
+
::selection{background:${selectionBg}}
|
|
668
|
+
.math-inline{display:inline;padding:2px 4px;border-radius:3px;background:${codeBg}}
|
|
669
|
+
.math-block{display:block;padding:16px;margin:1em 0;border-radius:6px;background:${codeBlockBg};text-align:center;overflow-x:auto}
|
|
670
|
+
.mermaid-block{display:block;padding:16px;margin:1em 0;border-radius:6px;background:${mermaidBg};border:1px solid ${borderColor}}
|
|
671
|
+
.mermaid-preview{display:flex;justify-content:center;align-items:center}
|
|
672
|
+
.mermaid-preview svg{max-width:100%;height:auto}
|
|
673
|
+
@page{margin:15mm;size:A4}
|
|
674
|
+
@media print{body{max-width:none;margin:0;padding:20px}#editor{position:static!important;overflow:visible!important}}
|
|
675
|
+
</style>
|
|
676
|
+
</head><body>${getLiveHTML()}</body></html>`
|
|
677
|
+
}
|
|
303
678
|
init().catch((e) => console.error('ColaMD init failed:', e))
|