+
+ {MARK_BUTTONS.map(({ key, label, tooltip }) => {
+ const isActive = Boolean(activeMarks?.[key]);
+ return (
+
+ );
+ })}
+
+
+
{
+ setActiveMarks(editor.api.marks?.() ?? {});
+ }}
+ >
+ onFocusChange?.(true),
+ onBlur: () => onFocusChange?.(false),
+ }}
+ />
+
+
+
+ );
+ },
+);
+
+RichTextEditor.displayName = 'RichTextEditor';
+
+export default RichTextEditor;
diff --git a/electron/database.ts b/electron/database.ts
index cd80a48..871ec86 100644
--- a/electron/database.ts
+++ b/electron/database.ts
@@ -921,7 +921,7 @@ export const databaseService = {
}
if (nodeType === 'document') {
- const allowedDocTypes: DocType[] = ['prompt', 'source_code', 'pdf', 'image'];
+ const allowedDocTypes: DocType[] = ['prompt', 'source_code', 'pdf', 'image', 'rich_text'];
const allowedViewModes: ViewMode[] = ['edit', 'preview', 'split-vertical', 'split-horizontal'];
let docType = allowedDocTypes.includes(node.doc_type as DocType)
diff --git a/hooks/usePrompts.ts b/hooks/usePrompts.ts
index 1391c54..eeba052 100644
--- a/hooks/usePrompts.ts
+++ b/hooks/usePrompts.ts
@@ -61,9 +61,12 @@ export const useDocuments = () => {
const allNodesFlat = useMemo(() => flattenNodes(nodes), [nodes]);
const items: DocumentOrFolder[] = useMemo(() => allNodesFlat.map(nodeToDocumentOrFolder), [allNodesFlat]);
- const addDocument = useCallback(async ({ parentId, title = 'New Document', content = '', doc_type = 'prompt', language_hint = 'markdown' }: { parentId: string | null, title?: string, content?: string, doc_type?: DocType, language_hint?: string | null }) => {
- const resolvedLanguage = mapExtensionToLanguageId(language_hint);
- const shouldPreviewByDefault = doc_type === 'pdf' || doc_type === 'image' || resolvedLanguage === 'pdf' || resolvedLanguage === 'image';
+ const addDocument = useCallback(async ({ parentId, title = 'New Document', content = '', doc_type = 'prompt', language_hint }: { parentId: string | null, title?: string, content?: string, doc_type?: DocType, language_hint?: string | null }) => {
+ const resolvedDocType = doc_type ?? 'prompt';
+ const defaultLanguageHint = resolvedDocType === 'rich_text' ? 'html' : 'markdown';
+ const languageHintToUse = language_hint ?? defaultLanguageHint;
+ const resolvedLanguage = mapExtensionToLanguageId(languageHintToUse);
+ const shouldPreviewByDefault = resolvedDocType === 'pdf' || resolvedDocType === 'image' || resolvedLanguage === 'pdf' || resolvedLanguage === 'image';
const defaultViewMode = shouldPreviewByDefault ? 'preview' : undefined;
const now = new Date().toISOString();
const newNode = await addNode({
@@ -73,7 +76,7 @@ export const useDocuments = () => {
locked: false,
document: {
content,
- doc_type,
+ doc_type: resolvedDocType,
language_hint: resolvedLanguage,
language_source: 'user',
doc_type_source: 'user',
diff --git a/package-lock.json b/package-lock.json
index 7f4445d..0938675 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,12 +10,18 @@
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
+ "@udecode/plate": "^49.0.0",
+ "@udecode/plate-basic-elements": "^49.0.0",
+ "@udecode/plate-basic-marks": "^49.0.0",
"@uiw/react-color-compact": "^2.9.2",
"better-sqlite3": "^11.1.2",
"electron-log": "^5.1.5",
"electron-squirrel-startup": "^1.0.1",
"electron-updater": "^6.2.1",
"emoji-picker-react": "^4.15.0",
+ "slate": "^0.118.1",
+ "slate-history": "^0.113.1",
+ "slate-react": "^0.119.0",
"uuid": "^10.0.0"
},
"devDependencies": {
@@ -1857,6 +1863,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@juggle/resize-observer": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
+ "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==",
+ "license": "Apache-2.0"
+ },
"node_modules/@malept/cross-spawn-promise": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
@@ -1984,6 +1996,39 @@
"node": ">=14"
}
},
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz",
+ "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.38",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz",
@@ -2708,14 +2753,14 @@
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.26",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -2775,6 +2820,212 @@
"@types/node": "*"
}
},
+ "node_modules/@udecode/plate": {
+ "version": "49.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/plate/-/plate-49.0.0.tgz",
+ "integrity": "sha512-jhvQ47+lxiEzUEmXMWBK5YpAT1rIFxf78zoiH98r2CQ9NsZrBqce4onCQ684o5EhU0/7MpHBOqRkBuPnZWtFZA==",
+ "deprecated": "Package no longer supported, use platejs instead.",
+ "license": "MIT",
+ "dependencies": {
+ "@udecode/plate-core": "49.0.0",
+ "@udecode/plate-utils": "49.0.0",
+ "@udecode/react-hotkeys": "37.0.0",
+ "@udecode/react-utils": "47.3.1",
+ "@udecode/slate": "49.0.0",
+ "@udecode/utils": "47.2.7"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@udecode/plate-basic-elements": {
+ "version": "49.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/plate-basic-elements/-/plate-basic-elements-49.0.0.tgz",
+ "integrity": "sha512-6Bv7eovWrGfM5PFEHQbSAHsYxkskjC5vkxn7vQuZlBUl8O8s5Z3OTGNQrEr0U6JJDinn+ylMGPG8rs3v7CHIVQ==",
+ "deprecated": "Package no longer supported, use @platejs/basic-nodes instead.",
+ "license": "MIT",
+ "peerDependencies": {
+ "@udecode/plate": ">=49.0.0",
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@udecode/plate-basic-marks": {
+ "version": "49.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/plate-basic-marks/-/plate-basic-marks-49.0.0.tgz",
+ "integrity": "sha512-qSVr6VKwafDiTvOjRicJh9bdM/WNgCzvEPV2kz1jIAhG2n++fG5LoWJ7qdsFLxtWleUAt8yQKduoGn+0dydk4g==",
+ "deprecated": "Package no longer supported, use @platejs/basic-nodes instead.",
+ "license": "MIT",
+ "peerDependencies": {
+ "@udecode/plate": ">=49.0.0",
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@udecode/plate-core": {
+ "version": "49.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/plate-core/-/plate-core-49.0.0.tgz",
+ "integrity": "sha512-KaLv2coeHWy/Q3L9ldMXqfVK/d17EnyiMNH39M2iW3NSG6PZ1Kr9i43/z2u59pwFIUlJd4yt/g9idz8jgaWXfw==",
+ "deprecated": "Package no longer supported, use @platejs/core instead.",
+ "license": "MIT",
+ "dependencies": {
+ "@udecode/react-hotkeys": "37.0.0",
+ "@udecode/react-utils": "47.3.1",
+ "@udecode/slate": "49.0.0",
+ "@udecode/utils": "47.2.7",
+ "clsx": "^2.1.1",
+ "html-entities": "^2.6.0",
+ "is-hotkey": "^0.2.0",
+ "jotai": "~2.8.4",
+ "jotai-optics": "0.4.0",
+ "jotai-x": "2.3.2",
+ "lodash": "^4.17.21",
+ "nanoid": "^5.1.5",
+ "optics-ts": "2.4.1",
+ "slate-hyperscript": "0.100.0",
+ "slate-react": "0.114.2",
+ "use-deep-compare": "^1.3.0",
+ "zustand": "^5.0.3",
+ "zustand-x": "6.1.0"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@udecode/plate-core/node_modules/nanoid": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz",
+ "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ }
+ },
+ "node_modules/@udecode/plate-core/node_modules/slate-react": {
+ "version": "0.114.2",
+ "resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.114.2.tgz",
+ "integrity": "sha512-yqJnX1/7A30szl9BxW3qX99MZy6mM6VtUi1rXTy0JpRMTKv3rduo0WOxqcX90tpt0ke2pzHGbrLLr1buIN4vrw==",
+ "license": "MIT",
+ "dependencies": {
+ "@juggle/resize-observer": "^3.4.0",
+ "direction": "^1.0.4",
+ "is-hotkey": "^0.2.0",
+ "is-plain-object": "^5.0.0",
+ "lodash": "^4.17.21",
+ "scroll-into-view-if-needed": "^3.1.0",
+ "tiny-invariant": "1.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.2.0",
+ "react-dom": ">=18.2.0",
+ "slate": ">=0.114.0",
+ "slate-dom": ">=0.110.2"
+ }
+ },
+ "node_modules/@udecode/plate-utils": {
+ "version": "49.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/plate-utils/-/plate-utils-49.0.0.tgz",
+ "integrity": "sha512-WkU+PQIhJ4vrrbPMb2SqfjURV3HxmHky7O4TvaKAVhGdo9L0Rql9TKfO6OKt+kF7dD7VaYf0dZcdWLgM6dDONA==",
+ "deprecated": "Package no longer supported, use @platejs/utils instead.",
+ "license": "MIT",
+ "dependencies": {
+ "@udecode/plate-core": "49.0.0",
+ "@udecode/react-utils": "47.3.1",
+ "@udecode/slate": "49.0.0",
+ "@udecode/utils": "47.2.7",
+ "clsx": "^2.1.1",
+ "lodash": "^4.17.21"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@udecode/react-hotkeys": {
+ "version": "37.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/react-hotkeys/-/react-hotkeys-37.0.0.tgz",
+ "integrity": "sha512-3ZV5LiaTnKyhXwN6U0NE2cofNsNN2IPMkNCDntbSIIRLYmI+o6LRkDwAucSNh/BIdNXfvxscsR04RYyIwjGbJw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@udecode/react-utils": {
+ "version": "47.3.1",
+ "resolved": "https://registry.npmjs.org/@udecode/react-utils/-/react-utils-47.3.1.tgz",
+ "integrity": "sha512-fHnY0RGOeKKPnFW8xx8VWlLI0yscHd/kIU5t0bZ5bJ7Vanlhk1CUnPGDNa5HCIMVQrLARngGut/lIyGtoF65EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "^1.2.0",
+ "@udecode/utils": "47.2.7",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@udecode/slate": {
+ "version": "49.0.0",
+ "resolved": "https://registry.npmjs.org/@udecode/slate/-/slate-49.0.0.tgz",
+ "integrity": "sha512-WttifcApSM+KNNivTC64XtgsRL4+OJ03qEaQmuW04Uoh8tKK/z5DePCRwWL19d+jkrPiPtzSB2/edtNJUhtgRQ==",
+ "deprecated": "Package no longer supported, use @platejs/slate instead.",
+ "license": "MIT",
+ "dependencies": {
+ "@udecode/utils": "47.2.7",
+ "is-plain-object": "^5.0.0",
+ "lodash": "^4.17.21",
+ "slate": "0.114.0",
+ "slate-dom": "0.114.0"
+ }
+ },
+ "node_modules/@udecode/slate/node_modules/slate": {
+ "version": "0.114.0",
+ "resolved": "https://registry.npmjs.org/slate/-/slate-0.114.0.tgz",
+ "integrity": "sha512-r3KHl22433DlN5BpLAlL4b3D8ItoGKAkj91YT6GhP39XuLoBT+YFd9ObKuL/okgiPb5lbwnW+71fM45hHceN9w==",
+ "license": "MIT",
+ "dependencies": {
+ "immer": "^10.0.3",
+ "is-plain-object": "^5.0.0",
+ "tiny-warning": "^1.0.3"
+ }
+ },
+ "node_modules/@udecode/slate/node_modules/slate-dom": {
+ "version": "0.114.0",
+ "resolved": "https://registry.npmjs.org/slate-dom/-/slate-dom-0.114.0.tgz",
+ "integrity": "sha512-3LWIfiDPNQSY+SCPsvMTErCkx2gXTViLoWISisw6uM+unwiOkEF9ZmpHp88/SSmcq6k3P4aIquehUNeNUlkdiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@juggle/resize-observer": "^3.4.0",
+ "direction": "^1.0.4",
+ "is-hotkey": "^0.2.0",
+ "is-plain-object": "^5.0.0",
+ "lodash": "^4.17.21",
+ "scroll-into-view-if-needed": "^3.1.0",
+ "tiny-invariant": "1.3.1"
+ },
+ "peerDependencies": {
+ "slate": ">=0.99.0"
+ }
+ },
+ "node_modules/@udecode/utils": {
+ "version": "47.2.7",
+ "resolved": "https://registry.npmjs.org/@udecode/utils/-/utils-47.2.7.tgz",
+ "integrity": "sha512-tQ8tIcdW+ZqWWrDgyf/moTLWtcErcHxaOfuCD/6qIL5hCq+jZm67nGHQToOT4Czti5Jr7CDPMgr8lYpdTEZcew==",
+ "license": "MIT"
+ },
"node_modules/@uiw/color-convert": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.9.2.tgz",
@@ -4048,6 +4299,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@@ -4154,6 +4414,12 @@
"node": ">= 10"
}
},
+ "node_modules/compute-scroll-into-view": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz",
+ "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==",
+ "license": "MIT"
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -4361,7 +4627,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/cytoscape": {
@@ -5062,7 +5328,6 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -5151,6 +5416,19 @@
"node": "*"
}
},
+ "node_modules/direction": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
+ "integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==",
+ "license": "MIT",
+ "bin": {
+ "direction": "cli.js"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
@@ -6842,6 +7120,22 @@
"node": ">=12"
}
},
+ "node_modules/html-entities": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz",
+ "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/mdevils"
+ },
+ {
+ "type": "patreon",
+ "url": "https://patreon.com/mdevils"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/html-url-attributes": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz",
@@ -7049,6 +7343,16 @@
],
"license": "BSD-3-Clause"
},
+ "node_modules/immer": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
+ "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
@@ -7230,6 +7534,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/is-hotkey": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
+ "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
+ "license": "MIT"
+ },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -7253,6 +7563,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -7332,6 +7651,56 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/jotai": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.8.4.tgz",
+ "integrity": "sha512-f6jwjhBJcDtpeauT2xH01gnqadKEySwwt1qNBLvAXcnojkmb76EdqRt05Ym8IamfHGAQz2qMKAwftnyjeSoHAA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=17.0.0",
+ "react": ">=17.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jotai-optics": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/jotai-optics/-/jotai-optics-0.4.0.tgz",
+ "integrity": "sha512-osbEt9AgS55hC4YTZDew2urXKZkaiLmLqkTS/wfW5/l0ib8bmmQ7kBXSFaosV6jDDWSp00IipITcJARFHdp42g==",
+ "license": "MIT",
+ "peerDependencies": {
+ "jotai": ">=2.0.0",
+ "optics-ts": ">=2.0.0"
+ }
+ },
+ "node_modules/jotai-x": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/jotai-x/-/jotai-x-2.3.2.tgz",
+ "integrity": "sha512-WjOfSO4lZBtuy7igTcJ8ZMq9zf/MfjnJnMgsdLNLZrFeiaAWif7Kh/kXwIG4dFMLTOFZ9Bf96bztv21VBcTB0g==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": ">=17.0.0",
+ "jotai": ">=2.0.0",
+ "react": ">=17.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -7657,7 +8026,6 @@
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true,
"license": "MIT"
},
"node_modules/lodash-es": {
@@ -7712,6 +8080,12 @@
"license": "MIT",
"peer": true
},
+ "node_modules/lodash.mapvalues": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
+ "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==",
+ "license": "MIT"
+ },
"node_modules/lodash.union": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
@@ -15013,6 +15387,15 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
+ "node_modules/mutative": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mutative/-/mutative-1.1.0.tgz",
+ "integrity": "sha512-2PJADREjOusk3iJkD3rXV2YjAxTuaLxdfqtqTEt6vcY07LtEBR1seHuBHXWEIuscqRDGvbauYPs+A4Rj/KTczQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0"
+ }
+ },
"node_modules/mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
@@ -15204,6 +15587,12 @@
"opener": "bin/opener-bin.js"
}
},
+ "node_modules/optics-ts": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/optics-ts/-/optics-ts-2.4.1.tgz",
+ "integrity": "sha512-HaYzMHvC80r7U/LqAd4hQyopDezC60PO2qF5GuIwALut2cl5rK1VWHsqTp0oqoJJWjiv6uXKqsO+Q2OO0C3MmQ==",
+ "license": "MIT"
+ },
"node_modules/p-cancelable": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
@@ -15677,6 +16066,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/proxy-compare": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz",
+ "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==",
+ "license": "MIT"
+ },
"node_modules/pump": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
@@ -16924,6 +17319,15 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/scroll-into-view-if-needed": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
+ "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "compute-scroll-into-view": "^3.0.2"
+ }
+ },
"node_modules/secure-compare": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
@@ -17236,6 +17640,79 @@
"node": ">=10"
}
},
+ "node_modules/slate": {
+ "version": "0.118.1",
+ "resolved": "https://registry.npmjs.org/slate/-/slate-0.118.1.tgz",
+ "integrity": "sha512-6H1DNgnSwAFhq/pIgf+tLvjNzH912M5XrKKhP9Frmbds2zFXdSJ6L/uFNyVKxQIkPzGWPD0m+wdDfmEuGFH5Tg==",
+ "license": "MIT",
+ "dependencies": {
+ "immer": "^10.0.3",
+ "tiny-warning": "^1.0.3"
+ }
+ },
+ "node_modules/slate-dom": {
+ "version": "0.119.0",
+ "resolved": "https://registry.npmjs.org/slate-dom/-/slate-dom-0.119.0.tgz",
+ "integrity": "sha512-foc8a2NkE+1SldDIYaoqjhVKupt8RSuvHI868rfYOcypD4we5TT7qunjRKJ852EIRh/Ql8sSTepXgXKOUJnt1w==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@juggle/resize-observer": "^3.4.0",
+ "direction": "^1.0.4",
+ "is-hotkey": "^0.2.0",
+ "is-plain-object": "^5.0.0",
+ "lodash": "^4.17.21",
+ "scroll-into-view-if-needed": "^3.1.0",
+ "tiny-invariant": "1.3.1"
+ },
+ "peerDependencies": {
+ "slate": ">=0.99.0"
+ }
+ },
+ "node_modules/slate-history": {
+ "version": "0.113.1",
+ "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.113.1.tgz",
+ "integrity": "sha512-J9NSJ+UG2GxoW0lw5mloaKcN0JI0x2IA5M5FxyGiInpn+QEutxT1WK7S/JneZCMFJBoHs1uu7S7e6pxQjubHmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-object": "^5.0.0"
+ },
+ "peerDependencies": {
+ "slate": ">=0.65.3"
+ }
+ },
+ "node_modules/slate-hyperscript": {
+ "version": "0.100.0",
+ "resolved": "https://registry.npmjs.org/slate-hyperscript/-/slate-hyperscript-0.100.0.tgz",
+ "integrity": "sha512-fb2KdAYg6RkrQGlqaIi4wdqz3oa0S4zKNBJlbnJbNOwa23+9FLD6oPVx9zUGqCSIpy+HIpOeqXrg0Kzwh/Ii4A==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-object": "^5.0.0"
+ },
+ "peerDependencies": {
+ "slate": ">=0.65.3"
+ }
+ },
+ "node_modules/slate-react": {
+ "version": "0.119.0",
+ "resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.119.0.tgz",
+ "integrity": "sha512-snHqhQ1NkZXyuqG4JTxywRg1accho/hnioM2JIYqziaQQcgfqLi2Pe1AHL82WIC1pLWdzPjy2O7drnSbO0DBsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@juggle/resize-observer": "^3.4.0",
+ "direction": "^1.0.4",
+ "is-hotkey": "^0.2.0",
+ "lodash": "^4.17.21",
+ "scroll-into-view-if-needed": "^3.1.0",
+ "tiny-invariant": "1.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.2.0",
+ "react-dom": ">=18.2.0",
+ "slate": ">=0.114.0",
+ "slate-dom": ">=0.116.0"
+ }
+ },
"node_modules/slice-ansi": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
@@ -17810,12 +18287,24 @@
"node": ">=0.8"
}
},
+ "node_modules/tiny-invariant": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz",
+ "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==",
+ "license": "MIT"
+ },
"node_modules/tiny-typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==",
"license": "MIT"
},
+ "node_modules/tiny-warning": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
+ "license": "MIT"
+ },
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
@@ -18333,6 +18822,27 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/use-deep-compare": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/use-deep-compare/-/use-deep-compare-1.3.0.tgz",
+ "integrity": "sha512-94iG+dEdEP/Sl3WWde+w9StIunlV8Dgj+vkt5wTwMoFQLaijiEZSXXy8KtcStpmEDtIptRJiNeD4ACTtVvnIKA==",
+ "license": "MIT",
+ "dependencies": {
+ "dequal": "2.0.3"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
+ "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/utf8-byte-length": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
@@ -19451,6 +19961,95 @@
"node": ">= 10"
}
},
+ "node_modules/zustand": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
+ "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/zustand-x": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/zustand-x/-/zustand-x-6.1.0.tgz",
+ "integrity": "sha512-lW1Fs29bLCrerWDa3lZLPuEn+ZkbSGzXdwdImKLJUtI2OqlDjpcFac5WTzCPs2ul/igwXFnGiKH1mdn+1Pl2mw==",
+ "license": "MIT",
+ "dependencies": {
+ "immer": "^10.0.3",
+ "lodash.mapvalues": "^4.6.0",
+ "mutative": "1.1.0",
+ "react-tracked": "^1.7.11",
+ "use-sync-external-store": "1.4.0"
+ },
+ "peerDependencies": {
+ "zustand": ">=5.0.2"
+ }
+ },
+ "node_modules/zustand-x/node_modules/react-tracked": {
+ "version": "1.7.14",
+ "resolved": "https://registry.npmjs.org/react-tracked/-/react-tracked-1.7.14.tgz",
+ "integrity": "sha512-6UMlgQeRAGA+uyYzuQGm7kZB6ZQYFhc7sntgP7Oxwwd6M0Ud/POyb4K3QWT1eXvoifSa80nrAWnXWFGpOvbwkw==",
+ "license": "MIT",
+ "dependencies": {
+ "proxy-compare": "2.6.0",
+ "use-context-selector": "1.4.4"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": "*",
+ "react-native": "*",
+ "scheduler": ">=0.19.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/zustand-x/node_modules/use-context-selector": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.4.4.tgz",
+ "integrity": "sha512-pS790zwGxxe59GoBha3QYOwk8AFGp4DN6DOtH+eoqVmgBBRXVx4IlPDhJmmMiNQAgUaLlP+58aqRC3A4rdaSjg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": "*",
+ "react-native": "*",
+ "scheduler": ">=0.19.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
diff --git a/package.json b/package.json
index 616a38f..5410721 100644
--- a/package.json
+++ b/package.json
@@ -35,11 +35,17 @@
},
"dependencies": {
"@uiw/react-color-compact": "^2.9.2",
+ "@udecode/plate": "^49.0.0",
+ "@udecode/plate-basic-elements": "^49.0.0",
+ "@udecode/plate-basic-marks": "^49.0.0",
"better-sqlite3": "^11.1.2",
"electron-log": "^5.1.5",
"electron-squirrel-startup": "^1.0.1",
"electron-updater": "^6.2.1",
"emoji-picker-react": "^4.15.0",
+ "slate": "^0.118.1",
+ "slate-history": "^0.113.1",
+ "slate-react": "^0.119.0",
"uuid": "^10.0.0"
},
"devDependencies": {
diff --git a/services/classificationService.ts b/services/classificationService.ts
index 9b5c081..b470a5a 100644
--- a/services/classificationService.ts
+++ b/services/classificationService.ts
@@ -211,6 +211,9 @@ export const classifyDocumentContent = (options: ClassificationOptions): Classif
if (langFromExtension === 'plantuml') {
return classifyWith('plantuml', 'source_code', 'split-vertical', 0.8, 'Extension indicates PlantUML');
}
+ if (langFromExtension === 'html') {
+ return classifyWith('html', 'rich_text', null, 0.75, 'Extension indicates HTML');
+ }
if (langFromExtension !== 'plaintext') {
return classifyWith(langFromExtension, 'source_code', null, 0.7, `Extension indicates ${langFromExtension}`);
}
@@ -233,7 +236,7 @@ export const classifyDocumentContent = (options: ClassificationOptions): Classif
}
if (looksLikeHtml(trimmed)) {
- return classifyWith('html', 'source_code', null, 0.75, 'HTML tag heuristics matched');
+ return classifyWith('html', 'rich_text', null, 0.75, 'HTML tag heuristics matched');
}
if (looksLikeYaml(trimmed)) {
diff --git a/services/documentExportService.ts b/services/documentExportService.ts
index 117af02..d14ff65 100644
--- a/services/documentExportService.ts
+++ b/services/documentExportService.ts
@@ -21,6 +21,7 @@ const DEFAULT_DOC_TYPE_EXTENSION: Record