diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
index 1db1bb9e4..8fcfbdc28 100644
--- a/.github/workflows/preview.yml
+++ b/.github/workflows/preview.yml
@@ -45,3 +45,5 @@ jobs:
with:
message: |
Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }}
+ [Playground](${{ steps.deploy.outputs.stdout }}/playground.html)
+ [Storybook](${{ steps.deploy.outputs.stdout }}/storybook/)
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index 1241b47ce..a8a219f14 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -7,11 +7,12 @@ import './storybook.css'
const preview: Preview = {
decorators: [
- (Story) => (
-
+ (Story, c) => {
+ const noScaling = c.parameters.noScaling
+ return
-
- ),
+
;
+ },
],
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },
diff --git a/package.json b/package.json
index 6bf9a456c..8d6bfbf6c 100644
--- a/package.json
+++ b/package.json
@@ -62,11 +62,16 @@
"node-gzip": "^1.1.2",
"peerjs": "^1.5.0",
"pretty-bytes": "^6.1.1",
+ "prosemirror-example-setup": "^1.2.2",
+ "prosemirror-markdown": "^1.12.0",
+ "prosemirror-state": "^1.4.3",
+ "prosemirror-view": "^1.33.1",
"prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-transition-group": "^4.4.5",
+ "remark": "^15.0.1",
"sanitize-filename": "^1.6.3",
"skinview3d": "^3.0.1",
"source-map-js": "^1.0.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 33f87a073..759690ffe 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -126,6 +126,18 @@ importers:
prismarine-provider-anvil:
specifier: github:zardoy/prismarine-provider-anvil#everything
version: github.com/zardoy/prismarine-provider-anvil/0ddcd9d48574113308e1fbebef60816aced0846f(minecraft-data@3.62.0)
+ prosemirror-example-setup:
+ specifier: ^1.2.2
+ version: 1.2.2
+ prosemirror-markdown:
+ specifier: ^1.12.0
+ version: 1.12.0
+ prosemirror-state:
+ specifier: ^1.4.3
+ version: 1.4.3
+ prosemirror-view:
+ specifier: ^1.33.1
+ version: 1.33.1
qrcode.react:
specifier: ^3.1.0
version: 3.1.0(react@18.2.0)
@@ -138,6 +150,9 @@ importers:
react-transition-group:
specifier: ^4.4.5
version: 4.4.5(react-dom@18.2.0)(react@18.2.0)
+ remark:
+ specifier: ^15.0.1
+ version: 15.0.1
sanitize-filename:
specifier: ^1.6.3
version: 1.6.3
@@ -4992,6 +5007,12 @@ packages:
'@types/node': 20.8.10
dev: true
+ /@types/debug@4.1.12:
+ resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+ dependencies:
+ '@types/ms': 0.7.34
+ dev: false
+
/@types/detect-port@1.3.3:
resolution: {integrity: sha512-bV/jQlAJ/nPY3XqSatkGpu+nGzou+uSwrH1cROhn+jBFg47yaNH+blW4C7p9KhopC7QxCv/6M86s37k8dMk0Yg==}
dev: true
@@ -5113,6 +5134,12 @@ packages:
resolution: {integrity: sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==}
dev: true
+ /@types/mdast@4.0.3:
+ resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==}
+ dependencies:
+ '@types/unist': 2.0.8
+ dev: false
+
/@types/mdx@2.0.8:
resolution: {integrity: sha512-r7/zWe+f9x+zjXqGxf821qz++ld8tp6Z4jUS6qmPZUXH6tfh4riXOhAqb12tWGWAevCFtMt1goLWkQMqIJKpsA==}
dev: true
@@ -5137,6 +5164,10 @@ packages:
resolution: {integrity: sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==}
dev: true
+ /@types/ms@0.7.34:
+ resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
+ dev: false
+
/@types/node-fetch@2.6.6:
resolution: {integrity: sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==}
dependencies:
@@ -5293,7 +5324,10 @@ packages:
/@types/unist@2.0.8:
resolution: {integrity: sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==}
- dev: true
+
+ /@types/unist@3.0.2:
+ resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
+ dev: false
/@types/webxr@0.5.7:
resolution: {integrity: sha512-Rcgs5c2eNFnHp53YOjgtKfl/zWX1Y+uFGUwlSXrWcZWu3yhANRezmph4MninmqybUYT6g9ZE0aQ9QIdPkLR3Kg==}
@@ -5944,7 +5978,6 @@ packages:
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- dev: true
/aria-hidden@1.2.3:
resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==}
@@ -6226,6 +6259,10 @@ packages:
resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==}
dev: false
+ /bail@2.0.2:
+ resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
+ dev: false
+
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -6715,6 +6752,10 @@ packages:
resolution: {integrity: sha512-CAtbGEDulyjzs05RXy3uKcwqeztz/dMEuAc1Xu9NQBsbrhuGMneL0u9Dj5SoutLKBFYun8txxYIwhjtLNfUmCA==}
dev: false
+ /character-entities@2.0.2:
+ resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
+ dev: false
+
/check-error@1.0.3:
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
dependencies:
@@ -7103,6 +7144,10 @@ packages:
sha.js: 2.4.11
dev: true
+ /crelt@1.0.6:
+ resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
+ dev: false
+
/cross-spawn@6.0.5:
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
engines: {node: '>=4.8'}
@@ -7342,6 +7387,12 @@ packages:
engines: {node: '>=10'}
dev: true
+ /decode-named-character-reference@1.0.2:
+ resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
+ dependencies:
+ character-entities: 2.0.2
+ dev: false
+
/decompress-response@4.2.1:
resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
engines: {node: '>=8'}
@@ -7460,7 +7511,6 @@ packages:
/dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
- dev: true
/des.js@1.1.0:
resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==}
@@ -7515,6 +7565,12 @@ packages:
- supports-color
dev: true
+ /devlop@1.1.0:
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+ dependencies:
+ dequal: 2.0.3
+ dev: false
+
/diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -7812,7 +7868,6 @@ packages:
/entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
- dev: true
/env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
@@ -9989,6 +10044,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /is-plain-obj@4.1.0:
+ resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+ engines: {node: '>=12'}
+ dev: false
+
/is-plain-object@2.0.4:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
@@ -10500,6 +10560,12 @@ packages:
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ /linkify-it@5.0.0:
+ resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
+ dependencies:
+ uc.micro: 2.1.0
+ dev: false
+
/listr2@3.14.0(enquirer@2.4.1):
resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
engines: {node: '>=10.0.0'}
@@ -10655,6 +10721,10 @@ packages:
resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==}
dev: false
+ /longest-streak@3.1.0:
+ resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
+ dev: false
+
/looks-same@8.2.3:
resolution: {integrity: sha512-0LK5r4+9t2D56XPVNH3hhG4o0yBYUdeu9FEd8z0ZCs/2fR9zJQj+6ob6ued8iHk3yddrSAdUA+9YGVK2FBMGUw==}
engines: {node: '>= 12.0.0'}
@@ -10800,6 +10870,18 @@ packages:
resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
dev: true
+ /markdown-it@14.0.0:
+ resolution: {integrity: sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+ dev: false
+
/markdown-to-jsx@7.3.2(react@18.2.0):
resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==}
engines: {node: '>= 10'}
@@ -10829,14 +10911,63 @@ packages:
unist-util-visit: 2.0.3
dev: true
+ /mdast-util-from-markdown@2.0.0:
+ resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ '@types/unist': 3.0.2
+ decode-named-character-reference: 1.0.2
+ devlop: 1.1.0
+ mdast-util-to-string: 4.0.0
+ micromark: 4.0.0
+ micromark-util-decode-numeric-character-reference: 2.0.1
+ micromark-util-decode-string: 2.0.0
+ micromark-util-normalize-identifier: 2.0.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ unist-util-stringify-position: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /mdast-util-phrasing@4.1.0:
+ resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ unist-util-is: 6.0.0
+ dev: false
+
+ /mdast-util-to-markdown@2.1.0:
+ resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ '@types/unist': 3.0.2
+ longest-streak: 3.1.0
+ mdast-util-phrasing: 4.1.0
+ mdast-util-to-string: 4.0.0
+ micromark-util-decode-string: 2.0.0
+ unist-util-visit: 5.0.0
+ zwitch: 2.0.4
+ dev: false
+
/mdast-util-to-string@1.1.0:
resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==}
dev: true
+ /mdast-util-to-string@4.0.0:
+ resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ dev: false
+
/mdn-data@2.0.14:
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
dev: false
+ /mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+ dev: false
+
/media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
@@ -10892,6 +11023,181 @@ packages:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
engines: {node: '>= 0.6'}
+ /micromark-core-commonmark@2.0.0:
+ resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==}
+ dependencies:
+ decode-named-character-reference: 1.0.2
+ devlop: 1.1.0
+ micromark-factory-destination: 2.0.0
+ micromark-factory-label: 2.0.0
+ micromark-factory-space: 2.0.0
+ micromark-factory-title: 2.0.0
+ micromark-factory-whitespace: 2.0.0
+ micromark-util-character: 2.1.0
+ micromark-util-chunked: 2.0.0
+ micromark-util-classify-character: 2.0.0
+ micromark-util-html-tag-name: 2.0.0
+ micromark-util-normalize-identifier: 2.0.0
+ micromark-util-resolve-all: 2.0.0
+ micromark-util-subtokenize: 2.0.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-factory-destination@2.0.0:
+ resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==}
+ dependencies:
+ micromark-util-character: 2.1.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-factory-label@2.0.0:
+ resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==}
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-character: 2.1.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-factory-space@2.0.0:
+ resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==}
+ dependencies:
+ micromark-util-character: 2.1.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-factory-title@2.0.0:
+ resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==}
+ dependencies:
+ micromark-factory-space: 2.0.0
+ micromark-util-character: 2.1.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-factory-whitespace@2.0.0:
+ resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==}
+ dependencies:
+ micromark-factory-space: 2.0.0
+ micromark-util-character: 2.1.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-util-character@2.1.0:
+ resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
+ dependencies:
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-util-chunked@2.0.0:
+ resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==}
+ dependencies:
+ micromark-util-symbol: 2.0.0
+ dev: false
+
+ /micromark-util-classify-character@2.0.0:
+ resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==}
+ dependencies:
+ micromark-util-character: 2.1.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-util-combine-extensions@2.0.0:
+ resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==}
+ dependencies:
+ micromark-util-chunked: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-util-decode-numeric-character-reference@2.0.1:
+ resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==}
+ dependencies:
+ micromark-util-symbol: 2.0.0
+ dev: false
+
+ /micromark-util-decode-string@2.0.0:
+ resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==}
+ dependencies:
+ decode-named-character-reference: 1.0.2
+ micromark-util-character: 2.1.0
+ micromark-util-decode-numeric-character-reference: 2.0.1
+ micromark-util-symbol: 2.0.0
+ dev: false
+
+ /micromark-util-encode@2.0.0:
+ resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
+ dev: false
+
+ /micromark-util-html-tag-name@2.0.0:
+ resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==}
+ dev: false
+
+ /micromark-util-normalize-identifier@2.0.0:
+ resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==}
+ dependencies:
+ micromark-util-symbol: 2.0.0
+ dev: false
+
+ /micromark-util-resolve-all@2.0.0:
+ resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==}
+ dependencies:
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-util-sanitize-uri@2.0.0:
+ resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
+ dependencies:
+ micromark-util-character: 2.1.0
+ micromark-util-encode: 2.0.0
+ micromark-util-symbol: 2.0.0
+ dev: false
+
+ /micromark-util-subtokenize@2.0.0:
+ resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==}
+ dependencies:
+ devlop: 1.1.0
+ micromark-util-chunked: 2.0.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ dev: false
+
+ /micromark-util-symbol@2.0.0:
+ resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
+ dev: false
+
+ /micromark-util-types@2.0.0:
+ resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
+ dev: false
+
+ /micromark@4.0.0:
+ resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
+ dependencies:
+ '@types/debug': 4.1.12
+ debug: 4.3.4(supports-color@8.1.1)
+ decode-named-character-reference: 1.0.2
+ devlop: 1.1.0
+ micromark-core-commonmark: 2.0.0
+ micromark-factory-space: 2.0.0
+ micromark-util-character: 2.1.0
+ micromark-util-chunked: 2.0.0
+ micromark-util-combine-extensions: 2.0.0
+ micromark-util-decode-numeric-character-reference: 2.0.1
+ micromark-util-encode: 2.0.0
+ micromark-util-normalize-identifier: 2.0.0
+ micromark-util-resolve-all: 2.0.0
+ micromark-util-sanitize-uri: 2.0.0
+ micromark-util-subtokenize: 2.0.0
+ micromark-util-symbol: 2.0.0
+ micromark-util-types: 2.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/micromatch@4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
engines: {node: '>=8.6'}
@@ -11618,6 +11924,10 @@ packages:
wcwidth: 1.0.1
dev: true
+ /orderedmap@2.1.1:
+ resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
+ dev: false
+
/os-browserify@0.3.0:
resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==}
dev: true
@@ -12252,6 +12562,120 @@ packages:
object-assign: 4.1.1
react-is: 16.13.1
+ /prosemirror-commands@1.5.2:
+ resolution: {integrity: sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==}
+ dependencies:
+ prosemirror-model: 1.19.4
+ prosemirror-state: 1.4.3
+ prosemirror-transform: 1.8.0
+ dev: false
+
+ /prosemirror-dropcursor@1.8.1:
+ resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==}
+ dependencies:
+ prosemirror-state: 1.4.3
+ prosemirror-transform: 1.8.0
+ prosemirror-view: 1.33.1
+ dev: false
+
+ /prosemirror-example-setup@1.2.2:
+ resolution: {integrity: sha512-pHJc656IgYm249RNp0eQaWNmnyWGk6OrzysWfYI4+NwE14HQ7YNYOlRBLErUS6uCAHIYJLNXf0/XCmf1OCtNbQ==}
+ dependencies:
+ prosemirror-commands: 1.5.2
+ prosemirror-dropcursor: 1.8.1
+ prosemirror-gapcursor: 1.3.2
+ prosemirror-history: 1.3.2
+ prosemirror-inputrules: 1.4.0
+ prosemirror-keymap: 1.2.2
+ prosemirror-menu: 1.2.4
+ prosemirror-schema-list: 1.3.0
+ prosemirror-state: 1.4.3
+ dev: false
+
+ /prosemirror-gapcursor@1.3.2:
+ resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==}
+ dependencies:
+ prosemirror-keymap: 1.2.2
+ prosemirror-model: 1.19.4
+ prosemirror-state: 1.4.3
+ prosemirror-view: 1.33.1
+ dev: false
+
+ /prosemirror-history@1.3.2:
+ resolution: {integrity: sha512-/zm0XoU/N/+u7i5zepjmZAEnpvjDtzoPWW6VmKptcAnPadN/SStsBjMImdCEbb3seiNTpveziPTIrXQbHLtU1g==}
+ dependencies:
+ prosemirror-state: 1.4.3
+ prosemirror-transform: 1.8.0
+ prosemirror-view: 1.33.1
+ 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.8.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-markdown@1.12.0:
+ resolution: {integrity: sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==}
+ dependencies:
+ markdown-it: 14.0.0
+ prosemirror-model: 1.19.4
+ dev: false
+
+ /prosemirror-menu@1.2.4:
+ resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==}
+ dependencies:
+ crelt: 1.0.6
+ prosemirror-commands: 1.5.2
+ prosemirror-history: 1.3.2
+ prosemirror-state: 1.4.3
+ dev: false
+
+ /prosemirror-model@1.19.4:
+ resolution: {integrity: sha512-RPmVXxUfOhyFdayHawjuZCxiROsm9L4FCUA6pWI+l7n2yCBsWy9VpdE1hpDHUS8Vad661YLY9AzqfjLhAKQ4iQ==}
+ dependencies:
+ orderedmap: 2.1.1
+ dev: false
+
+ /prosemirror-schema-list@1.3.0:
+ resolution: {integrity: sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==}
+ dependencies:
+ prosemirror-model: 1.19.4
+ prosemirror-state: 1.4.3
+ prosemirror-transform: 1.8.0
+ dev: false
+
+ /prosemirror-state@1.4.3:
+ resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==}
+ dependencies:
+ prosemirror-model: 1.19.4
+ prosemirror-transform: 1.8.0
+ prosemirror-view: 1.33.1
+ dev: false
+
+ /prosemirror-transform@1.8.0:
+ resolution: {integrity: sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A==}
+ dependencies:
+ prosemirror-model: 1.19.4
+ dev: false
+
+ /prosemirror-view@1.33.1:
+ resolution: {integrity: sha512-62qkYgSJIkwIMMCpuGuPzc52DiK1Iod6TWoIMxP4ja6BTD4yO8kCUL64PZ/WhH/dJ9fW0CDO39FhH1EMyhUFEg==}
+ dependencies:
+ prosemirror-model: 1.19.4
+ prosemirror-state: 1.4.3
+ prosemirror-transform: 1.8.0
+ dev: false
+
/protodef-validator@1.3.1:
resolution: {integrity: sha512-lZ5FWKZYR9xOjpMw1+EfZRfCjzNRQWPq+Dk+jki47Sikl2EeWEPnTfnJERwnU/EwFq6us+0zqHHzSsmLeYX+Lg==}
hasBin: true
@@ -12315,6 +12739,11 @@ packages:
pump: 2.0.1
dev: true
+ /punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+ dev: false
+
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@@ -12920,6 +13349,17 @@ packages:
unist-util-visit: 2.0.3
dev: true
+ /remark-parse@11.0.0:
+ resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ mdast-util-from-markdown: 2.0.0
+ micromark-util-types: 2.0.0
+ unified: 11.0.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/remark-slug@6.1.0:
resolution: {integrity: sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==}
dependencies:
@@ -12928,6 +13368,25 @@ packages:
unist-util-visit: 2.0.3
dev: true
+ /remark-stringify@11.0.0:
+ resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ mdast-util-to-markdown: 2.1.0
+ unified: 11.0.4
+ dev: false
+
+ /remark@15.0.1:
+ resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==}
+ dependencies:
+ '@types/mdast': 4.0.3
+ remark-parse: 11.0.0
+ remark-stringify: 11.0.0
+ unified: 11.0.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/request-progress@3.0.0:
resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==}
dependencies:
@@ -13066,6 +13525,10 @@ packages:
optionalDependencies:
fsevents: 2.3.3
+ /rope-sequence@1.3.4:
+ resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
+ dev: false
+
/rtl-css-js@1.16.1:
resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==}
dependencies:
@@ -14162,6 +14625,10 @@ packages:
engines: {node: '>=12'}
dev: true
+ /trough@2.2.0:
+ resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
+ dev: false
+
/truncate-utf8-bytes@1.0.2:
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
dependencies:
@@ -14337,6 +14804,10 @@ packages:
resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==}
dev: false
+ /uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+ dev: false
+
/ufo@1.3.1:
resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==}
dev: true
@@ -14396,6 +14867,18 @@ packages:
diff: 2.2.3
dev: false
+ /unified@11.0.4:
+ resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==}
+ dependencies:
+ '@types/unist': 3.0.2
+ bail: 2.0.2
+ devlop: 1.1.0
+ extend: 3.0.2
+ is-plain-obj: 4.1.0
+ trough: 2.2.0
+ vfile: 6.0.1
+ dev: false
+
/union@0.5.0:
resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==}
engines: {node: '>= 0.8.0'}
@@ -14431,6 +14914,18 @@ packages:
resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==}
dev: true
+ /unist-util-is@6.0.0:
+ resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
+ dependencies:
+ '@types/unist': 3.0.2
+ dev: false
+
+ /unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+ dependencies:
+ '@types/unist': 3.0.2
+ dev: false
+
/unist-util-visit-parents@3.1.1:
resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==}
dependencies:
@@ -14438,6 +14933,13 @@ packages:
unist-util-is: 4.1.0
dev: true
+ /unist-util-visit-parents@6.0.1:
+ resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
+ dependencies:
+ '@types/unist': 3.0.2
+ unist-util-is: 6.0.0
+ dev: false
+
/unist-util-visit@2.0.3:
resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==}
dependencies:
@@ -14446,6 +14948,14 @@ packages:
unist-util-visit-parents: 3.1.1
dev: true
+ /unist-util-visit@5.0.0:
+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+ dependencies:
+ '@types/unist': 3.0.2
+ unist-util-is: 6.0.0
+ unist-util-visit-parents: 6.0.1
+ dev: false
+
/universalify@0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
@@ -14680,6 +15190,21 @@ packages:
core-util-is: 1.0.2
extsprintf: 1.3.0
+ /vfile-message@4.0.2:
+ resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
+ dependencies:
+ '@types/unist': 3.0.2
+ unist-util-stringify-position: 4.0.0
+ dev: false
+
+ /vfile@6.0.1:
+ resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
+ dependencies:
+ '@types/unist': 3.0.2
+ unist-util-stringify-position: 4.0.0
+ vfile-message: 4.0.2
+ dev: false
+
/vite-node@0.34.6(@types/node@20.8.0):
resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
engines: {node: '>=v14.18.0'}
@@ -14837,6 +15362,10 @@ packages:
- terser
dev: true
+ /w3c-keyname@2.2.8:
+ resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+ dev: false
+
/walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
dependencies:
@@ -15389,6 +15918,10 @@ packages:
react: 18.2.0
dev: false
+ /zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+ dev: false
+
github.com/PrismarineJS/mineflayer/195b3cbd70a110080af9b77a4659991c5d9e484a:
resolution: {tarball: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/195b3cbd70a110080af9b77a4659991c5d9e484a}
name: mineflayer
diff --git a/src/controls.ts b/src/controls.ts
index a02f76c4b..48c051791 100644
--- a/src/controls.ts
+++ b/src/controls.ts
@@ -22,6 +22,10 @@ subscribe(customKeymaps, () => {
localStorage.keymap = JSON.parse(customKeymaps)
})
+const controlOptions = {
+ preventDefault: true
+}
+
export const contro = new ControMax({
commands: {
general: {
@@ -58,6 +62,7 @@ export const contro = new ControMax({
}
},
}, {
+ defaultControlOptions: controlOptions,
target: document,
captureEvents () {
return bot && isGameActive(false)
@@ -71,6 +76,10 @@ export const contro = new ControMax({
window.controMax = contro
export type Command = CommandEventArgument['command']
+export const setDoPreventDefault = (state: boolean) => {
+ controlOptions.preventDefault = state
+}
+
const setSprinting = (state: boolean) => {
bot.setControlState('sprint', state)
gameAdditionalState.isSprinting = state
diff --git a/src/googledrive.ts b/src/googledrive.ts
index 2128ae2f1..3846add3e 100644
--- a/src/googledrive.ts
+++ b/src/googledrive.ts
@@ -25,9 +25,9 @@ export const useGoogleLogIn = () => {
const login = useGoogleLogin({
onSuccess (tokenResponse) {
localStorage.hasEverLoggedIn = true
- googleProviderData.accessToken = tokenResponse.access_token
- googleProviderData.expiresIn = ref(new Date(Date.now() + tokenResponse.expires_in * 1000))
- googleProviderData.hasEverLoggedIn = true
+ googleProviderState.accessToken = tokenResponse.access_token
+ googleProviderState.expiresIn = ref(new Date(Date.now() + tokenResponse.expires_in * 1000))
+ googleProviderState.hasEverLoggedIn = true
},
// prompt: hasEverLoggedIn ? 'none' : 'consent',
scope: SCOPES,
@@ -35,12 +35,12 @@ export const useGoogleLogIn = () => {
onError (error) {
const accessDenied = error.error === 'access_denied' || error.error === 'invalid_scope' || (error as any).error_subtype === 'access_denied'
if (accessDenied) {
- googleProviderData.hasEverLoggedIn = false
+ googleProviderState.hasEverLoggedIn = false
}
}
})
return () => login({
- prompt: googleProviderData.hasEverLoggedIn ? 'none' : 'consent'
+ prompt: googleProviderState.hasEverLoggedIn ? 'none' : 'consent'
})
}
@@ -61,11 +61,11 @@ export const possiblyHandleStateVariable = async () => {
async callback (response) {
if (response.error) {
setLoadingScreenStatus('Error: ' + response.error, true)
- googleProviderData.hasEverLoggedIn = false
+ googleProviderState.hasEverLoggedIn = false
return
}
setLoadingScreenStatus('Opening world in read only mode...')
- googleProviderData.accessToken = response.access_token
+ googleProviderState.accessToken = response.access_token
await mountGoogleDriveFolder(true, parsed.ids[0])
await loadInMemorySave('/google')
}
@@ -73,14 +73,14 @@ export const possiblyHandleStateVariable = async () => {
const choice = await showOptionsModal('Select an action...', ['Login'])
if (choice === 'Login') {
tokenClient.requestAccessToken({
- prompt: googleProviderData.hasEverLoggedIn ? '' : 'consent',
+ prompt: googleProviderState.hasEverLoggedIn ? '' : 'consent',
})
} else {
window.close()
}
}
-export const googleProviderData = proxy({
+export const googleProviderState = proxy({
accessToken: (localStorage.saveAccessToken ? localStorage.accessToken : null) as string | null,
hasEverLoggedIn: !!(localStorage.hasEverLoggedIn),
isReady: false,
@@ -92,18 +92,18 @@ export const googleProviderData = proxy({
} | null
})
-subscribe(googleProviderData, () => {
- localStorage.googleReadonlyMode = googleProviderData.readonlyMode
- localStorage.lastSelectedFolder = googleProviderData.lastSelectedFolder ? JSON.stringify(googleProviderData.lastSelectedFolder) : null
- if (googleProviderData.hasEverLoggedIn) {
+subscribe(googleProviderState, () => {
+ localStorage.googleReadonlyMode = googleProviderState.readonlyMode
+ localStorage.lastSelectedFolder = googleProviderState.lastSelectedFolder ? JSON.stringify(googleProviderState.lastSelectedFolder) : null
+ if (googleProviderState.hasEverLoggedIn) {
localStorage.hasEverLoggedIn = true
} else {
delete localStorage.hasEverLoggedIn
}
- if (localStorage.saveAccessToken && googleProviderData) {
+ if (localStorage.saveAccessToken && googleProviderState) {
// For testing only
- localStorage.accessToken = googleProviderData.accessToken || null
+ localStorage.accessToken = googleProviderState.accessToken || null
} else {
delete localStorage.accessToken
}
diff --git a/src/markdownToFormattedText.test.ts b/src/markdownToFormattedText.test.ts
new file mode 100644
index 000000000..5c1d5f35e
--- /dev/null
+++ b/src/markdownToFormattedText.test.ts
@@ -0,0 +1,39 @@
+import { describe, expect, it } from 'vitest'
+import markdownToFormattedText from './markdownToFormattedText'
+
+describe('markdownToFormattedText', () => {
+ it('should convert markdown to formatted text', () => {
+ const markdown = '**bold** *italic* [link](https://example.com) k `code`'
+ const text = markdownToFormattedText(markdown)
+ const command = '/data merge block ~ ~ ~ {Text1:\'' + JSON.stringify(text[0]) + '\',Text2: \'' + JSON.stringify(text[1]) + '\',Text3:\'' + JSON.stringify(text[2]) + '\',Text4:\'' + JSON.stringify(text[3]) + '\'}' // mojangson
+ expect(text).toMatchInlineSnapshot(`
+ [
+ [
+ [
+ {
+ "bold": true,
+ "text": "bold",
+ },
+ {
+ "text": " ",
+ },
+ {
+ "italic": true,
+ "text": "italic",
+ },
+ {
+ "text": " ",
+ },
+ {
+ "text": " k ",
+ },
+ "code",
+ ],
+ ],
+ "",
+ "",
+ "",
+ ]
+ `)
+ })
+})
diff --git a/src/markdownToFormattedText.ts b/src/markdownToFormattedText.ts
new file mode 100644
index 000000000..5a09917d2
--- /dev/null
+++ b/src/markdownToFormattedText.ts
@@ -0,0 +1,58 @@
+import { remark } from 'remark'
+
+export default (markdown: string) => {
+ const arr = markdown.split('\n\n')
+ const lines = ['', '', '', '']
+ for (const [i, ast] of arr.map(md => remark().parse(md)).entries()) {
+ lines[i] = transformToMinecraftJSON(ast as Element)
+ }
+ return lines
+}
+
+function transformToMinecraftJSON (element: Element): any {
+ switch (element.type) {
+ case 'root': {
+ if (!element.children) return
+ return element.children.map(child => transformToMinecraftJSON(child)).filter(Boolean)
+ }
+ case 'paragraph': {
+ if (!element.children) return
+ const transformedChildren = element.children.map(child => transformToMinecraftJSON(child)).filter(Boolean)
+ return transformedChildren.flat()
+ }
+ case 'strong': {
+ if (!element.children) return
+ return [{ bold: true, text: element.children[0].value }]
+ }
+ case 'text': {
+ return { text: element.value }
+ }
+ case 'emphasis': {
+ if (!element.children) return
+ return [{ italic: true, text: element.children[0].value }]
+ }
+ default:
+ // todo leave untouched eg links
+ return element.value
+ }
+}
+
+interface Position {
+ start: {
+ line: number;
+ column: number;
+ offset: number;
+ };
+ end: {
+ line: number;
+ column: number;
+ offset: number;
+ };
+ }
+
+ interface Element {
+ type: string;
+ children?: Element[];
+ value?: string;
+ position: Position;
+ }
diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx
index c0b649791..13e6388b2 100644
--- a/src/optionsGuiScheme.tsx
+++ b/src/optionsGuiScheme.tsx
@@ -152,6 +152,22 @@ export const guiOptionsScheme: {
},
chatSelect: {
},
+ },
+ {
+ custom () {
+ return Sign Editor
+ },
+ autoSignEditor: {
+ text: 'Enable Sign Editor',
+ },
+ wysiwygSignEditor: {
+ text: 'WYSIWG Editor',
+ values: [
+ 'auto',
+ 'always',
+ 'never'
+ ],
+ },
}
],
controls: [
diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts
index 63ad0b98d..8490053cb 100644
--- a/src/optionsStorage.ts
+++ b/src/optionsStorage.ts
@@ -75,6 +75,9 @@ const defaultOptions = {
autoRespawn: false,
mutedSounds: [] as string[],
plugins: [] as Array<{ enabled: boolean, name: string, description: string, script: string }>,
+ /** Wether to popup sign editor on server action */
+ autoSignEditor: true,
+ wysiwygSignEditor: 'auto' as 'auto' | 'always' | 'never',
}
const migrateOptions = (options: Partial>) => {
diff --git a/src/react/SignEditor.css b/src/react/SignEditor.css
new file mode 100644
index 000000000..ae7e874ba
--- /dev/null
+++ b/src/react/SignEditor.css
@@ -0,0 +1,115 @@
+.signs-editor-container {
+ position: fixed;
+ inset: 0;
+ background-color: rgba(0, 0, 0, 0.4);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.signs-editor-inner-container {
+ position: relative;
+ width: 700px;
+ aspect-ratio: 2;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.signs-editor-bg-image {
+ position: absolute;
+ z-index: -1;
+ width: 100%;
+ height: 100%;
+ image-rendering: pixelated;
+}
+
+.sign-editor {
+ font: inherit;
+ font-size: 420%;
+ width: 90%;
+ max-height: 90%;
+ background-color: rgba(255, 255, 255, 0);
+ border-width: 0px;
+ overflow: auto;
+ outline: none;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ box-sizing: border-box;
+ resize: none;
+ text-align: center;
+}
+
+/* @media (min-width: 1200px) { */
+/* .sign-editor { */
+/* font-size: 400%; */
+/* } */
+/* } */
+
+.ProseMirror p {
+ font-size: 420%;
+ text-align: center;
+}
+
+@media (max-width: 850px) {
+ .ProseMirror p {
+ font-size: 310%;
+ }
+ .sign-editor {
+ font-size: 310%;
+ }
+ .signs-editor-inner-container {
+ width: 500px;
+ }
+}
+
+@media (max-width: 550px) {
+ .ProseMirror p {
+ font-size: 180%;
+ }
+ .sign-editor {
+ font-size: 180%;
+ }
+ .signs-editor-inner-container {
+ width: 300px;
+ }
+}
+
+@media (max-width: 350px) {
+ .ProseMirror p {
+ font-size: 130%;
+ }
+ .sign-editor {
+ font-size: 130%;
+ }
+ .signs-editor-inner-container {
+ width: 220px;
+ }
+}
+
+.wysiwyg-editor {
+ color: black;
+ max-height: 100%;
+ overflow: hidden;
+ width: 90%;
+ margin: 0px;
+ white-space: pre-wrap;
+ border: 1px solid #ccc;
+}
+
+.sign-editor-button {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ width: 75px;
+}
+
+.ProseMirror-menubar {
+ background-color: rgba(255, 255, 255, 0.7);
+}
+
+.ProseMirror {
+
+}
diff --git a/src/react/SignEditor.stories.tsx b/src/react/SignEditor.stories.tsx
new file mode 100644
index 000000000..05d968f92
--- /dev/null
+++ b/src/react/SignEditor.stories.tsx
@@ -0,0 +1,25 @@
+import type { Meta, StoryObj } from '@storybook/react'
+
+import SignEditor from './SignEditor'
+
+const meta: Meta = {
+ component: SignEditor,
+ render (args) {
+ return {
+ console.log('handleClick', result)
+ }} />
+ }
+}
+
+export default meta
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ handleInput () {},
+ isWysiwyg: false
+ },
+ parameters: {
+ noScaling: true
+ },
+}
diff --git a/src/react/SignEditor.tsx b/src/react/SignEditor.tsx
new file mode 100644
index 000000000..ffea0784e
--- /dev/null
+++ b/src/react/SignEditor.tsx
@@ -0,0 +1,81 @@
+import { useEffect, useRef } from 'react'
+import { focusable } from 'tabbable'
+import markdownToFormattedText from '../markdownToFormattedText'
+import { ProseMirrorView } from './prosemirror-markdown'
+import Button from './Button'
+import 'prosemirror-view/style/prosemirror.css'
+import 'prosemirror-menu/style/menu.css'
+import './SignEditor.css'
+
+
+const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg=='
+
+type Props = {
+ handleInput: (target: HTMLInputElement) => void,
+ isWysiwyg: boolean,
+ handleClick?: (view: ResultType) => void
+}
+
+export type ResultType = {
+ plainText: string[]
+} | {
+ dataText: string[]
+}
+
+export default ({ handleInput, isWysiwyg, handleClick }: Props) => {
+ const prosemirrorContainer = useRef(null)
+ const editorView = useRef(null)
+
+ useEffect(() => {
+ if (isWysiwyg) {
+ editorView.current = new ProseMirrorView(prosemirrorContainer.current, '')
+ }
+ }, [isWysiwyg])
+
+ return {
+ let { code } = e
+ if ((e.target as HTMLElement).matches('input') && e.key === 'Enter') code = 'ArrowDown'
+ if (code === 'ArrowDown' || code === 'ArrowUp') {
+ e.preventDefault()
+ const dir = code === 'ArrowDown' ? 1 : -1
+ const elements = focusable(e.currentTarget)
+ const focusedElemIndex = elements.indexOf(document.activeElement as HTMLElement)
+ if (focusedElemIndex === -1) return
+ const nextElem = elements[focusedElemIndex + dir]
+ nextElem?.focus()
+ }
+ }}>
+
+
+ {isWysiwyg ? (
+
+ ) : [1, 2, 3, 4].map((value, index) => {
+ return
{
+ handleInput(e.currentTarget)
+ }} />
+ })
+ }
+
+
+}
diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx
new file mode 100644
index 000000000..b6ade6255
--- /dev/null
+++ b/src/react/SignEditorProvider.tsx
@@ -0,0 +1,84 @@
+import { useMemo, useEffect, useState, useRef } from 'react'
+import { showModal, hideModal } from '../globalState'
+import { setDoPreventDefault } from '../controls'
+import { options } from '../optionsStorage'
+import { useIsModalActive } from './utils'
+import SignEditor, { ResultType } from './SignEditor'
+
+
+const isWysiwyg = async () => {
+ const items = await bot.tabComplete('/', true, true)
+ const commands = new Set(['data'])
+ for (const item of items) {
+ if (commands.has(item.match as unknown as string)) {
+ return true
+ }
+ }
+ return false
+}
+
+export default () => {
+ const [location, setLocation] = useState<{x: number, y: number, z: number} | null>(null)
+ const [isFrontText, setIsFrontText] = useState(true)
+ const text = useRef(['', '', '', ''])
+ const [enableWysiwyg, setEnableWysiwyg] = useState(false)
+ const isModalActive = useIsModalActive('signs-editor-screen')
+
+ const handleClick = (result: ResultType) => {
+ hideModal({ reactType: 'signs-editor-screen' })
+ if ('plainText' in result) {
+ bot._client.write('update_sign', {
+ location,
+ isFrontText,
+ text1: result.plainText[0],
+ text2: result.plainText[1],
+ text3: result.plainText[2],
+ text4: result.plainText[3]
+ })
+ } else {
+ if (!location) return
+ const command = `/data merge block ${location.x} ${location.y} ${location.z} {Text1:'` + JSON.stringify(result.dataText[0]) + '\',Text2: \'' + JSON.stringify(result.dataText[1]) + '\',Text3:\'' + JSON.stringify(result.dataText[2]) + '\',Text4:\'' + JSON.stringify(result.dataText[3]) + '\'}' // mojangson
+ bot.chat(command)
+ }
+ }
+
+ const handleInput = (target: HTMLInputElement) => {
+ const smallSymbols = /[()[\]{} ]/
+ const largeSymbols = /[;|',.]/
+ let addLength = 0
+ for (const letter of target.value) {
+ if (smallSymbols.test(letter)) {
+ addLength += 1 - 1 / 1.46
+ } else if (largeSymbols.test(letter)) {
+ addLength += 1 - 1 / 3
+ }
+ }
+ text.current[Number(target.dataset.key)] = target.value
+ target.setAttribute('maxlength', `${15 + Math.ceil(addLength)}`)
+ }
+
+ useEffect(() => {
+ setDoPreventDefault(!isModalActive) // disable e.preventDefault() since we might be using wysiwyg editor which doesn't use textarea and need default browser behavior to ensure characters are being typed in contenteditable container. Ideally we should do e.preventDefault() only when either ctrl, cmd (meta) or alt key is pressed.
+ }, [isModalActive])
+
+ useMemo(() => {
+ bot._client.on('open_sign_entity', (packet) => {
+ if (!options.autoSignEditor) return
+ setIsFrontText((packet as any).isFrontText ?? true)
+ setLocation(prev => packet.location)
+ showModal({ reactType: 'signs-editor-screen' })
+ if (options.wysiwygSignEditor === 'auto') {
+ void isWysiwyg().then((value) => {
+ setEnableWysiwyg(value)
+ })
+ } else if (options.wysiwygSignEditor === 'always') {
+ setEnableWysiwyg(true)
+ } else {
+ setEnableWysiwyg(false)
+ }
+ })
+ }, [])
+
+ if (!isModalActive) return null
+ return
+}
diff --git a/src/react/SingleplayerProvider.tsx b/src/react/SingleplayerProvider.tsx
index 32d175f43..8eb3af0f6 100644
--- a/src/react/SingleplayerProvider.tsx
+++ b/src/react/SingleplayerProvider.tsx
@@ -7,7 +7,7 @@ import { googleDriveGetFileIdFromPath, mountExportFolder, mountGoogleDriveFolder
import { hideCurrentModal, showModal } from '../globalState'
import { haveDirectoryPicker, setLoadingScreenStatus } from '../utils'
import { exportWorld } from '../builtinCommands'
-import { googleProviderData, useGoogleLogIn, GoogleDriveProvider, isGoogleDriveAvailable, APP_ID } from '../googledrive'
+import { googleProviderState, useGoogleLogIn, GoogleDriveProvider, isGoogleDriveAvailable, APP_ID } from '../googledrive'
import Singleplayer, { WorldProps } from './Singleplayer'
import { useIsModalActive } from './utils'
import { showOptionsModal } from './SelectOption'
@@ -18,6 +18,7 @@ const worldsProxy = proxy({
value: null as null | WorldProps[],
brokenWorlds: [] as string[],
selectedProvider: 'local' as 'local' | 'google',
+ selectedGoogleId: '',
error: '',
})
@@ -48,7 +49,7 @@ export const readWorlds = (abortController: AbortController) => {
(async () => {
const brokenWorlds = [] as string[]
try {
- const loggedIn = !!googleProviderData.accessToken
+ const loggedIn = !!googleProviderState.accessToken
worldsProxy.value = null
if (worldsProxy.selectedProvider === 'google' && !loggedIn) {
worldsProxy.value = []
@@ -135,7 +136,7 @@ export const loadGoogleDriveApi = async () => {
gapi.load('client', () => {
gapi.load('client:picker', () => {
void gapi.client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest').then(() => {
- googleProviderData.isReady = true
+ googleProviderState.isReady = true
resolve()
})
})
@@ -145,24 +146,17 @@ export const loadGoogleDriveApi = async () => {
const Inner = () => {
const worlds = useSnapshot(worldsProxy).value as WorldProps[] | null
- const { selectedProvider, error, brokenWorlds } = useSnapshot(worldsProxy)
+ const { selectedProvider, error, brokenWorlds, selectedGoogleId } = useSnapshot(worldsProxy)
const readWorldsAbortController = useRef(new AbortController())
- useEffect(() => {
- return () => {
- worldsProxy.selectedProvider = 'local'
- }
- }, [])
-
// 3rd party providers
useEffect(() => {
if (selectedProvider !== 'google') return
void loadGoogleDriveApi()
}, [selectedProvider])
- const [selectedGoogleId, setSelectedGoogleId] = useState('')
- const loggedIn = !!useSnapshot(googleProviderData).accessToken
- const googleDriveReadonly = useSnapshot(googleProviderData).readonlyMode
+ const loggedIn = !!useSnapshot(googleProviderState).accessToken
+ const googleDriveReadonly = useSnapshot(googleProviderState).readonlyMode
useEffect(() => {
(async () => {
@@ -171,7 +165,7 @@ const Inner = () => {
worldsProxy.value = []
return
}
- await mountGoogleDriveFolder(googleProviderData.readonlyMode, selectedGoogleId)
+ await mountGoogleDriveFolder(googleProviderState.readonlyMode, selectedGoogleId)
const exists = async (path) => {
try {
await fs.promises.stat(path)
@@ -199,21 +193,74 @@ const Inner = () => {
const googleLogIn = useGoogleLogIn()
- const isGoogleProviderReady = useSnapshot(googleProviderData).isReady
- const providerActions = selectedProvider === 'google' ? isGoogleProviderReady ? loggedIn ? {
+ const googlePicker = useRef/* */(null as any)
+
+ useEffect(() => {
+ return () => {
+ googlePicker.current?.dispose()
+ }
+ })
+
+ const selectGoogleFolder = async () => {
+ if (googleProviderState.lastSelectedFolder) {
+ // ask to use saved previous fodler
+ const choice = await showOptionsModal(`Use previously selected folder "${googleProviderState.lastSelectedFolder.name}"?`, ['Yes', 'No'])
+ if (!choice) return
+ if (choice === 'Yes') {
+ worldsProxy.selectedGoogleId = googleProviderState.lastSelectedFolder.id
+ return
+ }
+ }
+
+ const { google } = window
+
+ const view = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
+ .setIncludeFolders(true)
+ .setMimeTypes('application/vnd.google-apps.folder')
+ .setSelectFolderEnabled(true)
+ .setParent('root')
+
+
+ googlePicker.current = new google.picker.PickerBuilder()
+ .enableFeature(google.picker.Feature.NAV_HIDDEN)
+ .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
+ .setDeveloperKey('AIzaSyBTiHpEqaLL7mEcrsnSS4M-z8cpRH5UwY0')
+ .setAppId(APP_ID)
+ .setOAuthToken(googleProviderState.accessToken)
+ .addView(view)
+ .addView(new google.picker.DocsUploadView())
+ .setTitle('Select a folder with your worlds')
+ .setCallback((data) => {
+ if (data.action === google.picker.Action.PICKED) {
+ googleProviderState.lastSelectedFolder = {
+ id: data.docs[0].id,
+ name: data.docs[0].name,
+ }
+ worldsProxy.selectedGoogleId = data.docs[0].id
+ }
+ })
+ .build()
+ googlePicker.current.setVisible(true)
+ }
+
+ const isGoogleProviderReady = useSnapshot(googleProviderState).isReady
+ const providerActions = loggedIn && selectedProvider === 'google' && isGoogleProviderReady && !selectedGoogleId ? {
+ 'Select Folder': selectGoogleFolder
+ } : selectedProvider === 'google' ? isGoogleProviderReady ? loggedIn ? {
'Log Out' () {
- googleProviderData.hasEverLoggedIn = false
- googleProviderData.accessToken = null
- googleProviderData.lastSelectedFolder = null
- window.google.accounts.oauth2.revoke(googleProviderData.accessToken)
+ googleProviderState.hasEverLoggedIn = false
+ googleProviderState.accessToken = null
+ googleProviderState.lastSelectedFolder = null
+ window.google.accounts.oauth2.revoke(googleProviderState.accessToken)
},
async [`Read Only: ${googleDriveReadonly ? 'ON' : 'OFF'}`] () {
- if (googleProviderData.readonlyMode) {
+ if (googleProviderState.readonlyMode) {
const choice = await showOptionsModal('[Unstable Feature] Enabling world save might corrupt your worlds, eg remove entities (note: you can always restore previous version of files in Drive)', ['Continue'])
if (choice !== 'Continue') return
}
- googleProviderData.readonlyMode = !googleProviderData.readonlyMode
+ googleProviderState.readonlyMode = !googleProviderState.readonlyMode
},
+ 'Select Folder': selectGoogleFolder,
// 'Worlds Path': {
// googleProviderData.worldsPath = e.target.value
// }} />
@@ -224,48 +271,9 @@ const Inner = () => {
} : undefined
// end
- useEffect(() => {
- let picker
- if (loggedIn && selectedProvider === 'google' && isGoogleProviderReady) {
- const { google } = window
-
- const view = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
- .setIncludeFolders(true)
- .setMimeTypes('application/vnd.google-apps.folder')
- .setSelectFolderEnabled(true)
- .setParent('root')
-
-
- picker = new google.picker.PickerBuilder()
- .enableFeature(google.picker.Feature.NAV_HIDDEN)
- .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
- .setDeveloperKey('AIzaSyBTiHpEqaLL7mEcrsnSS4M-z8cpRH5UwY0')
- .setAppId(APP_ID)
- .setOAuthToken(googleProviderData.accessToken)
- .addView(view)
- .addView(new google.picker.DocsUploadView())
- .setTitle('Select a folder with your worlds')
- .setCallback((data) => {
- if (data.action === google.picker.Action.PICKED) {
- googleProviderData.lastSelectedFolder = {
- id: data.docs[0].id,
- name: data.docs[0].name,
- }
- setSelectedGoogleId(data.docs[0].id)
- }
- })
- .build()
- picker.setVisible(true)
- }
-
- return () => {
- if (picker) picker.dispose()
- }
- }, [selectedProvider, loggedIn])
-
return ({ color: value })
+ }
+ ],
+ toDOM: mark => ['span', { style: `color: ${mark.attrs.color}` }, 0]
+ },
+ }
+
+ const fullMenu = buildMenuItems(schema).fullMenu as Array>
+ fullMenu[0] = fullMenu[0].filter(item => item.spec.title !== 'Add or remove link' && item.spec.title !== 'Toggle code font')
+ fullMenu.splice(3, 1); // remove the insert list, quote & checkbox menu
+ (fullMenu[1][0] as any).options.label = 'Color' // check-build error: fullMenu[1][0].options.label = 'Color'
+ // fullMenu[1][0].content[0].spec.label = 'Red'
+ // fullMenu[1][0].content[0].spec.run = (state, dispatch, view) => {
+ // console.log('state', state)
+ // // make ...
+ // const { from, to } = state.selection
+ // const { tr } = state
+ // console.log(schema.marks)
+ // tr.addMark(from, to, schema.marks.textColor.create({ color: 'red' }))
+ // dispatch(tr)
+ // toggleMark(schema.marks.textColor, { color: 'red' })(state, dispatch, view)
+ // }
+ fullMenu[1].splice(1, 1) // remove the type menu
+ console.log('fullMenu', fullMenu)
+ this.view = new EditorView(target, {
+ state: EditorState.create({
+ doc: defaultMarkdownParser.parse(content) ?? undefined,
+ plugins: exampleSetup({
+ schema,
+ menuContent: fullMenu,
+ }),
+ }),
+ attributes (state) {
+ return {
+ autocorrect: 'off',
+ autocapitalize: 'off',
+ spellcheck: 'false',
+ autofocus: 'true',
+ }
+ },
+ })
+ }
+
+ get content () {
+ const content = defaultMarkdownSerializer.serialize(this.view.state.doc)
+ console.log('content', content)
+ return content
+ }
+
+ focus () {
+ this.view.focus()
+ }
+
+ destroy () {
+ this.view.destroy()
+ }
+}
diff --git a/src/reactUi.tsx b/src/reactUi.tsx
index 2b474adc5..aa1d74dd9 100644
--- a/src/reactUi.tsx
+++ b/src/reactUi.tsx
@@ -15,6 +15,7 @@ import EnterFullscreenButton from './react/EnterFullscreenButton'
import ChatProvider from './react/ChatProvider'
import TitleProvider from './react/TitleProvider'
import ScoreboardProvider from './react/ScoreboardProvider'
+import SignEditorProvider from './react/SignEditorProvider'
import SoundMuffler from './react/SoundMuffler'
import TouchControls from './react/TouchControls'
import widgets from './react/widgets'
@@ -66,7 +67,10 @@ const InGameUi = () => {
-
+
+
+
+
{/* becaues of z-index */}
diff --git a/vitest.config.ts b/vitest.config.ts
index fc9d1e493..9a992a526 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -5,6 +5,7 @@ export default defineConfig({
test: {
include: [
'../../src/botUtils.test.ts',
+ '../../src/markdownToFormattedText.test.ts',
'sign-renderer/tests.test.ts'
],
},