From 85fb4745f8c8d19bc5235996adf1f68a39026703 Mon Sep 17 00:00:00 2001 From: gguio Date: Mon, 11 Mar 2024 21:54:13 +0400 Subject: [PATCH 01/22] skeleton --- src/react/SignsEditor.css | 45 +++++++++++++++++++++++++++++++ src/react/SignsEditor.stories.tsx | 17 ++++++++++++ src/react/SignsEditor.tsx | 20 ++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 src/react/SignsEditor.css create mode 100644 src/react/SignsEditor.stories.tsx create mode 100644 src/react/SignsEditor.tsx diff --git a/src/react/SignsEditor.css b/src/react/SignsEditor.css new file mode 100644 index 00000000..0139df34 --- /dev/null +++ b/src/react/SignsEditor.css @@ -0,0 +1,45 @@ +.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: absolute; + width: 50%; + max-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%; +} + +.signs-editor { + font: inherit; + font-size: 1.5rem; + width: 90%; + max-height: 90%; + background-color: rgba(255, 255, 255, 0); + border-width: 0px; + border: none; + overflow: auto; + outline: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + box-sizing: border-box; + resize: none; + text-align: center; +} + diff --git a/src/react/SignsEditor.stories.tsx b/src/react/SignsEditor.stories.tsx new file mode 100644 index 00000000..608f9076 --- /dev/null +++ b/src/react/SignsEditor.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import SignsEditor from './SignsEditor' + +const meta: Meta = { + component: SignsEditor +} + +export default meta +type Story = StoryObj; + +export const Primary: Story = { + args: { + + } +} + diff --git a/src/react/SignsEditor.tsx b/src/react/SignsEditor.tsx new file mode 100644 index 00000000..dd169de5 --- /dev/null +++ b/src/react/SignsEditor.tsx @@ -0,0 +1,20 @@ +import { useState } from 'react' +import './SignsEditor.css' + + +const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg==' + +export default () => { + const [replicatedValue, setReplicatedValue] = useState('') + + return
+
+ + +
+
+} From b95c096e582385afc19b5799358f4d8c31e22492 Mon Sep 17 00:00:00 2001 From: gguio Date: Wed, 13 Mar 2024 13:14:48 +0400 Subject: [PATCH 02/22] Sign update handle --- src/react/SignsEditor.tsx | 7 +++++-- src/react/SignsEditorProvider.tsx | 32 +++++++++++++++++++++++++++++++ src/reactUi.tsx | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/react/SignsEditorProvider.tsx diff --git a/src/react/SignsEditor.tsx b/src/react/SignsEditor.tsx index dd169de5..4200a809 100644 --- a/src/react/SignsEditor.tsx +++ b/src/react/SignsEditor.tsx @@ -4,15 +4,18 @@ import './SignsEditor.css' const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg==' -export default () => { - const [replicatedValue, setReplicatedValue] = useState('') +type Props = { + handleInput: (text: string) => void +} +export default ({ handleInput }: Props) => { return
diff --git a/src/react/SignsEditorProvider.tsx b/src/react/SignsEditorProvider.tsx new file mode 100644 index 00000000..37592437 --- /dev/null +++ b/src/react/SignsEditorProvider.tsx @@ -0,0 +1,32 @@ +import { useMemo, useEffect, useState } from 'react' +import { showModal } from '../globalState' +import { useIsModalActive } from './utils' +import SignsEditor from './SignsEditor' + + +export default () => { + const [text, setText] = useState('') + const isModalActive = useIsModalActive('signs-editor-screen') + + const handleInput = (text: string) => { + setText(text) + } + + useEffect(() => { + if (!isModalActive) { + const block = bot.blockAtCursor() + if (block) { + bot.updateSign(block, text) + } + } + }, [isModalActive]) + + useMemo(() => { + bot._client.on('open_sign_entity', (packet) => { + showModal({ reactType: 'signs-editor-screen' }) + }) + }, []) + + if (!isModalActive) return null + return +} diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 45415578..24abf3d6 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -16,6 +16,7 @@ import EnterFullscreenButton from './react/EnterFullscreenButton' import ChatProvider from './react/ChatProvider' import TitleProvider from './react/TitleProvider' import ScoreboardProvider from './react/ScoreboardProvider' +import SignsEditorProvider from './react/SignsEditorProvider' import SoundMuffler from './react/SoundMuffler' import TouchControls from './react/TouchControls' import widgets from './react/widgets' @@ -62,6 +63,7 @@ const InGameUi = () => { + From c7afdf3538e8d08a40bc845a6b886256789955ce Mon Sep 17 00:00:00 2001 From: gguio Date: Wed, 13 Mar 2024 14:11:16 +0400 Subject: [PATCH 03/22] wysiwyg in stories --- src/react/SignsEditor.stories.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/react/SignsEditor.stories.tsx b/src/react/SignsEditor.stories.tsx index 608f9076..1267fa6f 100644 --- a/src/react/SignsEditor.stories.tsx +++ b/src/react/SignsEditor.stories.tsx @@ -11,7 +11,8 @@ type Story = StoryObj; export const Primary: Story = { args: { - + handleInput: () => {}, + isWysiwyg: false } } From 6524738caf001e190d4a88dc026e346444d69785 Mon Sep 17 00:00:00 2001 From: gguio Date: Wed, 13 Mar 2024 14:51:07 +0400 Subject: [PATCH 04/22] wysiwyg option added --- package.json | 4 + pnpm-lock.yaml | 175 +++++++++++++++++++++++++++++- src/react/SignsEditor.css | 8 ++ src/react/SignsEditor.stories.tsx | 2 +- src/react/SignsEditor.tsx | 34 ++++-- src/react/SignsEditorProvider.tsx | 2 +- src/react/prosemirror-markdown.ts | 47 ++++++++ 7 files changed, 259 insertions(+), 13 deletions(-) create mode 100644 src/react/prosemirror-markdown.ts diff --git a/package.json b/package.json index a21c60b3..ffd9bc20 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,10 @@ "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", "qrcode.react": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91a178d0..bd7f0196 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,6 +114,18 @@ importers: pretty-bytes: specifier: ^6.1.1 version: 6.1.1 + 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) @@ -5917,7 +5929,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==} @@ -7076,6 +7087,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'} @@ -7785,7 +7800,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==} @@ -10473,6 +10487,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'} @@ -10773,6 +10793,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'} @@ -10810,6 +10842,10 @@ packages: 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'} @@ -11591,6 +11627,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 @@ -12234,6 +12274,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 @@ -12297,6 +12451,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'} @@ -13048,6 +13207,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: @@ -14319,6 +14482,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 @@ -14819,6 +14986,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: diff --git a/src/react/SignsEditor.css b/src/react/SignsEditor.css index 0139df34..0b6e64b0 100644 --- a/src/react/SignsEditor.css +++ b/src/react/SignsEditor.css @@ -43,3 +43,11 @@ text-align: center; } +.wysiwyg-editor { + color: black; + background-color: rgba(255, 255, 255, 0.7); + width: 90%; + max-height: 90%; + margin: 0px; + white-space: pre-wrap; +} diff --git a/src/react/SignsEditor.stories.tsx b/src/react/SignsEditor.stories.tsx index 1267fa6f..23bdaadc 100644 --- a/src/react/SignsEditor.stories.tsx +++ b/src/react/SignsEditor.stories.tsx @@ -11,7 +11,7 @@ type Story = StoryObj; export const Primary: Story = { args: { - handleInput: () => {}, + handleInput () {}, isWysiwyg: false } } diff --git a/src/react/SignsEditor.tsx b/src/react/SignsEditor.tsx index 4200a809..46bd255f 100644 --- a/src/react/SignsEditor.tsx +++ b/src/react/SignsEditor.tsx @@ -1,23 +1,39 @@ -import { useState } from 'react' +import { useEffect, useRef } from 'react' +import { ProseMirrorView } from './prosemirror-markdown' +import 'prosemirror-view/style/prosemirror.css' +import 'prosemirror-menu/style/menu.css' import './SignsEditor.css' const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg==' type Props = { - handleInput: (text: string) => void + handleInput: (text: string) => void, + isWysiwyg: boolean } -export default ({ handleInput }: Props) => { +export default ({ handleInput, isWysiwyg }: Props) => { + const ref = useRef(null) + + useEffect(() => { + if (ref.current) { + const view = new ProseMirrorView(ref.current, '') + } + }, [ref.current]) + return
- + {isWysiwyg ? ( +

+ ) : ( + + )}
} diff --git a/src/react/SignsEditorProvider.tsx b/src/react/SignsEditorProvider.tsx index 37592437..5ae3807e 100644 --- a/src/react/SignsEditorProvider.tsx +++ b/src/react/SignsEditorProvider.tsx @@ -28,5 +28,5 @@ export default () => { }, []) if (!isModalActive) return null - return + return } diff --git a/src/react/prosemirror-markdown.ts b/src/react/prosemirror-markdown.ts new file mode 100644 index 00000000..aada0400 --- /dev/null +++ b/src/react/prosemirror-markdown.ts @@ -0,0 +1,47 @@ +import { EditorView } from 'prosemirror-view' +import { EditorState } from 'prosemirror-state' +import { schema, defaultMarkdownParser, defaultMarkdownSerializer } from 'prosemirror-markdown' +import { exampleSetup, buildMenuItems } from 'prosemirror-example-setup' + +export class ProseMirrorView { + view + + constructor (target, content) { + 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 + // check-build error: fullMenu[1][0].options.label = 'Color' + // fullMenu[1][0].options.label = 'Color' + // fullMenu[1][0].content // replace with colors + fullMenu[1].splice(1, 1) // remove the type menu + 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', + } + }, + }) + } + + get content () { + return defaultMarkdownSerializer.serialize(this.view.state.doc) + } + + focus () { + this.view.focus() + } + + destroy () { + this.view.destroy() + } +} + From 5f735cd66c1282b33393cf916de5584f7f65e2c2 Mon Sep 17 00:00:00 2001 From: gguio Date: Fri, 15 Mar 2024 14:02:35 +0400 Subject: [PATCH 05/22] Multiple lines handling added for basic text --- src/react/{SignsEditor.css => SignEditor.css} | 0 ...tor.stories.tsx => SignEditor.stories.tsx} | 8 +-- src/react/{SignsEditor.tsx => SignEditor.tsx} | 2 +- src/react/SignEditorProvider.tsx | 57 +++++++++++++++++++ src/react/SignsEditorProvider.tsx | 32 ----------- src/react/prosemirror-markdown.ts | 3 +- src/reactUi.tsx | 4 +- 7 files changed, 65 insertions(+), 41 deletions(-) rename src/react/{SignsEditor.css => SignEditor.css} (100%) rename src/react/{SignsEditor.stories.tsx => SignEditor.stories.tsx} (53%) rename src/react/{SignsEditor.tsx => SignEditor.tsx} (98%) create mode 100644 src/react/SignEditorProvider.tsx delete mode 100644 src/react/SignsEditorProvider.tsx diff --git a/src/react/SignsEditor.css b/src/react/SignEditor.css similarity index 100% rename from src/react/SignsEditor.css rename to src/react/SignEditor.css diff --git a/src/react/SignsEditor.stories.tsx b/src/react/SignEditor.stories.tsx similarity index 53% rename from src/react/SignsEditor.stories.tsx rename to src/react/SignEditor.stories.tsx index 23bdaadc..1ab2bd5e 100644 --- a/src/react/SignsEditor.stories.tsx +++ b/src/react/SignEditor.stories.tsx @@ -1,13 +1,13 @@ import type { Meta, StoryObj } from '@storybook/react' -import SignsEditor from './SignsEditor' +import SignEditor from './SignEditor' -const meta: Meta = { - component: SignsEditor +const meta: Meta = { + component: SignEditor } export default meta -type Story = StoryObj; +type Story = StoryObj; export const Primary: Story = { args: { diff --git a/src/react/SignsEditor.tsx b/src/react/SignEditor.tsx similarity index 98% rename from src/react/SignsEditor.tsx rename to src/react/SignEditor.tsx index 46bd255f..85833bb6 100644 --- a/src/react/SignsEditor.tsx +++ b/src/react/SignEditor.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef } from 'react' import { ProseMirrorView } from './prosemirror-markdown' import 'prosemirror-view/style/prosemirror.css' import 'prosemirror-menu/style/menu.css' -import './SignsEditor.css' +import './SignEditor.css' const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg==' diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx new file mode 100644 index 00000000..31d3d77a --- /dev/null +++ b/src/react/SignEditorProvider.tsx @@ -0,0 +1,57 @@ +import { useMemo, useEffect, useState } from 'react' +import { showModal } from '../globalState' +import { useIsModalActive } from './utils' +import SignEditor from './SignEditor' + + +export default () => { + const [location, setLocation] = useState<{x: number, y: number, z: number} | null>(null) + const [text, setText] = useState('') + const isModalActive = useIsModalActive('signs-editor-screen') + + const handleInput = (text: string) => { + if (text.length > 22 || text.includes('\n')) { + const lines = text.split('\n') + const result: string[] = [] + for (const line of lines) { + let startIndex = 0 + while (startIndex < line.length) { + if (startIndex + 22 < line.length) { + result.push(line.slice(startIndex, startIndex + 22)) + } else { + result.push(line.slice(startIndex)) + } + startIndex += 22 + } + } + setText(result) + } else { + setText(text) + } + } + + useEffect(() => { + if (!isModalActive) { + if (location) { + console.log(location) + bot._client.write('update_sign', { + location, + text1: typeof text === 'string' ? text : text[0] ?? '', + text2: typeof text === 'string' ? '' : text[1] ?? '', + text3: typeof text === 'string' ? '' : text[2] ?? '', + text4: typeof text === 'string' ? '' : text[3] ?? '' + }) + } + } + }, [isModalActive]) + + useMemo(() => { + bot._client.on('open_sign_entity', (packet) => { + setLocation(prev => packet.location) + showModal({ reactType: 'signs-editor-screen' }) + }) + }, []) + + if (!isModalActive) return null + return +} diff --git a/src/react/SignsEditorProvider.tsx b/src/react/SignsEditorProvider.tsx deleted file mode 100644 index 5ae3807e..00000000 --- a/src/react/SignsEditorProvider.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useMemo, useEffect, useState } from 'react' -import { showModal } from '../globalState' -import { useIsModalActive } from './utils' -import SignsEditor from './SignsEditor' - - -export default () => { - const [text, setText] = useState('') - const isModalActive = useIsModalActive('signs-editor-screen') - - const handleInput = (text: string) => { - setText(text) - } - - useEffect(() => { - if (!isModalActive) { - const block = bot.blockAtCursor() - if (block) { - bot.updateSign(block, text) - } - } - }, [isModalActive]) - - useMemo(() => { - bot._client.on('open_sign_entity', (packet) => { - showModal({ reactType: 'signs-editor-screen' }) - }) - }, []) - - if (!isModalActive) return null - return -} diff --git a/src/react/prosemirror-markdown.ts b/src/react/prosemirror-markdown.ts index aada0400..37ebb184 100644 --- a/src/react/prosemirror-markdown.ts +++ b/src/react/prosemirror-markdown.ts @@ -10,8 +10,7 @@ export class ProseMirrorView { 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 - // check-build error: fullMenu[1][0].options.label = 'Color' - // fullMenu[1][0].options.label = 'Color' + // fullMenu[1][0].options.label = 'Color' check-build error: fullMenu[1][0].options.label = 'Color' // fullMenu[1][0].content // replace with colors fullMenu[1].splice(1, 1) // remove the type menu this.view = new EditorView(target, { diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 24abf3d6..b2ec3cfc 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -16,7 +16,7 @@ import EnterFullscreenButton from './react/EnterFullscreenButton' import ChatProvider from './react/ChatProvider' import TitleProvider from './react/TitleProvider' import ScoreboardProvider from './react/ScoreboardProvider' -import SignsEditorProvider from './react/SignsEditorProvider' +import SignEditorProvider from './react/SignEditorProvider' import SoundMuffler from './react/SoundMuffler' import TouchControls from './react/TouchControls' import widgets from './react/widgets' @@ -63,7 +63,7 @@ const InGameUi = () => { - + From ea0d35e114afa54728c480b8c45ca33c49492b1d Mon Sep 17 00:00:00 2001 From: gguio Date: Fri, 15 Mar 2024 17:53:48 +0400 Subject: [PATCH 06/22] JSON text can be passed as text + autoswitch modes --- src/react/SignEditor.tsx | 3 +- src/react/SignEditorProvider.tsx | 67 +++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/react/SignEditor.tsx b/src/react/SignEditor.tsx index 85833bb6..83348d32 100644 --- a/src/react/SignEditor.tsx +++ b/src/react/SignEditor.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef } from 'react' +import { MessageFormatPart } from '../botUtils' import { ProseMirrorView } from './prosemirror-markdown' import 'prosemirror-view/style/prosemirror.css' import 'prosemirror-menu/style/menu.css' @@ -8,7 +9,7 @@ import './SignEditor.css' const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg==' type Props = { - handleInput: (text: string) => void, + handleInput: (text: string | MessageFormatPart[]) => void, isWysiwyg: boolean } diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx index 31d3d77a..0a84f865 100644 --- a/src/react/SignEditorProvider.tsx +++ b/src/react/SignEditorProvider.tsx @@ -1,17 +1,34 @@ import { useMemo, useEffect, useState } from 'react' import { showModal } from '../globalState' +import { MessageFormatPart } from '../botUtils' import { useIsModalActive } from './utils' import SignEditor 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 [text, setText] = useState('') + const [text, setText] = useState('') + const [enableWysiwyg, setEnableWysiwyg] = useState(false) const isModalActive = useIsModalActive('signs-editor-screen') - const handleInput = (text: string) => { - if (text.length > 22 || text.includes('\n')) { - const lines = text.split('\n') + const handleInput = (newText: string | MessageFormatPart[]) => { + if (typeof newText !== 'string') { + setText(newText) + return + } + if (newText.length > 22 || newText.includes('\n')) { + const lines = newText.split('\n') const result: string[] = [] for (const line of lines) { let startIndex = 0 @@ -26,21 +43,40 @@ export default () => { } setText(result) } else { - setText(text) + setText(newText) } } useEffect(() => { if (!isModalActive) { if (location) { - console.log(location) - bot._client.write('update_sign', { - location, - text1: typeof text === 'string' ? text : text[0] ?? '', - text2: typeof text === 'string' ? '' : text[1] ?? '', - text3: typeof text === 'string' ? '' : text[2] ?? '', - text4: typeof text === 'string' ? '' : text[3] ?? '' - }) + if (typeof text === 'string') { + bot._client.write('update_sign', { + location, + text1: text, + text2: '', + text3: '', + text4: '' + }) + } else if (text.length === 0) { + console.error('text array is empty. It should never happen') + } else if (typeof text[0] === 'string') { + bot._client.write('update_sign', { + location, + text1: text[0], + text2: text[1] ?? '', + text3: text[2] ?? '', + text4: text[3] ?? '' + }) + } else if (typeof text[0] === 'object') { + bot._client.write('update_sign', { + location, + text1: JSON.stringify(text[0]), + text2: text[1] ? JSON.stringify(text[1]) : '', + text3: text[2] ? JSON.stringify(text[2]) : '', + text4: text[3] ? JSON.stringify(text[3]) : '' + }) + } } } }, [isModalActive]) @@ -50,8 +86,11 @@ export default () => { setLocation(prev => packet.location) showModal({ reactType: 'signs-editor-screen' }) }) + isWysiwyg().then((value) => { + setEnableWysiwyg(value) + }) }, []) if (!isModalActive) return null - return + return } From 9507d8f4b4d7d2e933bf888708bd176e87d3188f Mon Sep 17 00:00:00 2001 From: gguio Date: Sat, 16 Mar 2024 18:05:20 +0400 Subject: [PATCH 07/22] Done button added + 2 prosemirror bug fixed + font size fixed --- src/react/SignEditor.css | 14 +++++++++++++- src/react/SignEditor.tsx | 13 +++++++++---- src/react/SignEditorProvider.tsx | 8 ++++++-- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/react/SignEditor.css b/src/react/SignEditor.css index 0b6e64b0..0017e010 100644 --- a/src/react/SignEditor.css +++ b/src/react/SignEditor.css @@ -27,7 +27,7 @@ .signs-editor { font: inherit; - font-size: 1.5rem; + font-size: 215%; width: 90%; max-height: 90%; background-color: rgba(255, 255, 255, 0); @@ -43,6 +43,11 @@ text-align: center; } +.ProseMirror p { + font-size: 215%; + text-align: center; +} + .wysiwyg-editor { color: black; background-color: rgba(255, 255, 255, 0.7); @@ -51,3 +56,10 @@ margin: 0px; white-space: pre-wrap; } + +.sign-editor-button { + position: absolute; + right: 0px; + bottom: 0px; + width: 75px; +} diff --git a/src/react/SignEditor.tsx b/src/react/SignEditor.tsx index 83348d32..1ac17b6f 100644 --- a/src/react/SignEditor.tsx +++ b/src/react/SignEditor.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef } from 'react' import { MessageFormatPart } from '../botUtils' import { ProseMirrorView } from './prosemirror-markdown' +import Button from './Button' import 'prosemirror-view/style/prosemirror.css' import 'prosemirror-menu/style/menu.css' import './SignEditor.css' @@ -10,16 +11,19 @@ const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAA type Props = { handleInput: (text: string | MessageFormatPart[]) => void, - isWysiwyg: boolean + isWysiwyg: boolean, + handleClick?: () => void } -export default ({ handleInput, isWysiwyg }: Props) => { +export default ({ handleInput, isWysiwyg, handleClick }: Props) => { const ref = useRef(null) + const mount = useRef(false) useEffect(() => { - if (ref.current) { + if (ref.current && !mount.current) { + mount.current = true const view = new ProseMirrorView(ref.current, '') - } + } }, [ref.current]) return
@@ -35,6 +39,7 @@ export default ({ handleInput, isWysiwyg }: Props) => { }}> )} +
} diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx index 0a84f865..9f9da207 100644 --- a/src/react/SignEditorProvider.tsx +++ b/src/react/SignEditorProvider.tsx @@ -1,5 +1,5 @@ import { useMemo, useEffect, useState } from 'react' -import { showModal } from '../globalState' +import { showModal, hideModal } from '../globalState' import { MessageFormatPart } from '../botUtils' import { useIsModalActive } from './utils' import SignEditor from './SignEditor' @@ -22,6 +22,10 @@ export default () => { const [enableWysiwyg, setEnableWysiwyg] = useState(false) const isModalActive = useIsModalActive('signs-editor-screen') + const handleClick = () => { + hideModal({ reactType: 'signs-editor-screen' }) + } + const handleInput = (newText: string | MessageFormatPart[]) => { if (typeof newText !== 'string') { setText(newText) @@ -92,5 +96,5 @@ export default () => { }, []) if (!isModalActive) return null - return + return } From b7f581abdc0b8ce35597bba79d64ab0ba727df70 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 17 Mar 2024 01:59:32 +0300 Subject: [PATCH 08/22] fix promise mirror bug, improve ui --- src/controls.ts | 9 +++++++++ src/react/SignEditor.css | 13 +++++++++++-- src/react/SignEditor.tsx | 6 +++--- src/react/SignEditorProvider.tsx | 11 +++++++---- src/react/prosemirror-markdown.ts | 2 +- src/reactUi.tsx | 2 +- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 068b16b0..3709a31a 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/react/SignEditor.css b/src/react/SignEditor.css index 0017e010..4d7b2fa7 100644 --- a/src/react/SignEditor.css +++ b/src/react/SignEditor.css @@ -23,6 +23,7 @@ z-index: -1; width: 100%; height: 100%; + image-rendering: pixelated; } .signs-editor { @@ -39,7 +40,7 @@ -moz-box-shadow: none; box-shadow: none; box-sizing: border-box; - resize: none; + resize: none; text-align: center; } @@ -50,11 +51,11 @@ .wysiwyg-editor { color: black; - background-color: rgba(255, 255, 255, 0.7); width: 90%; max-height: 90%; margin: 0px; white-space: pre-wrap; + border: 1px solid #ccc; } .sign-editor-button { @@ -63,3 +64,11 @@ bottom: 0px; width: 75px; } + +.ProseMirror-menubar { + background-color: rgba(255, 255, 255, 0.7); +} + +.ProseMirror { + +} diff --git a/src/react/SignEditor.tsx b/src/react/SignEditor.tsx index 1ac17b6f..d3722960 100644 --- a/src/react/SignEditor.tsx +++ b/src/react/SignEditor.tsx @@ -12,7 +12,7 @@ const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAA type Props = { handleInput: (text: string | MessageFormatPart[]) => void, isWysiwyg: boolean, - handleClick?: () => void + handleClick?: () => void } export default ({ handleInput, isWysiwyg, handleClick }: Props) => { @@ -23,14 +23,14 @@ export default ({ handleInput, isWysiwyg, handleClick }: Props) => { if (ref.current && !mount.current) { mount.current = true const view = new ProseMirrorView(ref.current, '') - } + } }, [ref.current]) return
{isWysiwyg ? ( -

+

) : ( - )} + ) : [1, 2, 3, 4].map((value, index) => { + return { + handleInput(e.currentTarget) + }} /> + }) + }
diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx index 734137c0..9623705c 100644 --- a/src/react/SignEditorProvider.tsx +++ b/src/react/SignEditorProvider.tsx @@ -1,4 +1,4 @@ -import { useMemo, useEffect, useState } from 'react' +import { useMemo, useEffect, useState, useRef } from 'react' import { showModal, hideModal } from '../globalState' import { MessageFormatPart } from '../botUtils' import { setDoPreventDefault } from '../controls' @@ -20,7 +20,7 @@ const isWysiwyg = async () => { export default () => { const [location, setLocation] = useState<{x: number, y: number, z: number} | null>(null) - const [text, setText] = useState('') + const text = useRef([]) const [enableWysiwyg, setEnableWysiwyg] = useState(false) const isModalActive = useIsModalActive('signs-editor-screen') @@ -28,29 +28,20 @@ export default () => { hideModal({ reactType: 'signs-editor-screen' }) } - const handleInput = (newText: string | MessageFormatPart[]) => { - if (typeof newText !== 'string') { - setText(newText) - return + const handleInput = (target: HTMLInputElement) => { + const specialSymbols = /[;|',.()[\]{} ]/ + let addLength = 0 + for (const letter of target.value) { + if (specialSymbols.test(letter)) { + addLength += 1 - 1 / 1.46 + } } - if (newText.length > 22 || newText.includes('\n')) { - const lines = newText.split('\n') - const result: string[] = [] - for (const line of lines) { - let startIndex = 0 - while (startIndex < line.length) { - if (startIndex + 22 < line.length) { - result.push(line.slice(startIndex, startIndex + 22)) - } else { - result.push(line.slice(startIndex)) - } - startIndex += 22 - } - } - setText(result) + if (text.current.length < Number(target.dataset.key) + 1) { + text.current.push({ text: target.value }) } else { - setText(newText) + text.current[Number(target.dataset.key)] = { text: target.value } } + target.setAttribute('maxlength', `${15 + Math.ceil(addLength)}`) } useEffect(() => { @@ -58,33 +49,13 @@ export default () => { if (!isModalActive) { if (location) { - if (typeof text === 'string') { - bot._client.write('update_sign', { - location, - text1: text, - text2: '', - text3: '', - text4: '' - }) - } else if (text.length === 0) { - console.error('text array is empty. It should never happen') - } else if (typeof text[0] === 'string') { - bot._client.write('update_sign', { - location, - text1: text[0], - text2: text[1] ?? '', - text3: text[2] ?? '', - text4: text[3] ?? '' - }) - } else if (typeof text[0] === 'object') { - bot._client.write('update_sign', { - location, - text1: JSON.stringify(text[0]), - text2: text[1] ? JSON.stringify(text[1]) : '', - text3: text[2] ? JSON.stringify(text[2]) : '', - text4: text[3] ? JSON.stringify(text[3]) : '' - }) - } + bot._client.write('update_sign', { + location, + text1: text.current[0] ? JSON.stringify(text.current[0]) : '', + text2: text.current[1] ? JSON.stringify(text.current[1]) : '', + text3: text.current[2] ? JSON.stringify(text.current[2]) : '', + text4: text.current[3] ? JSON.stringify(text.current[3]) : '' + }) } } }, [isModalActive]) From ebdb0dda518408fadcbe10c7940dc0e27c4f321c Mon Sep 17 00:00:00 2001 From: gguio Date: Mon, 18 Mar 2024 02:25:38 +0400 Subject: [PATCH 11/22] ;|'., are counted as 3 --- src/react/SignEditorProvider.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx index 9623705c..e9531559 100644 --- a/src/react/SignEditorProvider.tsx +++ b/src/react/SignEditorProvider.tsx @@ -29,11 +29,14 @@ export default () => { } const handleInput = (target: HTMLInputElement) => { - const specialSymbols = /[;|',.()[\]{} ]/ + const smallSymbols = /[()[\]{} ]/ + const largeSymbols = /[;|',.]/ let addLength = 0 for (const letter of target.value) { - if (specialSymbols.test(letter)) { + if (smallSymbols.test(letter)) { addLength += 1 - 1 / 1.46 + } else if (largeSymbols.test(letter)) { + addLength -= 2 } } if (text.current.length < Number(target.dataset.key) + 1) { From d03989f9fca2168f4a40ec88aec581da66af1fb8 Mon Sep 17 00:00:00 2001 From: gguio Date: Mon, 18 Mar 2024 14:22:14 +0400 Subject: [PATCH 12/22] Basic mod is done --- src/react/SignEditor.tsx | 11 ++++++++--- src/react/SignEditorProvider.tsx | 22 ++++++++++------------ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/react/SignEditor.tsx b/src/react/SignEditor.tsx index aaefa9e6..c2c7cc33 100644 --- a/src/react/SignEditor.tsx +++ b/src/react/SignEditor.tsx @@ -12,17 +12,18 @@ const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAA type Props = { handleInput: (target: HTMLInputElement) => void, isWysiwyg: boolean, - handleClick?: () => void + handleClick?: (view: ProseMirrorView) => void } export default ({ handleInput, isWysiwyg, handleClick }: Props) => { const ref = useRef(null) const mount = useRef(false) + const editorView = useRef(null) useEffect(() => { if (ref.current && !mount.current) { mount.current = true - const view = new ProseMirrorView(ref.current, '') + editorView.current = new ProseMirrorView(ref.current, '') } }, [ref.current]) @@ -37,7 +38,11 @@ export default ({ handleInput, isWysiwyg, handleClick }: Props) => { }} /> }) } -