ProseMirrorEditor and ProseMirrorViewer

master
Niko PLP 1 month ago
parent 4ae372a860
commit 74137c4bdd
  1. 6
      ng-app/package.json
  2. 0
      ng-app/src/apps/JsonEditor.svelte
  3. 0
      ng-app/src/apps/JsonViewer.svelte
  4. 99
      ng-app/src/apps/ProseMirrorEditor.svelte
  5. 89
      ng-app/src/apps/ProseMirrorViewer.svelte
  6. 2
      ng-app/src/lib/Document.svelte
  7. 2
      ng-app/src/lib/NoWallet.svelte
  8. 45
      ng-app/src/styles.css
  9. 3
      ng-app/vite.config.ts
  10. 9
      package.json
  11. 157
      pnpm-lock.yaml

@ -44,12 +44,18 @@
"flowbite-svelte": "^0.43.3",
"html5-qrcode": "^2.3.8",
"ng-sdk-js": "workspace:^0.1.0-preview.1",
"prosemirror-model": "^1.7.1",
"prosemirror-state": "^1.2.3",
"prosemirror-svelte": "^0.2.4",
"prosemirror-view": "^1.9.10",
"svelte-codemirror-editor": "^1.4.0",
"svelte-i18n": "^4.0.0",
"svelte-inview": "^4.0.2",
"svelte-spa-router": "^3.3.0",
"vite-plugin-top-level-await": "^1.3.1",
"y-codemirror.next": "^0.3.5",
"y-prosemirror": "^1.2.10",
"y-protocols": "^1.0.1",
"yjs": "^13.6.18"
},
"devDependencies": {

@ -0,0 +1,99 @@
<!--
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<script lang="ts">
import { onMount, tick, onDestroy } from "svelte";
import {
toast_error,
toast_success,
reset_toasts,
display_error,
live_discrete_update,
discrete_update
} from "../store";
import {
cur_tab_register_on_save,
cur_tab_deregister_on_save,
cur_tab_branch_class
} from "../tab";
import * as Y from 'yjs'
// @ts-ignore
import { ySyncPlugin, initProseMirrorDoc } from 'y-prosemirror';
import ProsemirrorEditor from 'prosemirror-svelte';
import { richTextSchema } from 'prosemirror-svelte/state';
import { richTextPlugins, corePlugins } from 'prosemirror-svelte/helpers';
import { EditorState } from "prosemirror-state";
export let commits = {};
const ydoc = new Y.Doc()
const yxml = ydoc.getXmlFragment('ng')
ydoc.on('update', async (update, origin) => {
console.log(update,origin);
if (!origin.local) {
try {
await discrete_update(update, "YXml", commits.heads);
} catch (e){
toast_error(display_error(e));
}
}
})
ydoc.on('destroy', async () => {
commits.discrete?.deregisterOnUpdate();
await cur_tab_deregister_on_save();
})
const { doc, mapping } = initProseMirrorDoc(yxml, richTextSchema)
let selection;
let editorState = EditorState.create({
schema: richTextSchema,
doc,
selection,
plugins: [
...corePlugins,
...richTextPlugins,
ySyncPlugin(yxml, { mapping })
]
});
onMount(()=>{
cur_tab_register_on_save(async (updates)=>{
let update = Y.mergeUpdates(updates);
await live_discrete_update(update, "YXml", commits.heads);
});
let history = commits.discrete?.registerOnUpdate((update) => {
Y.applyUpdate(ydoc, update.YXml, {local:true})
});
for (const h of history) {
Y.applyUpdate(ydoc, h.YXml, {local:true})
}
});
onDestroy(()=>{
ydoc.destroy();
});
</script>
<div class="grow p-5 post-rich-text" style="min-height:300px;">
<ProsemirrorEditor
className="prosemirror-editor"
{editorState}
debounceChangeEventsInterval=2000
/>
</div>

@ -0,0 +1,89 @@
<!--
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<script lang="ts">
import { onMount, tick, onDestroy } from "svelte";
import {
sparql_update,
toast_error,
toast_success
} from "../store";
import {
set_view_or_edit, cur_tab_doc_can_edit
} from "../tab";
import{ PencilSquare, RocketLaunch } from "svelte-heros-v2";
import { t } from "svelte-i18n";
import * as Y from 'yjs'
import { yXmlFragmentToProseMirrorRootNode } from 'y-prosemirror';
import { richTextSchema } from 'prosemirror-svelte/state';
import { DOMSerializer } from "prosemirror-model";
export let commits = {};
let source = "";
const ydoc = new Y.Doc()
const yxml = ydoc.getXmlFragment('ng')
ydoc.on('destroy', async () => {
commits.discrete?.deregisterOnUpdate();
})
const toHTML = () => {
const serializer = DOMSerializer.fromSchema(richTextSchema);
const fragment = serializer.serializeFragment(yXmlFragmentToProseMirrorRootNode(yxml, richTextSchema));
const node = document.createElement('div');
node.append(fragment);
return node.innerHTML;
}
onMount(()=>{
let history = commits.discrete?.registerOnUpdate((update) => {
Y.applyUpdate(ydoc, update.YXml, {local:true})
source = toHTML()
});
for (const h of history) {
Y.applyUpdate(ydoc, h.YXml, {local:true})
}
source = toHTML()
});
onDestroy(()=>{
ydoc.destroy();
});
const edit = () => {
set_view_or_edit(false);
}
</script>
<div class="grow p-5">
{#if source}
<div class="post-rich-text">
{@html source}
</div>
{:else if $cur_tab_doc_can_edit}
<button
on:click={edit}
on:keypress={edit}
class="select-none mb-10 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55"
>
<PencilSquare tabindex="-1" class="mr-2 focus:outline-none" />
{$t("doc.start_editing")}
</button>
{/if}
</div>

@ -58,7 +58,7 @@
if (inView) nav_bar_reset_newest();
}}>
<div class="flex flex-col ">
<div class="flex flex-col grow">
{#if $can_have_header}
<div class="flex p-4 max-w-screen-lg justify-start flex-wrap" class:w-[1024px]={width>1024} >

@ -27,7 +27,7 @@
<div class="row">
<Logo class="logo block h-40" alt={$t("common.logo")} />
</div>
<h1 class="text-2xl mb-10">{$t("pages.no_wallet.welcome")}</h1>
<h1 class="text-2xl text-center mb-10">{$t("pages.no_wallet.welcome")}</h1>
<p class="max-w-sm">
{@html $t("pages.no_wallet.description")}

@ -26,6 +26,45 @@ td.hljs {
.splashing {
display: none;
}
.prosemirror-editor {
height: 100%;
overflow-wrap: anywhere !important;
}
.prosemirror-editor:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
.post-rich-text em {
font-style: italic;
font-family: Verdana, Arial, sans-serif;
}
.post-rich-text h1 {
font-size: 2.5rem /* 24px */;
line-height: 4rem /* 32px */;
}
.post-rich-text h2 {
font-size: 2rem /* 20px */;
line-height: 3rem /* 28px */;
}
.post-rich-text h3 {
font-size: 1.5rem /* 18px */;
line-height: 2.5rem /* 28px */;
}
.post-rich-text h4 {
font-size: 1.25rem /* 18px */;
line-height: 2rem /* 28px */;
font-weight: 700;
}
.post-rich-text h5 {
font-size: 1.125rem /* 18px */;
line-height: 2rem /* 28px */;
}
.menu-bg-modal + div {
padding: 0 !important;
@ -206,12 +245,6 @@ a:hover {
color: #535bf2;
}
h1 {
text-align: center;
font-size: 3.2em;
line-height: 1.1;
}
.toast {
left: 50%;
transform: translateX(-50%);

@ -13,7 +13,8 @@ export default defineConfig(async () => {
const config = {
optimizeDeps: {
exclude: ["codemirror", "@codemirror/*", "@codemirror/language", "@codemirror/state", "@codemirror/view","@codemirror/legacy-modes/mode/sparql",
"@codemirror/lang-javascript", "@codemirror/lang-rust", "@replit/codemirror-lang-svelte", "yjs", "y-codemirror.next", "svelte-codemirror-editor"],
"@codemirror/lang-javascript", "@codemirror/lang-rust", "@replit/codemirror-lang-svelte", "yjs", "y-codemirror.next", "svelte-codemirror-editor",
"prosemirror-svelte", "prosemirror-svelte/state", "prosemirror-svelte/helpers", "y-prosemirror", "prosemirror-state", "prosemirror-model", "prosemirror-view", "y-protocols"],
},
worker: {
format: 'es',

@ -14,14 +14,5 @@
"prettier-plugin-svelte": "^3.2.5"
},
"dependencies": {
"@codemirror/autocomplete": "^6.17.0",
"@codemirror/commands": "^6.6.0",
"@codemirror/language": "^6.10.2",
"@codemirror/legacy-modes": "^6.4.0",
"@codemirror/lint": "^6.8.1",
"@codemirror/search": "^6.5.6",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.28.6",
"codemirror": "^6.0.1"
}
}

@ -71,6 +71,10 @@ importers:
node-gzip: ^1.1.2
postcss: ^8.4.23
postcss-load-config: ^4.0.1
prosemirror-model: ^1.7.1
prosemirror-state: ^1.2.3
prosemirror-svelte: ^0.2.4
prosemirror-view: ^1.9.10
shx: ^0.3.4
svelte: ^3.54.0
svelte-check: ^3.0.0
@ -91,6 +95,8 @@ importers:
vite-plugin-top-level-await: ^1.3.1
vite-plugin-wasm: ^3.2.2
y-codemirror.next: ^0.3.5
y-prosemirror: ^1.2.10
y-protocols: ^1.0.1
yjs: ^13.6.18
dependencies:
'@codemirror/autocomplete': 6.17.0_y4udqqf6vpekb2i4jypui2pd5e
@ -121,12 +127,18 @@ importers:
flowbite-svelte: 0.43.3_svelte@3.59.1
html5-qrcode: 2.3.8
ng-sdk-js: link:../ng-sdk-js/pkg
prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-svelte: 0.2.4
prosemirror-view: 1.33.9
svelte-codemirror-editor: 1.4.0_5sa7ksvb6ejctmkumffbkxbvpi
svelte-i18n: 4.0.0_svelte@3.59.1
svelte-inview: 4.0.2_svelte@3.59.1
svelte-spa-router: 3.3.0
vite-plugin-top-level-await: 1.3.1_vite@4.3.9
y-codemirror.next: 0.3.5_2derscuhaavtzv2sogf3enfvaa
y-prosemirror: 1.2.10_t5dsb3fc2figoeqqliqhb3exne
y-protocols: 1.0.6_yjs@13.6.18
yjs: 13.6.18
devDependencies:
'@sveltejs/vite-plugin-svelte': 2.4.1_svelte@3.59.1+vite@4.3.9
@ -2116,6 +2128,10 @@ packages:
mimic-fn: 2.1.0
dev: true
/orderedmap/2.1.1:
resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
dev: false
/p-event/4.2.0:
resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==}
engines: {node: '>=8'}
@ -2258,6 +2274,112 @@ packages:
hasBin: true
dev: true
/prosemirror-commands/1.6.0:
resolution: {integrity: sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==}
dependencies:
prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
dev: false
/prosemirror-dropcursor/1.8.1:
resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==}
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
prosemirror-view: 1.33.9
dev: false
/prosemirror-gapcursor/1.3.2:
resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==}
dependencies:
prosemirror-keymap: 1.2.2
prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-view: 1.33.9
dev: false
/prosemirror-history/1.4.1:
resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==}
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
prosemirror-view: 1.33.9
rope-sequence: 1.3.4
dev: false
/prosemirror-inputrules/1.4.0:
resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==}
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
dev: false
/prosemirror-keymap/1.2.2:
resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==}
dependencies:
prosemirror-state: 1.4.3
w3c-keyname: 2.2.8
dev: false
/prosemirror-model/1.22.2:
resolution: {integrity: sha512-I4lS7HHIW47D0Xv/gWmi4iUWcQIDYaJKd8Hk4+lcSps+553FlQrhmxtItpEvTr75iAruhzVShVp6WUwsT6Boww==}
dependencies:
orderedmap: 2.1.1
dev: false
/prosemirror-schema-basic/1.2.3:
resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==}
dependencies:
prosemirror-model: 1.22.2
dev: false
/prosemirror-schema-list/1.4.1:
resolution: {integrity: sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==}
dependencies:
prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
dev: false
/prosemirror-state/1.4.3:
resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==}
dependencies:
prosemirror-model: 1.22.2
prosemirror-transform: 1.9.0
prosemirror-view: 1.33.9
dev: false
/prosemirror-svelte/0.2.4:
resolution: {integrity: sha512-BJCzKduRlwsOhLpOjQAH7q1sAI+MqvVBtHHmaSzEX+USmZlHHpwuiVGocJijE0UhkHYkYB49bwI4rgs4jDDa5w==}
dependencies:
prosemirror-commands: 1.6.0
prosemirror-dropcursor: 1.8.1
prosemirror-gapcursor: 1.3.2
prosemirror-history: 1.4.1
prosemirror-inputrules: 1.4.0
prosemirror-keymap: 1.2.2
prosemirror-model: 1.22.2
prosemirror-schema-basic: 1.2.3
prosemirror-schema-list: 1.4.1
prosemirror-state: 1.4.3
prosemirror-view: 1.33.9
dev: false
/prosemirror-transform/1.9.0:
resolution: {integrity: sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==}
dependencies:
prosemirror-model: 1.22.2
dev: false
/prosemirror-view/1.33.9:
resolution: {integrity: sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==}
dependencies:
prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-transform: 1.9.0
dev: false
/queue-microtask/1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
@ -2320,6 +2442,10 @@ packages:
optionalDependencies:
fsevents: 2.3.2
/rope-sequence/1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
dev: false
/run-parallel/1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
@ -2950,6 +3076,37 @@ packages:
yjs: 13.6.18
dev: false
/y-prosemirror/1.2.10_t5dsb3fc2figoeqqliqhb3exne:
resolution: {integrity: sha512-lleZ0Pfq6oGK6m8IWCuSa4JjBFMNo17ux9G63qJi505c7txd+l6HL2LL0kjfR9sMrSTrlz+gsieQNrnUPieeuw==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
prosemirror-model: ^1.7.1
prosemirror-state: ^1.2.3
prosemirror-view: ^1.9.10
y-protocols: ^1.0.1
yjs: ^13.5.38
peerDependenciesMeta:
y-protocols:
optional: true
dependencies:
lib0: 0.2.95
prosemirror-model: 1.22.2
prosemirror-state: 1.4.3
prosemirror-view: 1.33.9
y-protocols: 1.0.6_yjs@13.6.18
yjs: 13.6.18
dev: false
/y-protocols/1.0.6_yjs@13.6.18:
resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==}
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
peerDependencies:
yjs: ^13.0.0
dependencies:
lib0: 0.2.95
yjs: 13.6.18
dev: false
/yaml/2.3.1:
resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
engines: {node: '>= 14'}

Loading…
Cancel
Save