@bytechain.cn/colamd 1.5.0
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/.github/workflows/release.yml +66 -0
- package/.trae/documents/fix-mermaid-colors-and-sankey.md +50 -0
- package/CLAUDE.md +87 -0
- package/LICENSE +21 -0
- package/README.md +540 -0
- package/README_CN.md +543 -0
- package/demo.md +486 -0
- package/dist/main/index.js +735 -0
- package/dist/preload/index.js +71 -0
- package/dist/renderer/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/renderer/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/renderer/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/renderer/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/renderer/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/renderer/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/renderer/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/renderer/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/renderer/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/renderer/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/renderer/assets/arc-tTbbM8LO.js +131 -0
- package/dist/renderer/assets/architectureDiagram-3BPJPVTR-CEgYow6c.js +8720 -0
- package/dist/renderer/assets/blockDiagram-GPEHLZMM-LHyVtPwW.js +3825 -0
- package/dist/renderer/assets/c4Diagram-AAUBKEIU-C1P1eJrf.js +2482 -0
- package/dist/renderer/assets/channel-upve91Tq.js +7 -0
- package/dist/renderer/assets/chunk-2J33WTMH-lag2vhq9.js +24 -0
- package/dist/renderer/assets/chunk-4BX2VUAB-BXJ8Ggh-.js +16 -0
- package/dist/renderer/assets/chunk-55IACEB6-CiBpxRa1.js +13 -0
- package/dist/renderer/assets/chunk-727SXJPM-ODeKQFXC.js +2016 -0
- package/dist/renderer/assets/chunk-AQP2D5EJ-BK7xJolB.js +1953 -0
- package/dist/renderer/assets/chunk-FMBD7UC4-BxpCZPtz.js +19 -0
- package/dist/renderer/assets/chunk-ND2GUHAM-CqqaU9Ue.js +116 -0
- package/dist/renderer/assets/chunk-QZHKN3VN-Biq_K124.js +19 -0
- package/dist/renderer/assets/classDiagram-4FO5ZUOK-Cq95X99o.js +23 -0
- package/dist/renderer/assets/classDiagram-v2-Q7XG4LA2-Cq95X99o.js +23 -0
- package/dist/renderer/assets/cose-bilkent-S5V4N54A-XasiD0bu.js +4942 -0
- package/dist/renderer/assets/cytoscape.esm-CpHeHM5e.js +30269 -0
- package/dist/renderer/assets/dagre-BM42HDAG-Nq84Gfx4.js +705 -0
- package/dist/renderer/assets/defaultLocale-B2RvLBDe.js +206 -0
- package/dist/renderer/assets/diagram-2AECGRRQ-DwuB1GWt.js +301 -0
- package/dist/renderer/assets/diagram-5GNKFQAL-C2tgeI1h.js +169 -0
- package/dist/renderer/assets/diagram-KO2AKTUF-D5KzjNBc.js +632 -0
- package/dist/renderer/assets/diagram-LMA3HP47-C12xHS1c.js +212 -0
- package/dist/renderer/assets/diagram-OG6HWLK6-CnxI9oEa.js +851 -0
- package/dist/renderer/assets/erDiagram-TEJ5UH35-D_uPaKwn.js +1227 -0
- package/dist/renderer/assets/flowDiagram-I6XJVG4X-B6q_1-tE.js +2332 -0
- package/dist/renderer/assets/ganttDiagram-6RSMTGT7-CFo7ifF9.js +3720 -0
- package/dist/renderer/assets/gitGraphDiagram-PVQCEYII-WSexHTnq.js +1373 -0
- package/dist/renderer/assets/graph-DyX_9f6d.js +1988 -0
- package/dist/renderer/assets/index-DW7LS8C1.js +72292 -0
- package/dist/renderer/assets/index-dyHEFYvY.css +2184 -0
- package/dist/renderer/assets/infoDiagram-5YYISTIA-DaeJdLRq.js +31 -0
- package/dist/renderer/assets/init-ZxktEp_H.js +16 -0
- package/dist/renderer/assets/ishikawaDiagram-YF4QCWOH-DDCZc35f.js +967 -0
- package/dist/renderer/assets/journeyDiagram-JHISSGLW-BEdmpAgl.js +1255 -0
- package/dist/renderer/assets/kanban-definition-UN3LZRKU-BEFtQcFb.js +1052 -0
- package/dist/renderer/assets/layout-CAJgQHdw.js +2610 -0
- package/dist/renderer/assets/linear-B2ggJ8Am.js +340 -0
- package/dist/renderer/assets/mindmap-definition-RKZ34NQL-DSxVgHB5.js +1180 -0
- package/dist/renderer/assets/ordinal-DSZU4PqD.js +76 -0
- package/dist/renderer/assets/pieDiagram-4H26LBE5-CwYoJBuL.js +246 -0
- package/dist/renderer/assets/quadrantDiagram-W4KKPZXB-CST9Fvg9.js +1344 -0
- package/dist/renderer/assets/requirementDiagram-4Y6WPE33-DtrH52jS.js +1204 -0
- package/dist/renderer/assets/sankeyDiagram-5OEKKPKP-ca1tPzJ_.js +1274 -0
- package/dist/renderer/assets/sequenceDiagram-3UESZ5HK-Dfp1EJZ7.js +4514 -0
- package/dist/renderer/assets/stateDiagram-AJRCARHV-Bha2QoNB.js +450 -0
- package/dist/renderer/assets/stateDiagram-v2-BHNVJYJU-DWgFUYu1.js +21 -0
- package/dist/renderer/assets/timeline-definition-PNZ67QCA-C3h_-OTj.js +1596 -0
- package/dist/renderer/assets/vennDiagram-CIIHVFJN-DFzjSrZi.js +2486 -0
- package/dist/renderer/assets/wardley-L42UT6IY-Cx-VbqoS.js +30699 -0
- package/dist/renderer/assets/wardleyDiagram-YWT4CUSO-S2D9XqX6.js +975 -0
- package/dist/renderer/assets/xychartDiagram-2RQKCTM6-Cfxigbts.js +1932 -0
- package/dist/renderer/index.html +19 -0
- package/docs/agent-diff-view.md +48 -0
- package/electron-builder.yml +57 -0
- package/electron.vite.config.ts +30 -0
- package/package.json +40 -0
- package/resources/entitlements.mac.plist +12 -0
- package/resources/icon.icns +0 -0
- package/resources/icon.png +0 -0
- package/resources/icon.svg +23 -0
- package/resources/templates/slides/icon.png +0 -0
- package/resources/templates/slides/slides-template.md +74 -0
- package/resources/templates/slides/template.html +535 -0
- package/scripts/afterPack.js +13 -0
- package/src/main/index.ts +881 -0
- package/src/preload/index.ts +110 -0
- package/src/renderer/editor/editor.ts +204 -0
- package/src/renderer/editor/html-view.ts +15 -0
- package/src/renderer/editor/plugins/index.ts +76 -0
- package/src/renderer/editor/plugins/math-plugin.ts +297 -0
- package/src/renderer/editor/plugins/mermaid-plugin-custom.css +431 -0
- package/src/renderer/editor/plugins/mermaid-plugin-dark.css +428 -0
- package/src/renderer/editor/plugins/mermaid-plugin-elegant.css +443 -0
- package/src/renderer/editor/plugins/mermaid-plugin-newsprint.css +208 -0
- package/src/renderer/editor/plugins/mermaid-plugin.css +111 -0
- package/src/renderer/editor/plugins/mermaid-plugin.ts +679 -0
- package/src/renderer/env.d.ts +7 -0
- package/src/renderer/index.html +18 -0
- package/src/renderer/main.ts +303 -0
- package/src/renderer/themes/base.css +509 -0
- package/src/renderer/themes/theme-manager.ts +40 -0
- package/themes/README.md +280 -0
- package/themes/elegant.css +664 -0
- package/themes/guizang.css +732 -0
- package/tsconfig.json +14 -0
- package/tsconfig.main.json +11 -0
- package/tsconfig.preload.json +11 -0
- package/tsconfig.renderer.json +12 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { contextBridge, ipcRenderer, webUtils } from 'electron'
|
|
2
|
+
|
|
3
|
+
export interface ElectronAPI {
|
|
4
|
+
openFile: () => Promise<{ path: string; content: string } | null>
|
|
5
|
+
openFilePath: (path: string) => Promise<{ path: string; content: string } | null>
|
|
6
|
+
saveFile: (content: string) => Promise<boolean>
|
|
7
|
+
saveFileAs: (content: string) => Promise<boolean>
|
|
8
|
+
exportPDF: () => Promise<boolean>
|
|
9
|
+
exportHTML: (html: string) => Promise<boolean>
|
|
10
|
+
newSlides: () => Promise<string | null>
|
|
11
|
+
openAsSlides: (content: string) => Promise<boolean>
|
|
12
|
+
loadCustomTheme: () => Promise<{ name: string; css: string } | null>
|
|
13
|
+
loadThemeCSS: (fileName: string) => Promise<string | null>
|
|
14
|
+
getPathForFile: (file: File) => string
|
|
15
|
+
openExternal: (url: string) => void
|
|
16
|
+
onFileChanged: (callback: (content: string) => void) => void
|
|
17
|
+
onNewFile: (callback: () => void) => void
|
|
18
|
+
onFileOpened: (callback: (data: { path: string; content: string }) => void) => void
|
|
19
|
+
onMenuOpen: (callback: () => void) => void
|
|
20
|
+
onMenuSave: (callback: () => void) => void
|
|
21
|
+
onMenuSaveAs: (callback: () => void) => void
|
|
22
|
+
onMenuExportPDF: (callback: () => void) => void
|
|
23
|
+
onMenuExportHTML: (callback: () => void) => void
|
|
24
|
+
onMenuNewSlides: (callback: () => void) => void
|
|
25
|
+
onMenuOpenAsSlides: (callback: () => void) => void
|
|
26
|
+
onNewSlidesContent: (callback: (content: string) => void) => void
|
|
27
|
+
onSetTheme: (callback: (theme: string) => void) => void
|
|
28
|
+
onSetCustomCSS: (callback: (css: string) => void) => void
|
|
29
|
+
exportSlides: (content: string) => Promise<boolean>
|
|
30
|
+
onMenuExportSlides: (callback: () => void) => void
|
|
31
|
+
onAgentActivity: (callback: (state: string) => void) => void
|
|
32
|
+
registerPlugins: (plugins: Array<{ id: string; name: string; enabled: boolean }>) => Promise<boolean>
|
|
33
|
+
syncPluginState: (id: string, enabled: boolean) => Promise<void>
|
|
34
|
+
onMenuTogglePlugin: (callback: (id: string) => void) => void
|
|
35
|
+
onMenuImportTheme: (callback: () => void) => void
|
|
36
|
+
exportFile: (dataUrl: string, defaultName: string) => Promise<boolean>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
contextBridge.exposeInMainWorld('electronAPI', {
|
|
40
|
+
openFile: () => ipcRenderer.invoke('open-file'),
|
|
41
|
+
openFilePath: (path: string) => ipcRenderer.invoke('open-file-path', path),
|
|
42
|
+
saveFile: (content: string) => ipcRenderer.invoke('save-file', content),
|
|
43
|
+
saveFileAs: (content: string) => ipcRenderer.invoke('save-file-as', content),
|
|
44
|
+
exportPDF: () => ipcRenderer.invoke('export-pdf'),
|
|
45
|
+
exportHTML: (html: string) => ipcRenderer.invoke('export-html', html),
|
|
46
|
+
exportSlides: (content: string) => ipcRenderer.invoke('export-slides', content),
|
|
47
|
+
newSlides: () => ipcRenderer.invoke('new-slides'),
|
|
48
|
+
openAsSlides: (content: string) => ipcRenderer.invoke('open-as-slides', content),
|
|
49
|
+
loadCustomTheme: () => ipcRenderer.invoke('load-custom-theme'),
|
|
50
|
+
loadThemeCSS: (fileName: string) => ipcRenderer.invoke('load-theme-css', fileName),
|
|
51
|
+
getPathForFile: (file: File) => webUtils.getPathForFile(file),
|
|
52
|
+
openExternal: (url: string) => ipcRenderer.send('open-external', url),
|
|
53
|
+
onFileChanged: (callback: (content: string) => void) => {
|
|
54
|
+
ipcRenderer.on('file-changed', (_event, content) => callback(content))
|
|
55
|
+
},
|
|
56
|
+
onNewFile: (callback: () => void) => {
|
|
57
|
+
ipcRenderer.on('new-file', () => callback())
|
|
58
|
+
},
|
|
59
|
+
onFileOpened: (callback: (data: { path: string; content: string }) => void) => {
|
|
60
|
+
ipcRenderer.on('file-opened', (_event, data) => callback(data))
|
|
61
|
+
},
|
|
62
|
+
onMenuOpen: (callback: () => void) => {
|
|
63
|
+
ipcRenderer.on('menu-open', () => callback())
|
|
64
|
+
},
|
|
65
|
+
onMenuSave: (callback: () => void) => {
|
|
66
|
+
ipcRenderer.on('menu-save', () => callback())
|
|
67
|
+
},
|
|
68
|
+
onMenuSaveAs: (callback: () => void) => {
|
|
69
|
+
ipcRenderer.on('menu-save-as', () => callback())
|
|
70
|
+
},
|
|
71
|
+
onMenuExportPDF: (callback: () => void) => {
|
|
72
|
+
ipcRenderer.on('menu-export-pdf', () => callback())
|
|
73
|
+
},
|
|
74
|
+
onMenuExportHTML: (callback: () => void) => {
|
|
75
|
+
ipcRenderer.on('menu-export-html', () => callback())
|
|
76
|
+
},
|
|
77
|
+
onMenuNewSlides: (callback: () => void) => {
|
|
78
|
+
ipcRenderer.on('menu-new-slides', () => callback())
|
|
79
|
+
},
|
|
80
|
+
onMenuOpenAsSlides: (callback: () => void) => {
|
|
81
|
+
ipcRenderer.on('menu-open-as-slides', () => callback())
|
|
82
|
+
},
|
|
83
|
+
onNewSlidesContent: (callback: (content: string) => void) => {
|
|
84
|
+
ipcRenderer.on('new-slides-content', (_event, content) => callback(content))
|
|
85
|
+
},
|
|
86
|
+
onSetTheme: (callback: (theme: string) => void) => {
|
|
87
|
+
ipcRenderer.on('set-theme', (_event, theme) => callback(theme))
|
|
88
|
+
},
|
|
89
|
+
onSetCustomCSS: (callback: (css: string) => void) => {
|
|
90
|
+
ipcRenderer.on('set-custom-css', (_event, css) => callback(css))
|
|
91
|
+
},
|
|
92
|
+
onMenuImportTheme: (callback: () => void) => {
|
|
93
|
+
ipcRenderer.on('menu-import-theme', () => callback())
|
|
94
|
+
},
|
|
95
|
+
onMenuExportSlides: (callback: () => void) => {
|
|
96
|
+
ipcRenderer.on('menu-export-slides', () => callback())
|
|
97
|
+
},
|
|
98
|
+
onAgentActivity: (callback: (state: string) => void) => {
|
|
99
|
+
ipcRenderer.on('agent-activity', (_event, state) => callback(state))
|
|
100
|
+
},
|
|
101
|
+
registerPlugins: (plugins: Array<{ id: string; name: string; enabled: boolean }>) =>
|
|
102
|
+
ipcRenderer.invoke('register-plugins', plugins),
|
|
103
|
+
syncPluginState: (id: string, enabled: boolean) =>
|
|
104
|
+
ipcRenderer.invoke('sync-plugin-state', id, enabled),
|
|
105
|
+
onMenuTogglePlugin: (callback: (id: string) => void) => {
|
|
106
|
+
ipcRenderer.on('menu-toggle-plugin', (_event, id) => callback(id))
|
|
107
|
+
},
|
|
108
|
+
exportFile: (dataUrl: string, defaultName: string) =>
|
|
109
|
+
ipcRenderer.invoke('save-export-file', dataUrl, defaultName),
|
|
110
|
+
} satisfies ElectronAPI)
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { Editor, rootCtx, defaultValueCtx, editorViewCtx, serializerCtx, remarkPluginsCtx, nodeViewCtx, schemaCtx } from '@milkdown/kit/core'
|
|
2
|
+
import { DOMSerializer } from '@milkdown/kit/prose/model'
|
|
3
|
+
import { EditorView } from '@milkdown/kit/prose/view'
|
|
4
|
+
import remarkBreaks from 'remark-breaks'
|
|
5
|
+
import { commonmark } from '@milkdown/kit/preset/commonmark'
|
|
6
|
+
import { gfm } from '@milkdown/kit/preset/gfm'
|
|
7
|
+
import { history } from '@milkdown/kit/plugin/history'
|
|
8
|
+
import { listener, listenerCtx } from '@milkdown/kit/plugin/listener'
|
|
9
|
+
import { clipboard } from '@milkdown/kit/plugin/clipboard'
|
|
10
|
+
import { replaceAll } from '@milkdown/kit/utils'
|
|
11
|
+
import { htmlView } from './html-view'
|
|
12
|
+
import { getAllPluginModules } from './plugins'
|
|
13
|
+
|
|
14
|
+
import '@milkdown/kit/prose/view/style/prosemirror.css'
|
|
15
|
+
|
|
16
|
+
let editorInstance: Editor | null = null
|
|
17
|
+
|
|
18
|
+
const inlineStyles: Record<string, string> = {
|
|
19
|
+
'h1': 'font-size:1.8em;font-weight:700;margin:1em 0 .5em;padding-bottom:.3em;border-bottom:1px solid #eee;',
|
|
20
|
+
'h2': 'font-size:1.4em;font-weight:600;margin:1em 0 .5em;padding-bottom:.25em;border-bottom:1px solid #eee;',
|
|
21
|
+
'h3': 'font-size:1.2em;font-weight:600;margin:.8em 0 .4em;',
|
|
22
|
+
'h4': 'font-weight:600;margin:.8em 0 .4em;',
|
|
23
|
+
'h5': 'font-weight:600;margin:.8em 0 .4em;',
|
|
24
|
+
'h6': 'font-weight:600;margin:.8em 0 .4em;',
|
|
25
|
+
'p': 'margin:.5em 0;line-height:1.75;',
|
|
26
|
+
'strong': 'font-weight:600;',
|
|
27
|
+
'a': 'color:#0969da;text-decoration:none;',
|
|
28
|
+
'code': 'background:rgba(175,184,193,0.2);padding:2px 6px;border-radius:3px;font-size:.875em;font-family:Menlo,Monaco,monospace;',
|
|
29
|
+
'pre': 'background:#f6f8fa;padding:16px;border-radius:6px;overflow-x:auto;margin:1em 0;',
|
|
30
|
+
'blockquote': 'border-left:4px solid #ddd;padding-left:16px;margin:1em 0;color:#666;',
|
|
31
|
+
'ul': 'padding-left:24px;margin:.5em 0;',
|
|
32
|
+
'ol': 'padding-left:24px;margin:.5em 0;',
|
|
33
|
+
'li': 'margin:.25em 0;',
|
|
34
|
+
'table': 'border-collapse:collapse;width:100%;margin:1em 0;',
|
|
35
|
+
'th': 'border:1px solid #ddd;padding:8px 12px;text-align:left;font-weight:600;background:#f6f8fa;',
|
|
36
|
+
'td': 'border:1px solid #ddd;padding:8px 12px;text-align:left;',
|
|
37
|
+
'hr': 'border:none;border-top:2px solid #ddd;margin:2em 0;',
|
|
38
|
+
'img': 'max-width:100%;',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function enhanceClipboard(e: ClipboardEvent): void {
|
|
42
|
+
const html = e.clipboardData?.getData('text/html')
|
|
43
|
+
if (!html) return
|
|
44
|
+
|
|
45
|
+
const doc = new DOMParser().parseFromString(html, 'text/html')
|
|
46
|
+
|
|
47
|
+
for (const [tag, style] of Object.entries(inlineStyles)) {
|
|
48
|
+
doc.querySelectorAll(tag).forEach((el) => {
|
|
49
|
+
;(el as HTMLElement).setAttribute('style', style)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
doc.querySelectorAll('pre code').forEach((el) => {
|
|
54
|
+
;(el as HTMLElement).setAttribute('style', 'background:none;padding:0;font-size:.875em;line-height:1.6;font-family:Menlo,Monaco,monospace;')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
doc.querySelectorAll('.math-inline').forEach((el) => {
|
|
58
|
+
;(el as HTMLElement).setAttribute('style', 'display:inline;padding:2px 4px;border-radius:3px;background:rgba(175,184,193,0.2);')
|
|
59
|
+
})
|
|
60
|
+
doc.querySelectorAll('.math-block').forEach((el) => {
|
|
61
|
+
;(el as HTMLElement).setAttribute('style', 'display:block;padding:16px;margin:1em 0;border-radius:6px;background:#f6f8fa;text-align:center;overflow-x:auto;')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
doc.querySelectorAll('.mermaid-block').forEach((el) => {
|
|
65
|
+
;(el as HTMLElement).setAttribute('style', 'display:block;padding:16px;margin:1em 0;border-radius:6px;background:#f6f8fa;border:1px solid #d0d7de;')
|
|
66
|
+
})
|
|
67
|
+
doc.querySelectorAll('.mermaid-preview svg').forEach((el) => {
|
|
68
|
+
;(el as HTMLElement).setAttribute('style', 'max-width:100%;height:auto;')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
e.clipboardData?.setData('text/html', doc.body.innerHTML)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const defaultContent = `# Welcome to ColaMD\n\nStart typing here...\n`
|
|
75
|
+
|
|
76
|
+
export async function createEditor(
|
|
77
|
+
rootId: string,
|
|
78
|
+
onChange?: (markdown: string) => void
|
|
79
|
+
): Promise<Editor> {
|
|
80
|
+
const root = document.getElementById(rootId)
|
|
81
|
+
if (!root) throw new Error(`Element #${rootId} not found`)
|
|
82
|
+
|
|
83
|
+
const pluginModules = getAllPluginModules()
|
|
84
|
+
|
|
85
|
+
let builder = Editor.make()
|
|
86
|
+
.config((ctx) => {
|
|
87
|
+
ctx.set(rootCtx, root)
|
|
88
|
+
ctx.set(defaultValueCtx, defaultContent)
|
|
89
|
+
ctx.set(remarkPluginsCtx, [
|
|
90
|
+
...pluginModules.map((m) => m.info.remarkPlugin),
|
|
91
|
+
{ plugin: remarkBreaks, options: undefined },
|
|
92
|
+
])
|
|
93
|
+
if (onChange) {
|
|
94
|
+
ctx.get(listenerCtx).markdownUpdated((_ctx, markdown) => {
|
|
95
|
+
onChange(markdown)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
.use(commonmark)
|
|
100
|
+
.use(gfm)
|
|
101
|
+
.use(history)
|
|
102
|
+
.use(listener)
|
|
103
|
+
.use(clipboard)
|
|
104
|
+
.use(htmlView)
|
|
105
|
+
|
|
106
|
+
for (const mod of pluginModules) {
|
|
107
|
+
for (const p of mod.milkdownPlugins) {
|
|
108
|
+
builder = builder.use(p)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
editorInstance = await builder.create()
|
|
113
|
+
|
|
114
|
+
editorInstance.action((ctx) => {
|
|
115
|
+
const nvs = ctx.get(nodeViewCtx)
|
|
116
|
+
const schema = ctx.get(schemaCtx)
|
|
117
|
+
const fixed = nvs.map((nv: any, i: number) => {
|
|
118
|
+
if (nv[0] != null) return nv
|
|
119
|
+
const viewFn = nv[1]
|
|
120
|
+
const fallbackNames = ['math_inline', 'math_block', 'mermaid_block']
|
|
121
|
+
const name = fallbackNames[i - 1]
|
|
122
|
+
if (name && schema.nodes[name]) {
|
|
123
|
+
return [name, viewFn]
|
|
124
|
+
}
|
|
125
|
+
return nv
|
|
126
|
+
})
|
|
127
|
+
ctx.set(nodeViewCtx, fixed)
|
|
128
|
+
|
|
129
|
+
const oldView = ctx.get(editorViewCtx)
|
|
130
|
+
const rootEl = ctx.get(rootCtx)
|
|
131
|
+
const nodeViews = Object.fromEntries(fixed)
|
|
132
|
+
const newView = new EditorView(rootEl, {
|
|
133
|
+
state: oldView.state,
|
|
134
|
+
nodeViews,
|
|
135
|
+
dispatchTransaction: oldView.props.dispatchTransaction!,
|
|
136
|
+
})
|
|
137
|
+
oldView.destroy()
|
|
138
|
+
rootEl.appendChild(newView.dom)
|
|
139
|
+
ctx.set(editorViewCtx, newView)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
root.addEventListener('copy', enhanceClipboard)
|
|
143
|
+
root.addEventListener('cut', enhanceClipboard)
|
|
144
|
+
|
|
145
|
+
root.addEventListener('click', (e) => {
|
|
146
|
+
if (!(e.metaKey || e.ctrlKey)) return
|
|
147
|
+
const link = (e.target as HTMLElement).closest('a')
|
|
148
|
+
if (!link) return
|
|
149
|
+
const href = link.getAttribute('href')
|
|
150
|
+
if (href) {
|
|
151
|
+
e.preventDefault()
|
|
152
|
+
window.electronAPI.openExternal(href)
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
return editorInstance
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function getMarkdown(): string {
|
|
160
|
+
if (!editorInstance) return ''
|
|
161
|
+
let markdown = ''
|
|
162
|
+
editorInstance.action((ctx) => {
|
|
163
|
+
const serializer = ctx.get(serializerCtx)
|
|
164
|
+
const view = ctx.get(editorViewCtx)
|
|
165
|
+
markdown = serializer(view.state.doc)
|
|
166
|
+
})
|
|
167
|
+
return markdown
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function getHTML(): string {
|
|
171
|
+
if (!editorInstance) return ''
|
|
172
|
+
let html = ''
|
|
173
|
+
editorInstance.action((ctx) => {
|
|
174
|
+
const view = ctx.get(editorViewCtx)
|
|
175
|
+
const div = document.createElement('div')
|
|
176
|
+
const fragment = DOMSerializer.fromSchema(view.state.schema).serializeFragment(view.state.doc.content)
|
|
177
|
+
div.appendChild(fragment)
|
|
178
|
+
html = div.innerHTML
|
|
179
|
+
})
|
|
180
|
+
return html
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function setMarkdown(content: string): void {
|
|
184
|
+
if (!editorInstance) return
|
|
185
|
+
editorInstance.action(replaceAll(content))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function togglePluginMode(nodeTypes: string[], mode: 'rendered' | 'raw'): void {
|
|
189
|
+
if (!editorInstance) return
|
|
190
|
+
editorInstance.action((ctx) => {
|
|
191
|
+
const view = ctx.get(editorViewCtx)
|
|
192
|
+
const { state, dispatch } = view
|
|
193
|
+
const tr = state.tr
|
|
194
|
+
const nodeTypeSet = new Set(nodeTypes)
|
|
195
|
+
|
|
196
|
+
state.doc.descendants((node, pos) => {
|
|
197
|
+
if (nodeTypeSet.has(node.type.name)) {
|
|
198
|
+
tr.setNodeMarkup(pos, undefined, { ...node.attrs, mode })
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
dispatch(tr)
|
|
203
|
+
})
|
|
204
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { $view } from '@milkdown/kit/utils'
|
|
2
|
+
import { htmlSchema } from '@milkdown/kit/preset/commonmark'
|
|
3
|
+
import type { NodeViewConstructor } from '@milkdown/kit/prose/view'
|
|
4
|
+
|
|
5
|
+
export const htmlView = $view(htmlSchema.node, (): NodeViewConstructor => {
|
|
6
|
+
return (node) => {
|
|
7
|
+
const dom = document.createElement('span')
|
|
8
|
+
dom.classList.add('milkdown-html-inline')
|
|
9
|
+
dom.innerHTML = node.attrs.value as string
|
|
10
|
+
return {
|
|
11
|
+
dom,
|
|
12
|
+
stopEvent: () => true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { MilkdownPlugin } from '@milkdown/ctx'
|
|
2
|
+
import type { Plugin } from 'unified'
|
|
3
|
+
|
|
4
|
+
export interface ExportCapability {
|
|
5
|
+
label: string
|
|
6
|
+
defaultName: string
|
|
7
|
+
filter: { name: string; extensions: string[] }
|
|
8
|
+
execute: (element: HTMLElement) => Promise<string | null>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RendererPlugin {
|
|
12
|
+
id: string
|
|
13
|
+
name: string
|
|
14
|
+
enabled: boolean
|
|
15
|
+
remarkPlugin: { plugin: Plugin; options?: any }
|
|
16
|
+
nodeTypes: string[]
|
|
17
|
+
onInit?: () => void
|
|
18
|
+
onThemeChange?: (theme: string) => void
|
|
19
|
+
exportCapabilities?: ExportCapability[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PluginModule {
|
|
23
|
+
info: RendererPlugin
|
|
24
|
+
milkdownPlugins: MilkdownPlugin[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const modules: PluginModule[] = []
|
|
28
|
+
|
|
29
|
+
export function registerPluginModule(m: PluginModule): void {
|
|
30
|
+
modules.push(m)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getAllPluginModules(): PluginModule[] {
|
|
34
|
+
return modules
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getAllPlugins(): RendererPlugin[] {
|
|
38
|
+
return modules.map(m => m.info)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getEnabledPlugins(): RendererPlugin[] {
|
|
42
|
+
return modules.filter(m => m.info.enabled).map(m => m.info)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getPlugin(id: string): RendererPlugin | undefined {
|
|
46
|
+
return modules.find(m => m.info.id === id)?.info
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function togglePlugin(id: string): void {
|
|
50
|
+
const m = modules.find(m => m.info.id === id)
|
|
51
|
+
if (m) m.info.enabled = !m.info.enabled
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function findPluginBySelector(selector: string): { plugin: RendererPlugin; capability: ExportCapability } | undefined {
|
|
55
|
+
for (const m of modules) {
|
|
56
|
+
if (!m.info.enabled || !m.info.exportCapabilities?.length) continue
|
|
57
|
+
for (const nodeType of m.info.nodeTypes) {
|
|
58
|
+
if (selector.includes(nodeType.replace(/_/g, '-'))) {
|
|
59
|
+
return { plugin: m.info, capability: m.info.exportCapabilities[0] }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return undefined
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function findExportCapabilities(selector: string): ExportCapability[] {
|
|
67
|
+
for (const m of modules) {
|
|
68
|
+
if (!m.info.enabled || !m.info.exportCapabilities?.length) continue
|
|
69
|
+
for (const nodeType of m.info.nodeTypes) {
|
|
70
|
+
if (selector.includes(nodeType.replace(/_/g, '-'))) {
|
|
71
|
+
return m.info.exportCapabilities
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return []
|
|
76
|
+
}
|