@jvs-milkdown/crepe 1.2.24 → 1.2.26
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/lib/cjs/builder.js +13 -13
- package/lib/cjs/builder.js.map +1 -1
- package/lib/cjs/index.js +414 -7
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/builder.js +13 -13
- package/lib/esm/builder.js.map +1 -1
- package/lib/esm/index.js +415 -8
- package/lib/esm/index.js.map +1 -1
- package/lib/theme/common/toolbar.css +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/core/builder.d.ts +1 -1
- package/lib/types/core/builder.d.ts.map +1 -1
- package/lib/types/feature/fixed-toolbar/config.d.ts.map +1 -1
- package/lib/types/feature/fixed-toolbar/index.d.ts +2 -0
- package/lib/types/feature/fixed-toolbar/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/core/builder.ts +4 -1
- package/src/default-config/default-config.spec.ts +15 -0
- package/src/feature/fixed-toolbar/config.ts +482 -3
- package/src/feature/fixed-toolbar/index.ts +17 -6
- package/src/theme/common/toolbar.css +1 -1
|
@@ -3,8 +3,8 @@ import { type ListenerManager } from '@jvs-milkdown/kit/plugin/listener';
|
|
|
3
3
|
import type { CrepeFeatureConfig } from '../feature';
|
|
4
4
|
import type { DefineFeature } from '../feature/shared';
|
|
5
5
|
import { CrepeFeature } from '../feature';
|
|
6
|
-
import { type CrepeTranslations } from './locale';
|
|
7
6
|
import { type ViewMenuState } from '../feature/fixed-toolbar/view-menu-state';
|
|
7
|
+
import { type CrepeTranslations } from './locale';
|
|
8
8
|
export interface CrepeBuilderConfig {
|
|
9
9
|
root?: Node | string | null;
|
|
10
10
|
defaultValue?: DefaultValue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/core/builder.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EAEjB,MAAM,EAKP,MAAM,wBAAwB,CAAA;AAI/B,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAA;AAO1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/core/builder.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EAEjB,MAAM,EAKP,MAAM,wBAAwB,CAAA;AAI/B,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,mCAAmC,CAAA;AAO1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,0CAA0C,CAAA;AAEjD,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAU7D,MAAM,WAAW,kBAAkB;IAIjC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IAG3B,YAAY,CAAC,EAAE,YAAY,CAAA;IAG3B,MAAM,CAAC,EAAE,MAAM,CAAA;IAGf,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAA;CAC1D;AAID,qBAAa,YAAY;;gBAYX,EACV,IAAI,EACJ,YAAiB,EACjB,MAAgB,EAChB,YAAY,GACb,GAAE,kBAAuB;IA0H1B,UAAU,EAAE;QACV,CAAC,CAAC,SAAS,YAAY,EACrB,OAAO,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAC7C,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC7B,YAAY,CAAA;QACf,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,CAAA;KACzD,CAGA;IAGD,MAAM,wBAEL;IAGD,OAAO,wBAEN;IAGD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAGD,IAAI,QAAQ,YAEX;IAGD,WAAW,GAAI,OAAO,OAAO,UAW5B;IAGD,WAAW,eAEV;IAGD,QAAQ,GAAI,aAAa,MAAM,EAAE,aAAa,MAAM,UAMnD;IAGD,QAAQ,aAMP;IAGD,EAAE,GAAI,IAAI,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,UAavC;IAGD,IAAI,cAAc,YAejB;IAGD,iBAAiB,GAAI,SAAS,OAAO,UAcpC;IAGD,gBAAgB,YAwBf;IAGD,gBAAgB,GAAI,OAAO,OAAO,CAAC,aAAa,CAAC,UAchD;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/feature/fixed-toolbar/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAkChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAqDxD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,EAClC,OAAO,CAAC,EAAE,yBAAyB,EACnC,GAAG,CAAC,EAAE,GAAG;;;;;;;;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/feature/fixed-toolbar/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAkChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAqDxD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,EAClC,OAAO,CAAC,EAAE,yBAAyB,EACnC,GAAG,CAAC,EAAE,GAAG;;;;;;;;IAyiBV"}
|
|
@@ -29,8 +29,10 @@ export interface FixedToolbarConfig {
|
|
|
29
29
|
showHistory?: boolean;
|
|
30
30
|
showExport?: boolean;
|
|
31
31
|
onExport?: (markdown: string, ctx: Ctx) => void;
|
|
32
|
+
exportItems?: ('markdown' | 'word' | 'pdf')[];
|
|
32
33
|
showImport?: boolean;
|
|
33
34
|
onImport?: (replaceContent: (markdown: string) => void, ctx: Ctx) => void;
|
|
35
|
+
importItems?: ('markdown' | 'word' | 'pdf')[];
|
|
34
36
|
useLocalStorage?: boolean;
|
|
35
37
|
id?: string;
|
|
36
38
|
outlineVisible?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/feature/fixed-toolbar/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAIhD,OAAO,EAAU,SAAS,EAAiB,MAAM,+BAA+B,CAAA;AAehF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAUpD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/feature/fixed-toolbar/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAIhD,OAAO,EAAU,SAAS,EAAiB,MAAM,+BAA+B,CAAA;AAehF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAUpD,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;IAC3D,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAClC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/C,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE;QACb,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,MAAM,CAAC,EAAE,OAAO,CAAA;KACjB,CAAA;IACD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC/C,WAAW,CAAC,EAAE,CAAC,UAAU,GAAG,MAAM,GAAG,KAAK,CAAC,EAAE,CAAA;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IACzE,WAAW,CAAC,EAAE,CAAC,UAAU,GAAG,MAAM,GAAG,KAAK,CAAC,EAAE,CAAA;IAC7C,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;AAEnE,eAAO,MAAM,kBAAkB,0FAG9B,CAAA;AAED,eAAO,MAAM,eAAe,gBAA0C,CAAA;AAoXtE,eAAO,MAAM,kBAAkB,sCAK7B,CAAA;AAEF,eAAO,MAAM,YAAY,EAAE,aAAa,CAAC,yBAAyB,CA6BjE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jvs-milkdown/crepe",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.26",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"crepe",
|
|
6
6
|
"editor",
|
|
@@ -107,9 +107,9 @@
|
|
|
107
107
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
108
108
|
"@codemirror/view": "^6.26.0",
|
|
109
109
|
"@floating-ui/dom": "^1.7.6",
|
|
110
|
-
"@jvs-milkdown/kit": "^1.2.
|
|
111
|
-
"@jvs-milkdown/prose": "^1.2.
|
|
112
|
-
"@jvs-milkdown/utils": "^1.2.
|
|
110
|
+
"@jvs-milkdown/kit": "^1.2.26",
|
|
111
|
+
"@jvs-milkdown/prose": "^1.2.26",
|
|
112
|
+
"@jvs-milkdown/utils": "^1.2.26",
|
|
113
113
|
"@types/lodash-es": "^4.17.12",
|
|
114
114
|
"clsx": "^2.0.0",
|
|
115
115
|
"codemirror": "^6.0.1",
|
package/src/core/builder.ts
CHANGED
|
@@ -27,6 +27,10 @@ import type { DefineFeature } from '../feature/shared'
|
|
|
27
27
|
|
|
28
28
|
import { CrepeFeature } from '../feature'
|
|
29
29
|
import { attachmentConfig } from '../feature/attachment/config'
|
|
30
|
+
import {
|
|
31
|
+
viewMenuStateCtx,
|
|
32
|
+
type ViewMenuState,
|
|
33
|
+
} from '../feature/fixed-toolbar/view-menu-state'
|
|
30
34
|
import { inlineDiffApiCtx } from '../feature/inline-diff/config'
|
|
31
35
|
import { zhCN, enUS, type CrepeTranslations } from './locale'
|
|
32
36
|
import {
|
|
@@ -36,7 +40,6 @@ import {
|
|
|
36
40
|
translationsCtx,
|
|
37
41
|
useCrepeFeatures,
|
|
38
42
|
} from './slice'
|
|
39
|
-
import { viewMenuStateCtx, type ViewMenuState } from '../feature/fixed-toolbar/view-menu-state'
|
|
40
43
|
|
|
41
44
|
/// The crepe builder configuration.
|
|
42
45
|
export interface CrepeBuilderConfig {
|
|
@@ -25,3 +25,18 @@ test('should use custom config to override the default config', () => {
|
|
|
25
25
|
mockCppLanguageDescription,
|
|
26
26
|
])
|
|
27
27
|
})
|
|
28
|
+
|
|
29
|
+
test('should apply exportItems and importItems config to FixedToolbar', () => {
|
|
30
|
+
const myConfig = applyConfig({
|
|
31
|
+
[CrepeFeature.FixedToolbar]: {
|
|
32
|
+
exportItems: ['markdown', 'word'],
|
|
33
|
+
importItems: ['markdown'],
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
expect(myConfig[CrepeFeature.FixedToolbar]?.exportItems).toEqual([
|
|
38
|
+
'markdown',
|
|
39
|
+
'word',
|
|
40
|
+
])
|
|
41
|
+
expect(myConfig[CrepeFeature.FixedToolbar]?.importItems).toEqual(['markdown'])
|
|
42
|
+
})
|
|
@@ -3,7 +3,7 @@ import type { Node as ProseNode } from '@jvs-milkdown/kit/prose/model'
|
|
|
3
3
|
|
|
4
4
|
import { imageBlockSchema } from '@jvs-milkdown/kit/component/image-block'
|
|
5
5
|
import { toggleLinkCommand } from '@jvs-milkdown/kit/component/link-tooltip'
|
|
6
|
-
import { commandsCtx, editorViewCtx } from '@jvs-milkdown/kit/core'
|
|
6
|
+
import { commandsCtx, editorViewCtx, rootCtx } from '@jvs-milkdown/kit/core'
|
|
7
7
|
import {
|
|
8
8
|
addBlockTypeCommand,
|
|
9
9
|
blockquoteSchema,
|
|
@@ -564,7 +564,18 @@ export function buildDefaultFixedToolbar(
|
|
|
564
564
|
active: () => false,
|
|
565
565
|
onRun: (ctx) => {
|
|
566
566
|
const markdown = getMarkdown()(ctx)
|
|
567
|
-
|
|
567
|
+
const view = ctx.get(editorViewCtx)
|
|
568
|
+
const root = ctx.get(rootCtx) as HTMLElement
|
|
569
|
+
const rootNode = view.dom.getRootNode() as ShadowRoot | Document
|
|
570
|
+
|
|
571
|
+
if (_config?.exportItems && _config.exportItems.length > 0) {
|
|
572
|
+
const exportItems = _config.exportItems
|
|
573
|
+
if (exportItems.length === 1) {
|
|
574
|
+
handleDirectExport(exportItems[0]!, markdown, view, root)
|
|
575
|
+
} else {
|
|
576
|
+
showDownloadPopover(rootNode, root, view, markdown, exportItems)
|
|
577
|
+
}
|
|
578
|
+
} else if (_config?.onExport) {
|
|
568
579
|
_config.onExport(markdown, ctx)
|
|
569
580
|
} else {
|
|
570
581
|
const blob = new Blob([markdown], {
|
|
@@ -587,7 +598,18 @@ export function buildDefaultFixedToolbar(
|
|
|
587
598
|
icon: importIcon,
|
|
588
599
|
active: () => false,
|
|
589
600
|
onRun: (ctx) => {
|
|
590
|
-
|
|
601
|
+
const view = ctx.get(editorViewCtx)
|
|
602
|
+
const root = ctx.get(rootCtx) as HTMLElement
|
|
603
|
+
const rootNode = view.dom.getRootNode() as ShadowRoot | Document
|
|
604
|
+
|
|
605
|
+
if (_config?.importItems && _config.importItems.length > 0) {
|
|
606
|
+
const importItems = _config.importItems
|
|
607
|
+
if (importItems.length === 1) {
|
|
608
|
+
handleDirectImport(importItems[0]!, root, ctx)
|
|
609
|
+
} else {
|
|
610
|
+
showImportPopover(rootNode, root, ctx, importItems)
|
|
611
|
+
}
|
|
612
|
+
} else if (_config?.onImport) {
|
|
591
613
|
_config.onImport((markdown) => replaceAll(markdown)(ctx), ctx)
|
|
592
614
|
} else {
|
|
593
615
|
const input = document.createElement('input')
|
|
@@ -622,3 +644,460 @@ export function buildDefaultFixedToolbar(
|
|
|
622
644
|
|
|
623
645
|
return builder.build()
|
|
624
646
|
}
|
|
647
|
+
|
|
648
|
+
const activeDownloadPopovers = new WeakMap<HTMLElement, HTMLElement>()
|
|
649
|
+
const activeImportPopovers = new WeakMap<HTMLElement, HTMLElement>()
|
|
650
|
+
|
|
651
|
+
const ensureStyles = (rootNode: ShadowRoot | Document) => {
|
|
652
|
+
const target = rootNode instanceof ShadowRoot ? rootNode : document.head
|
|
653
|
+
if (target.querySelector('#download-popover-styles')) return
|
|
654
|
+
|
|
655
|
+
const styleEl = document.createElement('style')
|
|
656
|
+
styleEl.id = 'download-popover-styles'
|
|
657
|
+
styleEl.textContent = `
|
|
658
|
+
.download-popover, .import-popover {
|
|
659
|
+
position: fixed;
|
|
660
|
+
z-index: 10000;
|
|
661
|
+
width: 140px;
|
|
662
|
+
padding: 6px 0;
|
|
663
|
+
display: flex;
|
|
664
|
+
flex-direction: column;
|
|
665
|
+
background-color: var(--crepe-color-surface, #ffffff);
|
|
666
|
+
border: 1px solid var(--crepe-color-outline-variant, color-mix(in srgb, var(--crepe-color-outline), transparent 80%));
|
|
667
|
+
border-radius: 8px;
|
|
668
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
669
|
+
opacity: 0;
|
|
670
|
+
transform: translateY(-8px);
|
|
671
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
672
|
+
pointer-events: none;
|
|
673
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
674
|
+
}
|
|
675
|
+
.download-popover.show, .import-popover.show {
|
|
676
|
+
opacity: 1;
|
|
677
|
+
transform: translateY(0);
|
|
678
|
+
pointer-events: auto;
|
|
679
|
+
}
|
|
680
|
+
.download-popover-item, .import-popover-item {
|
|
681
|
+
cursor: pointer;
|
|
682
|
+
padding: 8px 14px;
|
|
683
|
+
display: flex;
|
|
684
|
+
align-items: center;
|
|
685
|
+
gap: 8px;
|
|
686
|
+
font-size: 13px;
|
|
687
|
+
font-weight: 500;
|
|
688
|
+
color: var(--crepe-color-primary, #363B4C);
|
|
689
|
+
transition: background-color 0.2s;
|
|
690
|
+
user-select: none;
|
|
691
|
+
}
|
|
692
|
+
.download-popover-item:hover, .import-popover-item:hover {
|
|
693
|
+
background-color: var(--crepe-color-hover, #f5f5f5);
|
|
694
|
+
}
|
|
695
|
+
.download-popover-item-icon, .import-popover-item-icon {
|
|
696
|
+
display: flex;
|
|
697
|
+
align-items: center;
|
|
698
|
+
justify-content: center;
|
|
699
|
+
width: 14px;
|
|
700
|
+
height: 14px;
|
|
701
|
+
color: var(--crepe-color-primary, #363B4C);
|
|
702
|
+
opacity: 0.8;
|
|
703
|
+
}
|
|
704
|
+
`
|
|
705
|
+
target.appendChild(styleEl)
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function handleDirectExport(
|
|
709
|
+
type: 'markdown' | 'word' | 'pdf',
|
|
710
|
+
markdown: string,
|
|
711
|
+
view: any,
|
|
712
|
+
root: HTMLElement
|
|
713
|
+
) {
|
|
714
|
+
if (type === 'markdown') {
|
|
715
|
+
const blob = new Blob([markdown], { type: 'text/markdown;charset=utf-8;' })
|
|
716
|
+
const url = URL.createObjectURL(blob)
|
|
717
|
+
const link = document.createElement('a')
|
|
718
|
+
link.href = url
|
|
719
|
+
link.download = 'document.md'
|
|
720
|
+
link.click()
|
|
721
|
+
URL.revokeObjectURL(url)
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const event = new CustomEvent('download-click', {
|
|
725
|
+
detail: {
|
|
726
|
+
type,
|
|
727
|
+
markdown,
|
|
728
|
+
html: view.dom.innerHTML || '',
|
|
729
|
+
},
|
|
730
|
+
bubbles: true,
|
|
731
|
+
composed: true,
|
|
732
|
+
})
|
|
733
|
+
root.dispatchEvent(event)
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function handleDirectImport(
|
|
737
|
+
type: 'markdown' | 'word' | 'pdf',
|
|
738
|
+
root: HTMLElement,
|
|
739
|
+
ctx: Ctx
|
|
740
|
+
) {
|
|
741
|
+
if (type === 'markdown') {
|
|
742
|
+
const input = document.createElement('input')
|
|
743
|
+
input.type = 'file'
|
|
744
|
+
input.accept = '.md'
|
|
745
|
+
input.onchange = (evt) => {
|
|
746
|
+
const file = (evt.target as HTMLInputElement).files?.[0]
|
|
747
|
+
if (!file) return
|
|
748
|
+
file
|
|
749
|
+
.text()
|
|
750
|
+
.then((text) => {
|
|
751
|
+
replaceAll(text)(ctx)
|
|
752
|
+
|
|
753
|
+
const event = new CustomEvent('import-click', {
|
|
754
|
+
detail: { type: 'markdown', file },
|
|
755
|
+
bubbles: true,
|
|
756
|
+
composed: true,
|
|
757
|
+
})
|
|
758
|
+
root.dispatchEvent(event)
|
|
759
|
+
})
|
|
760
|
+
.catch((err) => {
|
|
761
|
+
console.error('Failed to read file:', err)
|
|
762
|
+
})
|
|
763
|
+
}
|
|
764
|
+
input.click()
|
|
765
|
+
} else {
|
|
766
|
+
const event = new CustomEvent('import-click', {
|
|
767
|
+
detail: { type },
|
|
768
|
+
bubbles: true,
|
|
769
|
+
composed: true,
|
|
770
|
+
})
|
|
771
|
+
root.dispatchEvent(event)
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
function showDownloadPopover(
|
|
776
|
+
rootNode: ShadowRoot | Document,
|
|
777
|
+
root: HTMLElement,
|
|
778
|
+
view: any,
|
|
779
|
+
markdown: string,
|
|
780
|
+
exportItems: ('markdown' | 'word' | 'pdf')[]
|
|
781
|
+
) {
|
|
782
|
+
const button = root.querySelector('button[data-key="export"]') as HTMLElement
|
|
783
|
+
if (!button) return
|
|
784
|
+
|
|
785
|
+
const existing = activeDownloadPopovers.get(button)
|
|
786
|
+
if (existing) {
|
|
787
|
+
;(existing as any).closePopover()
|
|
788
|
+
return
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
ensureStyles(rootNode)
|
|
792
|
+
|
|
793
|
+
const container = rootNode instanceof ShadowRoot ? rootNode : document.body
|
|
794
|
+
const popover = document.createElement('div')
|
|
795
|
+
popover.className = 'download-popover'
|
|
796
|
+
|
|
797
|
+
let popoverHtml = ''
|
|
798
|
+
if (exportItems.includes('markdown')) {
|
|
799
|
+
popoverHtml += `
|
|
800
|
+
<div class="download-popover-item" id="download-md-btn">
|
|
801
|
+
<span class="download-popover-item-icon">
|
|
802
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><line x1="10" y1="9" x2="8" y2="9"></line></svg>
|
|
803
|
+
</span>
|
|
804
|
+
<span>下载 MD</span>
|
|
805
|
+
</div>
|
|
806
|
+
`
|
|
807
|
+
}
|
|
808
|
+
if (exportItems.includes('word')) {
|
|
809
|
+
popoverHtml += `
|
|
810
|
+
<div class="download-popover-item" id="download-word-btn">
|
|
811
|
+
<span class="download-popover-item-icon">
|
|
812
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
|
|
813
|
+
</span>
|
|
814
|
+
<span>下载 WORD</span>
|
|
815
|
+
</div>
|
|
816
|
+
`
|
|
817
|
+
}
|
|
818
|
+
if (exportItems.includes('pdf')) {
|
|
819
|
+
popoverHtml += `
|
|
820
|
+
<div class="download-popover-item" id="download-pdf-btn">
|
|
821
|
+
<span class="download-popover-item-icon">
|
|
822
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg>
|
|
823
|
+
</span>
|
|
824
|
+
<span>下载 PDF</span>
|
|
825
|
+
</div>
|
|
826
|
+
`
|
|
827
|
+
}
|
|
828
|
+
popover.innerHTML = popoverHtml
|
|
829
|
+
|
|
830
|
+
container.appendChild(popover)
|
|
831
|
+
activeDownloadPopovers.set(button, popover)
|
|
832
|
+
|
|
833
|
+
const updatePosition = () => {
|
|
834
|
+
const rect = button.getBoundingClientRect()
|
|
835
|
+
popover.style.top = `${rect.bottom + 4}px`
|
|
836
|
+
popover.style.left = `${rect.left + (rect.width - 140) / 2}px`
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
updatePosition()
|
|
840
|
+
|
|
841
|
+
requestAnimationFrame(() => {
|
|
842
|
+
popover.classList.add('show')
|
|
843
|
+
})
|
|
844
|
+
|
|
845
|
+
const closePopover = () => {
|
|
846
|
+
popover.classList.remove('show')
|
|
847
|
+
activeDownloadPopovers.delete(button)
|
|
848
|
+
container.removeEventListener('pointerdown', handleContainerClick, true)
|
|
849
|
+
document.removeEventListener('pointerdown', handleOuterClick, true)
|
|
850
|
+
window.removeEventListener('resize', updatePosition)
|
|
851
|
+
popover.addEventListener(
|
|
852
|
+
'transitionend',
|
|
853
|
+
() => {
|
|
854
|
+
popover.remove()
|
|
855
|
+
},
|
|
856
|
+
{ once: true }
|
|
857
|
+
)
|
|
858
|
+
}
|
|
859
|
+
;(popover as any).closePopover = closePopover
|
|
860
|
+
|
|
861
|
+
const handleContainerClick = (e: Event) => {
|
|
862
|
+
const target = e.target as HTMLElement
|
|
863
|
+
if (
|
|
864
|
+
!popover.contains(target) &&
|
|
865
|
+
target !== button &&
|
|
866
|
+
!button.contains(target)
|
|
867
|
+
) {
|
|
868
|
+
closePopover()
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const handleOuterClick = (e: Event) => {
|
|
873
|
+
const target = e.target as HTMLElement
|
|
874
|
+
if (target !== root && !root.contains(target)) {
|
|
875
|
+
closePopover()
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
popover.addEventListener('pointerdown', (e) => {
|
|
880
|
+
e.stopPropagation()
|
|
881
|
+
})
|
|
882
|
+
|
|
883
|
+
container.addEventListener('pointerdown', handleContainerClick, true)
|
|
884
|
+
document.addEventListener('pointerdown', handleOuterClick, true)
|
|
885
|
+
window.addEventListener('resize', updatePosition)
|
|
886
|
+
|
|
887
|
+
popover.querySelector('#download-md-btn')?.addEventListener('click', (e) => {
|
|
888
|
+
e.stopPropagation()
|
|
889
|
+
const blob = new Blob([markdown], { type: 'text/markdown;charset=utf-8;' })
|
|
890
|
+
const url = URL.createObjectURL(blob)
|
|
891
|
+
const link = document.createElement('a')
|
|
892
|
+
link.href = url
|
|
893
|
+
link.download = 'document.md'
|
|
894
|
+
link.click()
|
|
895
|
+
URL.revokeObjectURL(url)
|
|
896
|
+
closePopover()
|
|
897
|
+
|
|
898
|
+
const event = new CustomEvent('download-click', {
|
|
899
|
+
detail: {
|
|
900
|
+
type: 'markdown',
|
|
901
|
+
markdown,
|
|
902
|
+
html: view.dom.innerHTML || '',
|
|
903
|
+
},
|
|
904
|
+
bubbles: true,
|
|
905
|
+
composed: true,
|
|
906
|
+
})
|
|
907
|
+
root.dispatchEvent(event)
|
|
908
|
+
})
|
|
909
|
+
|
|
910
|
+
popover
|
|
911
|
+
.querySelector('#download-word-btn')
|
|
912
|
+
?.addEventListener('click', (e) => {
|
|
913
|
+
e.stopPropagation()
|
|
914
|
+
closePopover()
|
|
915
|
+
const event = new CustomEvent('download-click', {
|
|
916
|
+
detail: {
|
|
917
|
+
type: 'word',
|
|
918
|
+
markdown,
|
|
919
|
+
html: view.dom.innerHTML || '',
|
|
920
|
+
},
|
|
921
|
+
bubbles: true,
|
|
922
|
+
composed: true,
|
|
923
|
+
})
|
|
924
|
+
root.dispatchEvent(event)
|
|
925
|
+
})
|
|
926
|
+
|
|
927
|
+
popover.querySelector('#download-pdf-btn')?.addEventListener('click', (e) => {
|
|
928
|
+
e.stopPropagation()
|
|
929
|
+
closePopover()
|
|
930
|
+
const event = new CustomEvent('download-click', {
|
|
931
|
+
detail: {
|
|
932
|
+
type: 'pdf',
|
|
933
|
+
markdown,
|
|
934
|
+
html: view.dom.innerHTML || '',
|
|
935
|
+
},
|
|
936
|
+
bubbles: true,
|
|
937
|
+
composed: true,
|
|
938
|
+
})
|
|
939
|
+
root.dispatchEvent(event)
|
|
940
|
+
})
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
function showImportPopover(
|
|
944
|
+
rootNode: ShadowRoot | Document,
|
|
945
|
+
root: HTMLElement,
|
|
946
|
+
ctx: Ctx,
|
|
947
|
+
importItems: ('markdown' | 'word' | 'pdf')[]
|
|
948
|
+
) {
|
|
949
|
+
const button = root.querySelector('button[data-key="import"]') as HTMLElement
|
|
950
|
+
if (!button) return
|
|
951
|
+
|
|
952
|
+
const existing = activeImportPopovers.get(button)
|
|
953
|
+
if (existing) {
|
|
954
|
+
;(existing as any).closePopover()
|
|
955
|
+
return
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
ensureStyles(rootNode)
|
|
959
|
+
|
|
960
|
+
const container = rootNode instanceof ShadowRoot ? rootNode : document.body
|
|
961
|
+
const popover = document.createElement('div')
|
|
962
|
+
popover.className = 'import-popover'
|
|
963
|
+
|
|
964
|
+
let popoverHtml = ''
|
|
965
|
+
if (importItems.includes('markdown')) {
|
|
966
|
+
popoverHtml += `
|
|
967
|
+
<div class="import-popover-item" id="import-md-btn">
|
|
968
|
+
<span class="import-popover-item-icon">
|
|
969
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><line x1="10" y1="9" x2="8" y2="9"></line></svg>
|
|
970
|
+
</span>
|
|
971
|
+
<span>导入 MD</span>
|
|
972
|
+
</div>
|
|
973
|
+
`
|
|
974
|
+
}
|
|
975
|
+
if (importItems.includes('word')) {
|
|
976
|
+
popoverHtml += `
|
|
977
|
+
<div class="import-popover-item" id="import-word-btn">
|
|
978
|
+
<span class="import-popover-item-icon">
|
|
979
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
|
|
980
|
+
</span>
|
|
981
|
+
<span>导入 WORD</span>
|
|
982
|
+
</div>
|
|
983
|
+
`
|
|
984
|
+
}
|
|
985
|
+
if (importItems.includes('pdf')) {
|
|
986
|
+
popoverHtml += `
|
|
987
|
+
<div class="import-popover-item" id="import-pdf-btn">
|
|
988
|
+
<span class="import-popover-item-icon">
|
|
989
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg>
|
|
990
|
+
</span>
|
|
991
|
+
<span>导入 PDF</span>
|
|
992
|
+
</div>
|
|
993
|
+
`
|
|
994
|
+
}
|
|
995
|
+
popover.innerHTML = popoverHtml
|
|
996
|
+
|
|
997
|
+
container.appendChild(popover)
|
|
998
|
+
activeImportPopovers.set(button, popover)
|
|
999
|
+
|
|
1000
|
+
const updatePosition = () => {
|
|
1001
|
+
const rect = button.getBoundingClientRect()
|
|
1002
|
+
popover.style.top = `${rect.bottom + 4}px`
|
|
1003
|
+
popover.style.left = `${rect.left + (rect.width - 140) / 2}px`
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
updatePosition()
|
|
1007
|
+
|
|
1008
|
+
requestAnimationFrame(() => {
|
|
1009
|
+
popover.classList.add('show')
|
|
1010
|
+
})
|
|
1011
|
+
|
|
1012
|
+
const closePopover = () => {
|
|
1013
|
+
popover.classList.remove('show')
|
|
1014
|
+
activeImportPopovers.delete(button)
|
|
1015
|
+
container.removeEventListener('pointerdown', handleContainerClick, true)
|
|
1016
|
+
document.removeEventListener('pointerdown', handleOuterClick, true)
|
|
1017
|
+
window.removeEventListener('resize', updatePosition)
|
|
1018
|
+
popover.addEventListener(
|
|
1019
|
+
'transitionend',
|
|
1020
|
+
() => {
|
|
1021
|
+
popover.remove()
|
|
1022
|
+
},
|
|
1023
|
+
{ once: true }
|
|
1024
|
+
)
|
|
1025
|
+
}
|
|
1026
|
+
;(popover as any).closePopover = closePopover
|
|
1027
|
+
|
|
1028
|
+
const handleContainerClick = (e: Event) => {
|
|
1029
|
+
const target = e.target as HTMLElement
|
|
1030
|
+
if (
|
|
1031
|
+
!popover.contains(target) &&
|
|
1032
|
+
target !== button &&
|
|
1033
|
+
!button.contains(target)
|
|
1034
|
+
) {
|
|
1035
|
+
closePopover()
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
const handleOuterClick = (e: Event) => {
|
|
1040
|
+
const target = e.target as HTMLElement
|
|
1041
|
+
if (target !== root && !root.contains(target)) {
|
|
1042
|
+
closePopover()
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
popover.addEventListener('pointerdown', (e) => {
|
|
1047
|
+
e.stopPropagation()
|
|
1048
|
+
})
|
|
1049
|
+
|
|
1050
|
+
container.addEventListener('pointerdown', handleContainerClick, true)
|
|
1051
|
+
document.addEventListener('pointerdown', handleOuterClick, true)
|
|
1052
|
+
window.addEventListener('resize', updatePosition)
|
|
1053
|
+
|
|
1054
|
+
popover.querySelector('#import-md-btn')?.addEventListener('click', (e) => {
|
|
1055
|
+
e.stopPropagation()
|
|
1056
|
+
closePopover()
|
|
1057
|
+
const input = document.createElement('input')
|
|
1058
|
+
input.type = 'file'
|
|
1059
|
+
input.accept = '.md'
|
|
1060
|
+
input.onchange = (evt) => {
|
|
1061
|
+
const file = (evt.target as HTMLInputElement).files?.[0]
|
|
1062
|
+
if (!file) return
|
|
1063
|
+
file
|
|
1064
|
+
.text()
|
|
1065
|
+
.then((text) => {
|
|
1066
|
+
replaceAll(text)(ctx)
|
|
1067
|
+
|
|
1068
|
+
const event = new CustomEvent('import-click', {
|
|
1069
|
+
detail: { type: 'markdown', file },
|
|
1070
|
+
bubbles: true,
|
|
1071
|
+
composed: true,
|
|
1072
|
+
})
|
|
1073
|
+
root.dispatchEvent(event)
|
|
1074
|
+
})
|
|
1075
|
+
.catch((err) => {
|
|
1076
|
+
console.error('Failed to read file:', err)
|
|
1077
|
+
})
|
|
1078
|
+
}
|
|
1079
|
+
input.click()
|
|
1080
|
+
})
|
|
1081
|
+
|
|
1082
|
+
popover.querySelector('#import-word-btn')?.addEventListener('click', (e) => {
|
|
1083
|
+
e.stopPropagation()
|
|
1084
|
+
closePopover()
|
|
1085
|
+
const event = new CustomEvent('import-click', {
|
|
1086
|
+
detail: { type: 'word' },
|
|
1087
|
+
bubbles: true,
|
|
1088
|
+
composed: true,
|
|
1089
|
+
})
|
|
1090
|
+
root.dispatchEvent(event)
|
|
1091
|
+
})
|
|
1092
|
+
|
|
1093
|
+
popover.querySelector('#import-pdf-btn')?.addEventListener('click', (e) => {
|
|
1094
|
+
e.stopPropagation()
|
|
1095
|
+
closePopover()
|
|
1096
|
+
const event = new CustomEvent('import-click', {
|
|
1097
|
+
detail: { type: 'pdf' },
|
|
1098
|
+
bubbles: true,
|
|
1099
|
+
composed: true,
|
|
1100
|
+
})
|
|
1101
|
+
root.dispatchEvent(event)
|
|
1102
|
+
})
|
|
1103
|
+
}
|
|
@@ -29,7 +29,11 @@ import { FixedToolbarComponent } from './component'
|
|
|
29
29
|
import { buildDefaultFixedToolbar } from './config'
|
|
30
30
|
import { DocumentHeader } from './document-header'
|
|
31
31
|
import { OutlinePanel } from './outline-panel'
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
viewMenuStateCtx,
|
|
34
|
+
editorWidthMap,
|
|
35
|
+
type EditorWidth,
|
|
36
|
+
} from './view-menu-state'
|
|
33
37
|
|
|
34
38
|
export interface FixedToolbarConfig {
|
|
35
39
|
boldIcon?: string
|
|
@@ -56,8 +60,10 @@ export interface FixedToolbarConfig {
|
|
|
56
60
|
showHistory?: boolean
|
|
57
61
|
showExport?: boolean
|
|
58
62
|
onExport?: (markdown: string, ctx: Ctx) => void
|
|
63
|
+
exportItems?: ('markdown' | 'word' | 'pdf')[]
|
|
59
64
|
showImport?: boolean
|
|
60
65
|
onImport?: (replaceContent: (markdown: string) => void, ctx: Ctx) => void
|
|
66
|
+
importItems?: ('markdown' | 'word' | 'pdf')[]
|
|
61
67
|
useLocalStorage?: boolean
|
|
62
68
|
id?: string
|
|
63
69
|
outlineVisible?: boolean
|
|
@@ -102,14 +108,19 @@ class FixedToolbarView implements PluginView {
|
|
|
102
108
|
const config = ctx.get(fixedToolbarConfig.key)
|
|
103
109
|
const viewState = ctx.get(viewMenuStateCtx.key)
|
|
104
110
|
|
|
105
|
-
if (config?.outlineVisible !== undefined)
|
|
106
|
-
|
|
107
|
-
if (config?.
|
|
108
|
-
|
|
111
|
+
if (config?.outlineVisible !== undefined)
|
|
112
|
+
viewState.outlineVisible = config.outlineVisible
|
|
113
|
+
if (config?.outlinePosition !== undefined)
|
|
114
|
+
viewState.outlinePosition = config.outlinePosition
|
|
115
|
+
if (config?.outlineWidth !== undefined)
|
|
116
|
+
viewState.outlineWidth = config.outlineWidth
|
|
117
|
+
if (config?.documentBackground !== undefined)
|
|
118
|
+
viewState.documentBackground = config.documentBackground
|
|
109
119
|
if (config?.showTitle !== undefined) viewState.showTitle = config.showTitle
|
|
110
120
|
if (config?.showCover !== undefined) viewState.showCover = config.showCover
|
|
111
121
|
if (config?.coverUrl !== undefined) viewState.coverUrl = config.coverUrl
|
|
112
|
-
if (config?.editorWidth !== undefined)
|
|
122
|
+
if (config?.editorWidth !== undefined)
|
|
123
|
+
viewState.editorWidth = config.editorWidth
|
|
113
124
|
|
|
114
125
|
// Load initial view menu state from localStorage if useLocalStorage is enabled
|
|
115
126
|
if (config?.useLocalStorage) {
|