mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-04-24 20:07:52 +00:00
added mentions and search
This commit is contained in:
parent
8679911c65
commit
86ed01cd1d
535
package-lock.json
generated
535
package-lock.json
generated
@ -33,6 +33,7 @@
|
|||||||
"@tiptap/extension-color": "^2.5.9",
|
"@tiptap/extension-color": "^2.5.9",
|
||||||
"@tiptap/extension-highlight": "^2.6.6",
|
"@tiptap/extension-highlight": "^2.6.6",
|
||||||
"@tiptap/extension-image": "^2.6.6",
|
"@tiptap/extension-image": "^2.6.6",
|
||||||
|
"@tiptap/extension-mention": "^2.9.1",
|
||||||
"@tiptap/extension-placeholder": "^2.6.2",
|
"@tiptap/extension-placeholder": "^2.6.2",
|
||||||
"@tiptap/extension-text-style": "^2.5.9",
|
"@tiptap/extension-text-style": "^2.5.9",
|
||||||
"@tiptap/extension-underline": "^2.6.6",
|
"@tiptap/extension-underline": "^2.6.6",
|
||||||
@ -50,6 +51,7 @@
|
|||||||
"dompurify": "^3.1.6",
|
"dompurify": "^3.1.6",
|
||||||
"emoji-picker-react": "^4.12.0",
|
"emoji-picker-react": "^4.12.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
"jssha": "3.3.1",
|
"jssha": "3.3.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mime": "^4.0.4",
|
"mime": "^4.0.4",
|
||||||
@ -73,7 +75,10 @@
|
|||||||
"short-unique-id": "^5.2.0",
|
"short-unique-id": "^5.2.0",
|
||||||
"slate": "^0.103.0",
|
"slate": "^0.103.0",
|
||||||
"slate-react": "^0.109.0",
|
"slate-react": "^0.109.0",
|
||||||
"tiptap-extension-resize-image": "^1.1.8"
|
"tippy.js": "^6.3.7",
|
||||||
|
"tiptap-extension-resize-image": "^1.1.8",
|
||||||
|
"vite-plugin-top-level-await": "^1.4.4",
|
||||||
|
"vite-plugin-wasm": "^3.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.3.0",
|
"@testing-library/dom": "^10.3.0",
|
||||||
@ -2020,7 +2025,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"aix"
|
"aix"
|
||||||
@ -2036,7 +2040,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@ -2052,7 +2055,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@ -2068,7 +2070,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@ -2084,7 +2085,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@ -2100,7 +2100,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@ -2116,7 +2115,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
@ -2132,7 +2130,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
@ -2148,7 +2145,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2164,7 +2160,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2180,7 +2175,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2196,7 +2190,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2212,7 +2205,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2228,7 +2220,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2244,7 +2235,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2260,7 +2250,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2276,7 +2265,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -2292,7 +2280,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"netbsd"
|
"netbsd"
|
||||||
@ -2308,7 +2295,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"openbsd"
|
"openbsd"
|
||||||
@ -2324,7 +2310,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"sunos"
|
"sunos"
|
||||||
@ -2340,7 +2325,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@ -2356,7 +2340,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@ -2372,7 +2355,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@ -3021,7 +3003,7 @@
|
|||||||
"version": "0.3.6",
|
"version": "0.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
||||||
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
@ -3412,9 +3394,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@remirror/core-constants": {
|
"node_modules/@remirror/core-constants": {
|
||||||
"version": "2.0.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
|
||||||
"integrity": "sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ=="
|
"integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg=="
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/plugin-virtual": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.13.0",
|
"version": "4.13.0",
|
||||||
@ -3423,7 +3421,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@ -3436,7 +3433,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
@ -3449,7 +3445,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@ -3462,7 +3457,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@ -3475,7 +3469,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -3488,7 +3481,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -3501,7 +3493,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -3514,7 +3505,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -3527,7 +3517,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -3540,7 +3529,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
@ -3553,7 +3541,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@ -3566,7 +3553,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@ -3579,12 +3565,23 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@selderee/plugin-htmlparser2": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"selderee": "^0.11.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sinclair/typebox": {
|
"node_modules/@sinclair/typebox": {
|
||||||
"version": "0.27.8",
|
"version": "0.27.8",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||||
@ -3592,6 +3589,206 @@
|
|||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@swc/core": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-dYyEkO6mRYtZFpnOsnYzv9rY69fHAHoawYOjGOEcxk9WYtaJhowMdP/w6NcOKnz2G7GlZaenjkzkMa6ZeQeMsg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@swc/counter": "^0.1.3",
|
||||||
|
"@swc/types": "^0.1.15"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/swc"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@swc/core-darwin-arm64": "1.9.2",
|
||||||
|
"@swc/core-darwin-x64": "1.9.2",
|
||||||
|
"@swc/core-linux-arm-gnueabihf": "1.9.2",
|
||||||
|
"@swc/core-linux-arm64-gnu": "1.9.2",
|
||||||
|
"@swc/core-linux-arm64-musl": "1.9.2",
|
||||||
|
"@swc/core-linux-x64-gnu": "1.9.2",
|
||||||
|
"@swc/core-linux-x64-musl": "1.9.2",
|
||||||
|
"@swc/core-win32-arm64-msvc": "1.9.2",
|
||||||
|
"@swc/core-win32-ia32-msvc": "1.9.2",
|
||||||
|
"@swc/core-win32-x64-msvc": "1.9.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@swc/helpers": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@swc/helpers": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-darwin-arm64": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-nETmsCoY29krTF2PtspEgicb3tqw7Ci5sInTI03EU5zpqYbPjoPH99BVTjj0OsF53jP5MxwnLI5Hm21lUn1d6A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-darwin-x64": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-9gD+bwBz8ZByjP6nZTXe/hzd0tySIAjpDHgkFiUrc+5zGF+rdTwhcNrzxNHJmy6mw+PW38jqII4uspFHUqqxuQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-kYq8ief1Qrn+WmsTWAYo4r+Coul4dXN6cLFjiPZ29Cv5pyU+GFvSPAB4bEdMzwy99rCR0u2P10UExaeCjurjvg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-n0W4XiXlmEIVqxt+rD3ZpkogsEWUk1jJ+i5bQNgB+1JuWh0fBE8c/blDgTQXa0GB5lTPVDZQussgdNOCnAZwiA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-linux-arm64-musl": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-8xzrOmsyCC1zrx2Wzx/h8dVsdewO1oMCwBTLc1gSJ/YllZYTb04pNm6NsVbzUX2tKddJVRgSJXV10j/NECLwpA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-linux-x64-gnu": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-kZrNz/PjRQKcchWF6W292jk3K44EoVu1ad5w+zbS4jekIAxsM8WwQ1kd+yjUlN9jFcF8XBat5NKIs9WphJCVXg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-linux-x64-musl": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-TTIpR4rjMkhX1lnFR+PSXpaL83TrQzp9znRdp2TzYrODlUd/R20zOwSo9vFLCyH6ZoD47bccY7QeGZDYT3nlRg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-+Eg2d4icItKC0PMjZxH7cSYFLWk0aIp94LNmOw6tPq0e69ax6oh10upeq0D1fjWsKLmOJAWEvnXlayZcijEXDw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-nLWBi4vZDdM/LkiQmPCakof8Dh1/t5EM7eudue04V1lIcqx9YHVRS3KMwEaCoHLGg0c312Wm4YgrWQd9vwZ5zQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/core-win32-x64-msvc": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-ik/k+JjRJBFkXARukdU82tSVx0CbExFQoQ78qTO682esbYXzjdB5eLVkoUbwen299pnfr88Kn4kyIqFPTje8Xw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/counter": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@swc/types": {
|
||||||
|
"version": "0.1.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.15.tgz",
|
||||||
|
"integrity": "sha512-XKaZ+dzDIQ9Ot9o89oJQ/aluI17+VvUnIpYJTcZtvv1iYX6MzHh3Ik2CSR7MdPKpPwfZXHBeCingb2b4PoDVdw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@swc/counter": "^0.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tanstack/react-virtual": {
|
"node_modules/@tanstack/react-virtual": {
|
||||||
"version": "3.10.8",
|
"version": "3.10.8",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.8.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.8.tgz",
|
||||||
@ -3898,15 +4095,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tiptap/core": {
|
"node_modules/@tiptap/core": {
|
||||||
"version": "2.6.6",
|
"version": "2.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.6.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.9.1.tgz",
|
||||||
"integrity": "sha512-VO5qTsjt6rwworkuo0s5AqYMfDA0ZwiTiH6FHKFSu2G/6sS7HKcc/LjPq+5Legzps4QYdBDl3W28wGsGuS1GdQ==",
|
"integrity": "sha512-tifnLL/ARzQ6/FGEJjVwj9UT3v+pENdWHdk9x6F3X0mB1y0SeCjV21wpFLYESzwNdBPAj8NMp8Behv7dBnhIfw==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ueberdosis"
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tiptap/pm": "^2.6.6"
|
"@tiptap/pm": "^2.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tiptap/extension-blockquote": {
|
"node_modules/@tiptap/extension-blockquote": {
|
||||||
@ -4151,6 +4348,20 @@
|
|||||||
"@tiptap/core": "^2.5.9"
|
"@tiptap/core": "^2.5.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tiptap/extension-mention": {
|
||||||
|
"version": "2.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-2.9.1.tgz",
|
||||||
|
"integrity": "sha512-2IzunpivdNtDNdtAXwRiQbNhTm87zrbkhz1cCE+2y9pWiX1QLXyx0HQq/DIAjxp6v7y4sIh+5UTUTFlH7vD9wQ==",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tiptap/core": "^2.7.0",
|
||||||
|
"@tiptap/pm": "^2.7.0",
|
||||||
|
"@tiptap/suggestion": "^2.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tiptap/extension-ordered-list": {
|
"node_modules/@tiptap/extension-ordered-list": {
|
||||||
"version": "2.5.9",
|
"version": "2.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.9.tgz",
|
||||||
@ -4237,13 +4448,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tiptap/pm": {
|
"node_modules/@tiptap/pm": {
|
||||||
"version": "2.6.6",
|
"version": "2.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.6.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.9.1.tgz",
|
||||||
"integrity": "sha512-56FGLPn3fwwUlIbLs+BO21bYfyqP9fKyZQbQyY0zWwA/AG2kOwoXaRn7FOVbjP6CylyWpFJnpRRmgn694QKHEg==",
|
"integrity": "sha512-mvV86fr7kEuDYEApQ2uMPCKL2uagUE0BsXiyyz3KOkY1zifyVm1fzdkscb24Qy1GmLzWAIIihA+3UHNRgYdOlQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prosemirror-changeset": "^2.2.1",
|
"prosemirror-changeset": "^2.2.1",
|
||||||
"prosemirror-collab": "^1.3.1",
|
"prosemirror-collab": "^1.3.1",
|
||||||
"prosemirror-commands": "^1.5.2",
|
"prosemirror-commands": "^1.6.0",
|
||||||
"prosemirror-dropcursor": "^1.8.1",
|
"prosemirror-dropcursor": "^1.8.1",
|
||||||
"prosemirror-gapcursor": "^1.3.2",
|
"prosemirror-gapcursor": "^1.3.2",
|
||||||
"prosemirror-history": "^1.4.1",
|
"prosemirror-history": "^1.4.1",
|
||||||
@ -4251,14 +4462,14 @@
|
|||||||
"prosemirror-keymap": "^1.2.2",
|
"prosemirror-keymap": "^1.2.2",
|
||||||
"prosemirror-markdown": "^1.13.0",
|
"prosemirror-markdown": "^1.13.0",
|
||||||
"prosemirror-menu": "^1.2.4",
|
"prosemirror-menu": "^1.2.4",
|
||||||
"prosemirror-model": "^1.22.2",
|
"prosemirror-model": "^1.22.3",
|
||||||
"prosemirror-schema-basic": "^1.2.3",
|
"prosemirror-schema-basic": "^1.2.3",
|
||||||
"prosemirror-schema-list": "^1.4.1",
|
"prosemirror-schema-list": "^1.4.1",
|
||||||
"prosemirror-state": "^1.4.3",
|
"prosemirror-state": "^1.4.3",
|
||||||
"prosemirror-tables": "^1.4.0",
|
"prosemirror-tables": "^1.4.0",
|
||||||
"prosemirror-trailing-node": "^2.0.9",
|
"prosemirror-trailing-node": "^3.0.0",
|
||||||
"prosemirror-transform": "^1.9.0",
|
"prosemirror-transform": "^1.10.0",
|
||||||
"prosemirror-view": "^1.33.9"
|
"prosemirror-view": "^1.34.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -4316,6 +4527,20 @@
|
|||||||
"url": "https://github.com/sponsors/ueberdosis"
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tiptap/suggestion": {
|
||||||
|
"version": "2.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.9.1.tgz",
|
||||||
|
"integrity": "sha512-MMxwpbtocxUsbmc8qtFY1AQYNTW5i/M4aNSv9zsKKRISaS5hMD7XVrw2eod0x0yEqZU3izLiPDZPmgr8glF+jQ==",
|
||||||
|
"peer": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tiptap/core": "^2.7.0",
|
||||||
|
"@tiptap/pm": "^2.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@transistorsoft/capacitor-background-fetch": {
|
"node_modules/@transistorsoft/capacitor-background-fetch": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@transistorsoft/capacitor-background-fetch/-/capacitor-background-fetch-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@transistorsoft/capacitor-background-fetch/-/capacitor-background-fetch-6.0.1.tgz",
|
||||||
@ -4392,8 +4617,7 @@
|
|||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||||
"devOptional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/filesystem": {
|
"node_modules/@types/filesystem": {
|
||||||
"version": "0.0.35",
|
"version": "0.0.35",
|
||||||
@ -5338,7 +5562,7 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/cac": {
|
"node_modules/cac": {
|
||||||
@ -6026,6 +6250,14 @@
|
|||||||
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/deepmerge": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/define-data-property": {
|
"node_modules/define-data-property": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||||
@ -6148,11 +6380,62 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dom-serializer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.2",
|
||||||
|
"entities": "^4.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domelementtype": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/domhandler": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "3.1.6",
|
"version": "3.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
|
||||||
"integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="
|
"integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/domutils": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.49",
|
"version": "1.5.49",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.49.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.49.tgz",
|
||||||
@ -6249,7 +6532,6 @@
|
|||||||
"version": "0.19.12",
|
"version": "0.19.12",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
|
||||||
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
|
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
|
||||||
"devOptional": true,
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
@ -6907,7 +7189,6 @@
|
|||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@ -7191,6 +7472,39 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-to-text": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@selderee/plugin-htmlparser2": "^0.11.0",
|
||||||
|
"deepmerge": "^4.3.1",
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"htmlparser2": "^8.0.2",
|
||||||
|
"selderee": "^0.11.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/htmlparser2": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/http-proxy-agent": {
|
"node_modules/http-proxy-agent": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||||
@ -7852,6 +8166,14 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/leac": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/levn": {
|
"node_modules/levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
@ -8243,7 +8565,6 @@
|
|||||||
"version": "3.3.7",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"devOptional": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -10910,6 +11231,18 @@
|
|||||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parseley": {
|
||||||
|
"version": "0.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
|
||||||
|
"integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
|
||||||
|
"dependencies": {
|
||||||
|
"leac": "^0.6.0",
|
||||||
|
"peberminta": "^0.9.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/path-exists": {
|
"node_modules/path-exists": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
@ -10986,6 +11319,14 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/peberminta": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pend": {
|
"node_modules/pend": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||||
@ -11037,7 +11378,6 @@
|
|||||||
"version": "8.4.37",
|
"version": "8.4.37",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.37.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.37.tgz",
|
||||||
"integrity": "sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==",
|
"integrity": "sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==",
|
||||||
"devOptional": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -11310,11 +11650,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prosemirror-trailing-node": {
|
"node_modules/prosemirror-trailing-node": {
|
||||||
"version": "2.0.9",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
|
||||||
"integrity": "sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg==",
|
"integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remirror/core-constants": "^2.0.2",
|
"@remirror/core-constants": "3.0.0",
|
||||||
"escape-string-regexp": "^4.0.0"
|
"escape-string-regexp": "^4.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@ -11335,17 +11675,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prosemirror-transform": {
|
"node_modules/prosemirror-transform": {
|
||||||
"version": "1.9.0",
|
"version": "1.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.2.tgz",
|
||||||
"integrity": "sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==",
|
"integrity": "sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prosemirror-model": "^1.21.0"
|
"prosemirror-model": "^1.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prosemirror-view": {
|
"node_modules/prosemirror-view": {
|
||||||
"version": "1.33.9",
|
"version": "1.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.9.tgz",
|
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.36.0.tgz",
|
||||||
"integrity": "sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==",
|
"integrity": "sha512-U0GQd5yFvV5qUtT41X1zCQfbw14vkbbKwLlQXhdylEmgpYVHkefXYcC4HHwWOfZa3x6Y8wxDLUBv7dxN5XQ3nA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prosemirror-model": "^1.20.0",
|
"prosemirror-model": "^1.20.0",
|
||||||
"prosemirror-state": "^1.0.0",
|
"prosemirror-state": "^1.0.0",
|
||||||
@ -12059,7 +12399,6 @@
|
|||||||
"version": "4.13.0",
|
"version": "4.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
|
||||||
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
|
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
|
||||||
"devOptional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.5"
|
"@types/estree": "1.0.5"
|
||||||
},
|
},
|
||||||
@ -12213,6 +12552,17 @@
|
|||||||
"compute-scroll-into-view": "^3.0.2"
|
"compute-scroll-into-view": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/selderee": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
|
||||||
|
"dependencies": {
|
||||||
|
"parseley": "^0.12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.6.0",
|
"version": "7.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||||
@ -12428,7 +12778,6 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||||
"devOptional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -12437,7 +12786,7 @@
|
|||||||
"version": "0.5.21",
|
"version": "0.5.21",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
@ -12448,7 +12797,7 @@
|
|||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@ -12664,7 +13013,7 @@
|
|||||||
"version": "5.36.0",
|
"version": "5.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
|
||||||
"integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==",
|
"integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.3",
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
@ -12683,7 +13032,7 @@
|
|||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/text-table": {
|
"node_modules/text-table": {
|
||||||
@ -13135,6 +13484,18 @@
|
|||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vfile": {
|
"node_modules/vfile": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
|
||||||
@ -13170,7 +13531,6 @@
|
|||||||
"version": "5.1.6",
|
"version": "5.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
|
||||||
"integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==",
|
"integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==",
|
||||||
"devOptional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.19.3",
|
"esbuild": "^0.19.3",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.35",
|
||||||
@ -13244,6 +13604,27 @@
|
|||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite-plugin-top-level-await": {
|
||||||
|
"version": "1.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.4.4.tgz",
|
||||||
|
"integrity": "sha512-QyxQbvcMkgt+kDb12m2P8Ed35Sp6nXP+l8ptGrnHV9zgYDUpraO0CPdlqLSeBqvY2DToR52nutDG7mIHuysdiw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@rollup/plugin-virtual": "^3.0.2",
|
||||||
|
"@swc/core": "^1.7.0",
|
||||||
|
"uuid": "^10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": ">=2.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite-plugin-wasm": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-plugin-wasm/-/vite-plugin-wasm-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-tVhz6w+W9MVsOCHzxo6SSMSswCeIw4HTrXEi6qL3IRzATl83jl09JVO1djBqPSwfjgnpVHNLYcaMbaDX5WB/pg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": "^2 || ^3 || ^4 || ^5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vitest": {
|
"node_modules/vitest": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz",
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
"@tiptap/extension-placeholder": "^2.6.2",
|
"@tiptap/extension-placeholder": "^2.6.2",
|
||||||
"@tiptap/extension-text-style": "^2.5.9",
|
"@tiptap/extension-text-style": "^2.5.9",
|
||||||
"@tiptap/extension-underline": "^2.6.6",
|
"@tiptap/extension-underline": "^2.6.6",
|
||||||
|
"@tiptap/extension-mention": "^2.9.1",
|
||||||
"@tiptap/pm": "^2.5.9",
|
"@tiptap/pm": "^2.5.9",
|
||||||
"@tiptap/react": "^2.5.9",
|
"@tiptap/react": "^2.5.9",
|
||||||
"@tiptap/starter-kit": "^2.5.9",
|
"@tiptap/starter-kit": "^2.5.9",
|
||||||
@ -77,7 +78,11 @@
|
|||||||
"short-unique-id": "^5.2.0",
|
"short-unique-id": "^5.2.0",
|
||||||
"slate": "^0.103.0",
|
"slate": "^0.103.0",
|
||||||
"slate-react": "^0.109.0",
|
"slate-react": "^0.109.0",
|
||||||
"tiptap-extension-resize-image": "^1.1.8"
|
"tiptap-extension-resize-image": "^1.1.8",
|
||||||
|
"vite-plugin-top-level-await": "^1.4.4",
|
||||||
|
"vite-plugin-wasm": "^3.3.0",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
|
"tippy.js": "^6.3.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.3.0",
|
"@testing-library/dom": "^10.3.0",
|
||||||
|
@ -1002,7 +1002,7 @@ function App() {
|
|||||||
.sendMessage("decryptWallet", {
|
.sendMessage("decryptWallet", {
|
||||||
password: walletToBeDownloadedPassword,
|
password: walletToBeDownloadedPassword,
|
||||||
wallet,
|
wallet,
|
||||||
})
|
},120000)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response && !response.error) {
|
if (response && !response.error) {
|
||||||
setRawWallet(wallet);
|
setRawWallet(wallet);
|
||||||
@ -1126,7 +1126,7 @@ function App() {
|
|||||||
.sendMessage("decryptWallet", {
|
.sendMessage("decryptWallet", {
|
||||||
password: authenticatePassword,
|
password: authenticatePassword,
|
||||||
wallet: rawWallet,
|
wallet: rawWallet,
|
||||||
})
|
}, 120000)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response && !response.error) {
|
if (response && !response.error) {
|
||||||
setAuthenticatePassword("");
|
setAuthenticatePassword("");
|
||||||
|
@ -6,15 +6,15 @@ const MessageQueueContext = createContext(null);
|
|||||||
export const useMessageQueue = () => useContext(MessageQueueContext);
|
export const useMessageQueue = () => useContext(MessageQueueContext);
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 8 });
|
const uid = new ShortUniqueId({ length: 8 });
|
||||||
let messageQueue = []; // Global message queue
|
|
||||||
|
|
||||||
export const MessageQueueProvider = ({ children }) => {
|
export const MessageQueueProvider = ({ children }) => {
|
||||||
|
const messageQueueRef = useRef([]);
|
||||||
const [queueChats, setQueueChats] = useState({}); // Stores chats and status for display
|
const [queueChats, setQueueChats] = useState({}); // Stores chats and status for display
|
||||||
const isProcessingRef = useRef(false); // To track if the queue is being processed
|
const isProcessingRef = useRef(false); // To track if the queue is being processed
|
||||||
const maxRetries = 3;
|
const maxRetries = 2;
|
||||||
const clearStatesMessageQueueProvider = useCallback(() => {
|
const clearStatesMessageQueueProvider = useCallback(() => {
|
||||||
setQueueChats({});
|
setQueueChats({});
|
||||||
messageQueue = [];
|
messageQueueRef.current = [];
|
||||||
isProcessingRef.current = false;
|
isProcessingRef.current = false;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -36,9 +36,9 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
[groupDirectId]: [...(prev[groupDirectId] || []), chatData]
|
[groupDirectId]: [...(prev[groupDirectId] || []), chatData]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Add the message to the global messageQueue
|
// Add the message to the global messageQueueRef.current
|
||||||
messageQueue = [
|
messageQueueRef.current = [
|
||||||
...messageQueue,
|
...messageQueueRef.current,
|
||||||
{ func: sendMessageFunc, identifier: tempId, groupDirectId, specialId: messageObj?.message?.specialId }
|
{ func: sendMessageFunc, identifier: tempId, groupDirectId, specialId: messageObj?.message?.specialId }
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
processQueue(newMessages, groupDirectId);
|
processQueue(newMessages, groupDirectId);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to process the messageQueue and handle new messages
|
// Function to process the messageQueueRef.current and handle new messages
|
||||||
const processQueue = useCallback(async (newMessages = [], groupDirectId) => {
|
const processQueue = useCallback(async (newMessages = [], groupDirectId) => {
|
||||||
// Filter out any message in the queue that matches the specialId from newMessages
|
// Filter out any message in the queue that matches the specialId from newMessages
|
||||||
messageQueue = messageQueue.filter((msg) => {
|
messageQueueRef.current = messageQueueRef.current.filter((msg) => {
|
||||||
return !newMessages.some(newMsg => newMsg?.specialId === msg?.specialId);
|
return !newMessages.some(newMsg => newMsg?.specialId === msg?.specialId);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -68,7 +68,6 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
return !newMessages.some(newMsg => newMsg?.specialId === chat?.message?.specialId);
|
return !newMessages.some(newMsg => newMsg?.specialId === chat?.message?.specialId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
updatedChats[groupDirectId] = updatedChats[groupDirectId].filter((chat) => {
|
updatedChats[groupDirectId] = updatedChats[groupDirectId].filter((chat) => {
|
||||||
return chat?.status !== 'failed-permanent'
|
return chat?.status !== 'failed-permanent'
|
||||||
});
|
});
|
||||||
@ -82,12 +81,12 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If currently processing or the queue is empty, return
|
// If currently processing or the queue is empty, return
|
||||||
if (isProcessingRef.current || messageQueue.length === 0) return;
|
if (isProcessingRef.current || messageQueueRef.current.length === 0) return;
|
||||||
|
|
||||||
isProcessingRef.current = true; // Lock the queue for processing
|
isProcessingRef.current = true; // Lock the queue for processing
|
||||||
|
|
||||||
while (messageQueue.length > 0) {
|
while (messageQueueRef.current.length > 0) {
|
||||||
const currentMessage = messageQueue[0]; // Get the first message in the queue
|
const currentMessage = messageQueueRef.current[0]; // Get the first message in the queue
|
||||||
const { groupDirectId, identifier } = currentMessage;
|
const { groupDirectId, identifier } = currentMessage;
|
||||||
|
|
||||||
// Update the chat status to 'sending'
|
// Update the chat status to 'sending'
|
||||||
@ -105,11 +104,10 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Execute the function stored in the messageQueue
|
// Execute the function stored in the messageQueueRef.current
|
||||||
await currentMessage.func();
|
await currentMessage.func();
|
||||||
|
// Remove the message from the messageQueueRef.current after successful sending
|
||||||
// Remove the message from the messageQueue after successful sending
|
messageQueueRef.current.shift(); // Slice here remains for successful messages
|
||||||
messageQueue = messageQueue.slice(1); // Slice here remains for successful messages
|
|
||||||
|
|
||||||
// Remove the message from queueChats after success
|
// Remove the message from queueChats after success
|
||||||
// setQueueChats((prev) => {
|
// setQueueChats((prev) => {
|
||||||
@ -138,10 +136,10 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
// Max retries reached, set status to 'failed-permanent'
|
// Max retries reached, set status to 'failed-permanent'
|
||||||
updatedChats[groupDirectId][chatIndex].status = 'failed-permanent';
|
updatedChats[groupDirectId][chatIndex].status = 'failed-permanent';
|
||||||
|
|
||||||
// Remove the message from the messageQueue after max retries
|
// Remove the message from the messageQueueRef.current after max retries
|
||||||
messageQueue = messageQueue.slice(1); // Slice for failed messages after max retries
|
messageQueueRef.current.shift();// Slice for failed messages after max retries
|
||||||
|
|
||||||
// Remove the message from queueChats after failure
|
// // Remove the message from queueChats after failure
|
||||||
// updatedChats[groupDirectId] = updatedChats[groupDirectId].filter(
|
// updatedChats[groupDirectId] = updatedChats[groupDirectId].filter(
|
||||||
// (item) => item.identifier !== identifier
|
// (item) => item.identifier !== identifier
|
||||||
// );
|
// );
|
||||||
@ -149,7 +147,7 @@ export const MessageQueueProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
return updatedChats;
|
return updatedChats;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay between processing each message to avoid overlap
|
// Delay between processing each message to avoid overlap
|
||||||
await new Promise((res) => setTimeout(res, 5000));
|
await new Promise((res) => setTimeout(res, 5000));
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
addEnteredQmailTimestamp,
|
addEnteredQmailTimestamp,
|
||||||
addTimestampEnterChat,
|
addTimestampEnterChat,
|
||||||
addTimestampGroupAnnouncement,
|
addTimestampGroupAnnouncement,
|
||||||
|
addTimestampMention,
|
||||||
addUserSettings,
|
addUserSettings,
|
||||||
banFromGroup,
|
banFromGroup,
|
||||||
cancelBan,
|
cancelBan,
|
||||||
@ -29,6 +30,7 @@ import {
|
|||||||
getTempPublish,
|
getTempPublish,
|
||||||
getTimestampEnterChat,
|
getTimestampEnterChat,
|
||||||
getTimestampGroupAnnouncement,
|
getTimestampGroupAnnouncement,
|
||||||
|
getTimestampMention,
|
||||||
getUserInfo,
|
getUserInfo,
|
||||||
getUserSettings,
|
getUserSettings,
|
||||||
handleActiveGroupDataFromSocket,
|
handleActiveGroupDataFromSocket,
|
||||||
@ -1745,4 +1747,57 @@ export async function publishGroupEncryptedResourceCase(request, event) {
|
|||||||
event.origin
|
event.origin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTimestampMentionCase(request, event) {
|
||||||
|
try {
|
||||||
|
const response = await getTimestampMention();
|
||||||
|
|
||||||
|
event.source.postMessage(
|
||||||
|
{
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: "getTimestampMention",
|
||||||
|
payload: response,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
},
|
||||||
|
event.origin
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
event.source.postMessage(
|
||||||
|
{
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: "getTimestampMention",
|
||||||
|
error: error?.message,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
},
|
||||||
|
event.origin
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addTimestampMentionCase(request, event) {
|
||||||
|
try {
|
||||||
|
const { groupId, timestamp } = request.payload;
|
||||||
|
const response = await addTimestampMention({ groupId, timestamp });
|
||||||
|
|
||||||
|
event.source.postMessage(
|
||||||
|
{
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: "addTimestampMention",
|
||||||
|
payload: response,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
},
|
||||||
|
event.origin
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
event.source.postMessage(
|
||||||
|
{
|
||||||
|
requestId: request.requestId,
|
||||||
|
action: "addTimestampMention",
|
||||||
|
error: error?.message,
|
||||||
|
type: "backgroundMessageResponse",
|
||||||
|
},
|
||||||
|
event.origin
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@ -66,6 +66,9 @@ import {
|
|||||||
inviteToGroupCase,
|
inviteToGroupCase,
|
||||||
joinGroupCase,
|
joinGroupCase,
|
||||||
kickFromGroupCase,
|
kickFromGroupCase,
|
||||||
|
addTimestampMentionCase,
|
||||||
|
getTimestampMentionCase,
|
||||||
|
|
||||||
leaveGroupCase,
|
leaveGroupCase,
|
||||||
ltcBalanceCase,
|
ltcBalanceCase,
|
||||||
makeAdminCase,
|
makeAdminCase,
|
||||||
@ -95,6 +98,8 @@ import {
|
|||||||
import { getData, removeKeysAndLogout, storeData } from "./utils/chromeStorage";
|
import { getData, removeKeysAndLogout, storeData } from "./utils/chromeStorage";
|
||||||
import {BackgroundFetch} from '@transistorsoft/capacitor-background-fetch';
|
import {BackgroundFetch} from '@transistorsoft/capacitor-background-fetch';
|
||||||
import { LocalNotifications } from '@capacitor/local-notifications';
|
import { LocalNotifications } from '@capacitor/local-notifications';
|
||||||
|
import ChatComputePowWorker from './chatComputePow.worker.js?worker';
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 9, dictionary: 'number' });
|
const uid = new ShortUniqueId({ length: 9, dictionary: 'number' });
|
||||||
|
|
||||||
const generateId = ()=> {
|
const generateId = ()=> {
|
||||||
@ -378,6 +383,31 @@ function playNotificationSound() {
|
|||||||
// chrome.runtime.sendMessage({ action: "PLAY_NOTIFICATION_SOUND" });
|
// chrome.runtime.sendMessage({ action: "PLAY_NOTIFICATION_SOUND" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const worker = new ChatComputePowWorker()
|
||||||
|
|
||||||
|
export async function performPowTask(chatBytes, difficulty) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
worker.onmessage = (e) => {
|
||||||
|
if (e.data.error) {
|
||||||
|
reject(new Error(e.data.error));
|
||||||
|
} else {
|
||||||
|
resolve(e.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
worker.onerror = (err) => {
|
||||||
|
reject(err);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the task to the worker
|
||||||
|
worker.postMessage({
|
||||||
|
chatBytes,
|
||||||
|
path: `${import.meta.env.BASE_URL}memory-pow.wasm.full`,
|
||||||
|
difficulty,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const handleNotificationDirect = async (directs) => {
|
const handleNotificationDirect = async (directs) => {
|
||||||
let isFocused;
|
let isFocused;
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
@ -1352,7 +1382,6 @@ async function sendChatForBuyOrder({ qortAddress, recipientPublicKey, message })
|
|||||||
};
|
};
|
||||||
const balance = await getBalanceInfo();
|
const balance = await getBalanceInfo();
|
||||||
const hasEnoughBalance = +balance < 4 ? false : true;
|
const hasEnoughBalance = +balance < 4 ? false : true;
|
||||||
const difficulty = 8;
|
|
||||||
const jsonData = {
|
const jsonData = {
|
||||||
addresses: message.addresses,
|
addresses: message.addresses,
|
||||||
foreignKey: message.foreignKey,
|
foreignKey: message.foreignKey,
|
||||||
@ -1378,13 +1407,9 @@ async function sendChatForBuyOrder({ qortAddress, recipientPublicKey, message })
|
|||||||
if (!hasEnoughBalance) {
|
if (!hasEnoughBalance) {
|
||||||
throw new Error('You must have at least 4 QORT to trade using the gateway.')
|
throw new Error('You must have at least 4 QORT to trade using the gateway.')
|
||||||
}
|
}
|
||||||
const path = `${import.meta.env.BASE_URL}memory-pow.wasm.full`;
|
const chatBytes = tx.chatBytes;
|
||||||
|
const difficulty = 8;
|
||||||
const { nonce, chatBytesArray } = await computePow({
|
const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty);
|
||||||
chatBytes: tx.chatBytes,
|
|
||||||
path,
|
|
||||||
difficulty,
|
|
||||||
});
|
|
||||||
let _response = await signChatFunc(
|
let _response = await signChatFunc(
|
||||||
chatBytesArray,
|
chatBytesArray,
|
||||||
nonce,
|
nonce,
|
||||||
@ -1417,7 +1442,6 @@ export async function sendChatGroup({
|
|||||||
};
|
};
|
||||||
// const balance = await getBalanceInfo();
|
// const balance = await getBalanceInfo();
|
||||||
// const hasEnoughBalance = +balance < 4 ? false : true;
|
// const hasEnoughBalance = +balance < 4 ? false : true;
|
||||||
const difficulty = 8;
|
|
||||||
|
|
||||||
const txBody = {
|
const txBody = {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
@ -1440,13 +1464,9 @@ export async function sendChatGroup({
|
|||||||
// if (!hasEnoughBalance) {
|
// if (!hasEnoughBalance) {
|
||||||
// throw new Error("Must have at least 4 QORT to send a chat message");
|
// throw new Error("Must have at least 4 QORT to send a chat message");
|
||||||
// }
|
// }
|
||||||
const path = `${import.meta.env.BASE_URL}memory-pow.wasm.full`;
|
const chatBytes = tx.chatBytes;
|
||||||
|
const difficulty = 8;
|
||||||
const { nonce, chatBytesArray } = await computePow({
|
const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty);
|
||||||
chatBytes: tx.chatBytes,
|
|
||||||
path,
|
|
||||||
difficulty,
|
|
||||||
});
|
|
||||||
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
||||||
if (_response?.error) {
|
if (_response?.error) {
|
||||||
throw new Error(_response?.message);
|
throw new Error(_response?.message);
|
||||||
@ -1492,7 +1512,6 @@ export async function sendChatDirect({
|
|||||||
// const balance = await getBalanceInfo();
|
// const balance = await getBalanceInfo();
|
||||||
// const hasEnoughBalance = +balance < 4 ? false : true;
|
// const hasEnoughBalance = +balance < 4 ? false : true;
|
||||||
|
|
||||||
const difficulty = 8;
|
|
||||||
|
|
||||||
const finalJson = {
|
const finalJson = {
|
||||||
message: messageText,
|
message: messageText,
|
||||||
@ -1520,13 +1539,9 @@ export async function sendChatDirect({
|
|||||||
// if (!hasEnoughBalance) {
|
// if (!hasEnoughBalance) {
|
||||||
// throw new Error("Must have at least 4 QORT to send a chat message");
|
// throw new Error("Must have at least 4 QORT to send a chat message");
|
||||||
// }
|
// }
|
||||||
const path = `${import.meta.env.BASE_URL}memory-pow.wasm.full`;
|
const chatBytes = tx.chatBytes;
|
||||||
|
const difficulty = 8;
|
||||||
const { nonce, chatBytesArray } = await computePow({
|
const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty);
|
||||||
chatBytes: tx.chatBytes,
|
|
||||||
path,
|
|
||||||
difficulty,
|
|
||||||
});
|
|
||||||
|
|
||||||
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
||||||
if (_response?.error) {
|
if (_response?.error) {
|
||||||
@ -2448,6 +2463,31 @@ async function setChatHeadsDirect(data) {
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
export async function getTimestampMention() {
|
||||||
|
const wallet = await getSaveWallet();
|
||||||
|
const address = wallet.address0;
|
||||||
|
const key = `enter-mention-timestamp-${address}`;
|
||||||
|
const res = await getData<any>(key).catch(() => null);
|
||||||
|
if (res) {
|
||||||
|
const parsedData = res;
|
||||||
|
return parsedData;
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function addTimestampMention({ groupId, timestamp }) {
|
||||||
|
const wallet = await getSaveWallet();
|
||||||
|
const address = wallet.address0;
|
||||||
|
const data = await getTimestampMention();
|
||||||
|
data[groupId] = timestamp;
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
storeData(`enter-mention-timestamp-${address}`, data)
|
||||||
|
.then(() => resolve(true))
|
||||||
|
.catch((error) => {
|
||||||
|
reject(new Error(error.message || "Error saving data"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function getTimestampEnterChat() {
|
export async function getTimestampEnterChat() {
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
@ -2720,7 +2760,12 @@ function setupMessageListener() {
|
|||||||
case "registerName":
|
case "registerName":
|
||||||
registerNameCase(request, event);
|
registerNameCase(request, event);
|
||||||
break;
|
break;
|
||||||
|
case "addTimestampMention":
|
||||||
|
addTimestampMentionCase(request, event);
|
||||||
|
break;
|
||||||
|
case "getTimestampMention":
|
||||||
|
getTimestampMentionCase(request, event);
|
||||||
|
break;
|
||||||
case "makeAdmin":
|
case "makeAdmin":
|
||||||
makeAdminCase(request, event);
|
makeAdminCase(request, event);
|
||||||
break;
|
break;
|
||||||
|
107
src/chatComputePow.worker.js
Normal file
107
src/chatComputePow.worker.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { Sha256 } from 'asmcrypto.js';
|
||||||
|
import wasmInit from './memory-pow.wasm?init';
|
||||||
|
|
||||||
|
let compute; // Exported compute function from Wasm
|
||||||
|
let memory; // WebAssembly.Memory instance
|
||||||
|
let heap; // Uint8Array view of the memory buffer
|
||||||
|
let brk = 512 * 1024; // Initial brk set to 512 KiB
|
||||||
|
const allocations = new Map(); // Track allocations by pointer
|
||||||
|
let workBufferPtr = null; // Reuse work buffer
|
||||||
|
const workBufferLength = 8 * 1024 * 1024; // 8 MiB
|
||||||
|
|
||||||
|
// Load the WebAssembly module
|
||||||
|
async function loadWasm() {
|
||||||
|
try {
|
||||||
|
memory = new WebAssembly.Memory({ initial: 256, maximum: 256 }); // 16 MiB
|
||||||
|
heap = new Uint8Array(memory.buffer);
|
||||||
|
|
||||||
|
const importObject = {
|
||||||
|
env: {
|
||||||
|
memory, // Pass memory to Wasm
|
||||||
|
abort: () => { throw new Error('Wasm abort called'); }, // Handle abort calls from Wasm
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wasmModule = await wasmInit(importObject);
|
||||||
|
compute = wasmModule.exports.compute2;
|
||||||
|
console.log('Wasm loaded successfully:', compute);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading Wasm:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory allocation function
|
||||||
|
function sbrk(size) {
|
||||||
|
const old = brk;
|
||||||
|
|
||||||
|
// If a previous allocation exists for this size, reuse it
|
||||||
|
if (allocations.has(size)) {
|
||||||
|
return allocations.get(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
brk += size;
|
||||||
|
|
||||||
|
// Grow memory if needed
|
||||||
|
if (brk > memory.buffer.byteLength) {
|
||||||
|
const pagesNeeded = Math.ceil((brk - memory.buffer.byteLength) / (64 * 1024)); // 64 KiB per page
|
||||||
|
console.log(`Growing memory by ${pagesNeeded} pages`);
|
||||||
|
try {
|
||||||
|
memory.grow(pagesNeeded);
|
||||||
|
heap = new Uint8Array(memory.buffer); // Update heap view
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to grow memory:', e);
|
||||||
|
throw new RangeError('WebAssembly.Memory.grow(): Maximum memory size exceeded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allocations.set(size, old); // Track the allocation
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proof-of-Work computation function
|
||||||
|
async function computePow(chatBytes, difficulty) {
|
||||||
|
if (!compute) {
|
||||||
|
throw new Error('WebAssembly module not initialized. Call loadWasm first.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatBytesArray = Uint8Array.from(Object.values(chatBytes));
|
||||||
|
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result;
|
||||||
|
|
||||||
|
// Allocate memory for the hash
|
||||||
|
const hashPtr = sbrk(32);
|
||||||
|
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32);
|
||||||
|
hashAry.set(chatBytesHash);
|
||||||
|
|
||||||
|
// Reuse the work buffer if already allocated
|
||||||
|
if (!workBufferPtr) {
|
||||||
|
workBufferPtr = sbrk(workBufferLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Starting POW computation...');
|
||||||
|
const nonce = compute(hashPtr, workBufferPtr, workBufferLength, difficulty);
|
||||||
|
console.log('POW computation finished.');
|
||||||
|
|
||||||
|
return { nonce, chatBytesArray };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Worker event listener
|
||||||
|
self.addEventListener('message', async (e) => {
|
||||||
|
const { chatBytes, difficulty } = e.data;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Initialize Wasm if not already done
|
||||||
|
if (!compute) {
|
||||||
|
await loadWasm();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the POW computation
|
||||||
|
const result = await computePow(chatBytes, difficulty);
|
||||||
|
|
||||||
|
// Send the result back to the main thread
|
||||||
|
self.postMessage(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in worker:', error);
|
||||||
|
self.postMessage({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
@ -21,10 +21,12 @@ import { ReplyPreview } from './MessageItem'
|
|||||||
import { ExitIcon } from '../../assets/Icons/ExitIcon'
|
import { ExitIcon } from '../../assets/Icons/ExitIcon'
|
||||||
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from '../../constants/resourceTypes'
|
import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from '../../constants/resourceTypes'
|
||||||
import { isExtMsg } from '../../background'
|
import { isExtMsg } from '../../background'
|
||||||
|
import MentionList from './MentionList'
|
||||||
|
import { ChatOptions } from './ChatOptions'
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
|
||||||
export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey, myAddress, handleNewEncryptionNotification, hide, handleSecretKeyCreationInProgress, triedToFetchSecretKey, myName, balance}) => {
|
export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey, myAddress, handleNewEncryptionNotification, hide, handleSecretKeyCreationInProgress, triedToFetchSecretKey, myName, balance, getTimestampEnterChatParent}) => {
|
||||||
const [messages, setMessages] = useState([])
|
const [messages, setMessages] = useState([])
|
||||||
const [chatReferences, setChatReferences] = useState({})
|
const [chatReferences, setChatReferences] = useState({})
|
||||||
const [isSending, setIsSending] = useState(false)
|
const [isSending, setIsSending] = useState(false)
|
||||||
@ -44,6 +46,63 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
|
|||||||
const { queueChats, addToQueue, processWithNewMessages } = useMessageQueue();
|
const { queueChats, addToQueue, processWithNewMessages } = useMessageQueue();
|
||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
|
|
||||||
|
const lastReadTimestamp = useRef(null)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const getTimestampEnterChat = async () => {
|
||||||
|
try {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
window.sendMessage("getTimestampEnterChat")
|
||||||
|
.then((response) => {
|
||||||
|
if (!response?.error) {
|
||||||
|
if(response && selectedGroup && response[selectedGroup]){
|
||||||
|
lastReadTimestamp.current = response[selectedGroup]
|
||||||
|
window.sendMessage("addTimestampEnterChat", {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
groupId: selectedGroup
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to add timestamp:", error.message || "An error occurred");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
getTimestampEnterChatParent();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
res(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rej(response.error);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
rej(error.message || "An error occurred");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
getTimestampEnterChat()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const members = useMemo(() => {
|
||||||
|
const uniqueMembers = new Set();
|
||||||
|
|
||||||
|
messages.forEach((message) => {
|
||||||
|
if (message?.senderName) {
|
||||||
|
uniqueMembers.add(message?.senderName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(uniqueMembers);
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
const triggerRerender = () => {
|
const triggerRerender = () => {
|
||||||
forceUpdate(); // Trigger re-render by updating the state
|
forceUpdate(); // Trigger re-render by updating the state
|
||||||
};
|
};
|
||||||
@ -211,16 +270,25 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
|
|||||||
return organizedChatReferences;
|
return organizedChatReferences;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let firstUnreadFound = false;
|
||||||
const formatted = combineUIAndExtensionMsgs
|
const formatted = combineUIAndExtensionMsgs
|
||||||
.filter((rawItem) => !rawItem?.chatReference)
|
.filter((rawItem) => !rawItem?.chatReference)
|
||||||
.map((item) => ({
|
.map((item) => {
|
||||||
...item,
|
const divide = lastReadTimestamp.current && !firstUnreadFound && item.timestamp > lastReadTimestamp.current && myAddress !== item?.sender;
|
||||||
id: item.signature,
|
|
||||||
text: item?.decryptedData?.message || "",
|
if(divide){
|
||||||
repliedTo: item?.repliedTo || item?.decryptedData?.repliedTo,
|
firstUnreadFound = true
|
||||||
isNotEncrypted: !!item?.messageText,
|
}
|
||||||
unread: false,
|
return {
|
||||||
}));
|
...item,
|
||||||
|
id: item.signature,
|
||||||
|
text: item?.decryptedData?.message || "",
|
||||||
|
repliedTo: item?.repliedTo || item?.decryptedData?.repliedTo,
|
||||||
|
isNotEncrypted: !!item?.messageText,
|
||||||
|
unread: false,
|
||||||
|
divide
|
||||||
|
}
|
||||||
|
});
|
||||||
setMessages(formatted);
|
setMessages(formatted);
|
||||||
|
|
||||||
setChatReferences((prev) => {
|
setChatReferences((prev) => {
|
||||||
@ -621,7 +689,7 @@ const clearEditorContent = () => {
|
|||||||
left: hide && '-100000px',
|
left: hide && '-100000px',
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
<ChatList onReply={onReply} chatId={selectedGroup} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages} handleReaction={handleReaction} chatReferences={chatReferences} tempChatReferences={tempChatReferences}/>
|
<ChatList enableMentions onReply={onReply} chatId={selectedGroup} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages} handleReaction={handleReaction} chatReferences={chatReferences} tempChatReferences={tempChatReferences} members={members} myName={myName} selectedGroup={selectedGroup}/>
|
||||||
|
|
||||||
|
|
||||||
<div style={{
|
<div style={{
|
||||||
@ -668,8 +736,19 @@ const clearEditorContent = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent} />
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
width: '100%'
|
||||||
|
}}>
|
||||||
|
|
||||||
|
|
||||||
|
<Tiptap enableMentions setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent} membersWithNames={members} />
|
||||||
|
{!isFocusedParent && (
|
||||||
|
<ChatOptions messages={messages} goToMessage={()=> {}} members={members} myName={myName} selectedGroup={selectedGroup}/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -701,36 +780,39 @@ const clearEditorContent = () => {
|
|||||||
</CustomButton>
|
</CustomButton>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
<CustomButton
|
{!isMobile && !isFocusedParent && (
|
||||||
onClick={()=> {
|
<CustomButton
|
||||||
if(isSending) return
|
onClick={()=> {
|
||||||
sendMessage()
|
if(isSending) return
|
||||||
}}
|
sendMessage()
|
||||||
style={{
|
}}
|
||||||
marginTop: 'auto',
|
style={{
|
||||||
alignSelf: 'center',
|
marginTop: 'auto',
|
||||||
cursor: isSending ? 'default' : 'pointer',
|
alignSelf: 'center',
|
||||||
background: isSending && 'rgba(0, 0, 0, 0.8)',
|
cursor: isSending ? 'default' : 'pointer',
|
||||||
flexShrink: 0,
|
background: isSending && 'rgba(0, 0, 0, 0.8)',
|
||||||
padding: isMobile && '5px',
|
flexShrink: 0,
|
||||||
|
padding: isMobile && '5px',
|
||||||
}}
|
|
||||||
>
|
}}
|
||||||
{isSending && (
|
>
|
||||||
<CircularProgress
|
{isSending && (
|
||||||
size={18}
|
<CircularProgress
|
||||||
sx={{
|
size={18}
|
||||||
position: 'absolute',
|
sx={{
|
||||||
top: '50%',
|
position: 'absolute',
|
||||||
left: '50%',
|
top: '50%',
|
||||||
marginTop: '-12px',
|
left: '50%',
|
||||||
marginLeft: '-12px',
|
marginTop: '-12px',
|
||||||
color: 'white'
|
marginLeft: '-12px',
|
||||||
}}
|
color: 'white'
|
||||||
/>
|
}}
|
||||||
)}
|
/>
|
||||||
{` Send`}
|
)}
|
||||||
</CustomButton>
|
{` Send`}
|
||||||
|
</CustomButton>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
{/* <button onClick={sendMessage}>send</button> */}
|
{/* <button onClick={sendMessage}>send</button> */}
|
||||||
|
@ -9,7 +9,18 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId, onR
|
|||||||
const [messages, setMessages] = useState(initialMessages);
|
const [messages, setMessages] = useState(initialMessages);
|
||||||
const [showScrollButton, setShowScrollButton] = useState(false);
|
const [showScrollButton, setShowScrollButton] = useState(false);
|
||||||
const hasLoadedInitialRef = useRef(false);
|
const hasLoadedInitialRef = useRef(false);
|
||||||
const isAtBottomRef = useRef(true);
|
const [showScrollDownButton, setShowScrollDownButton] = useState(false);
|
||||||
|
|
||||||
|
const showScrollButtonRef = useRef(showScrollButton);
|
||||||
|
const isScrollingRef = useRef(false);
|
||||||
|
const scrollTimeoutRef = useRef(null);
|
||||||
|
|
||||||
|
// Update the ref whenever the state changes
|
||||||
|
useEffect(() => {
|
||||||
|
showScrollButtonRef.current = showScrollButton;
|
||||||
|
}, [showScrollButton]);
|
||||||
|
|
||||||
|
|
||||||
// const [ref, inView] = useInView({
|
// const [ref, inView] = useInView({
|
||||||
// threshold: 0.7
|
// threshold: 0.7
|
||||||
// })
|
// })
|
||||||
@ -40,27 +51,36 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId, onR
|
|||||||
setMessages(totalMessages);
|
setMessages(totalMessages);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const hasUnreadMessages = totalMessages.some((msg) => msg.unread && !msg?.chatReference);
|
const hasUnreadMessages = totalMessages.some((msg) => msg.unread && !msg?.chatReference && !msg?.isTemp);
|
||||||
if (parentRef.current) {
|
if (parentRef.current) {
|
||||||
const { scrollTop, scrollHeight, clientHeight } = parentRef.current;
|
const { scrollTop, scrollHeight, clientHeight } = parentRef.current;
|
||||||
const atBottom = scrollTop + clientHeight >= scrollHeight - 10; // Adjust threshold as needed
|
const atBottom = scrollTop + clientHeight >= scrollHeight - 10; // Adjust threshold as needed
|
||||||
if (!atBottom && hasUnreadMessages) {
|
if (!atBottom && hasUnreadMessages) {
|
||||||
setShowScrollButton(hasUnreadMessages);
|
setShowScrollButton(hasUnreadMessages);
|
||||||
|
setShowScrollDownButton(false)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
handleMessageSeen();
|
handleMessageSeen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasLoadedInitialRef.current) {
|
if (!hasLoadedInitialRef.current) {
|
||||||
scrollToBottom(totalMessages);
|
const findDivideIndex = totalMessages.findIndex((item)=> !!item?.divide)
|
||||||
|
const divideIndex = findDivideIndex !== -1 ? findDivideIndex : undefined
|
||||||
|
scrollToBottom(totalMessages, divideIndex);
|
||||||
hasLoadedInitialRef.current = true;
|
hasLoadedInitialRef.current = true;
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}, [initialMessages, tempMessages]);
|
}, [initialMessages, tempMessages]);
|
||||||
|
|
||||||
const scrollToBottom = (initialMsgs) => {
|
const scrollToBottom = (initialMsgs, divideIndex) => {
|
||||||
const index = initialMsgs ? initialMsgs.length - 1 : messages.length - 1;
|
const index = initialMsgs ? initialMsgs.length - 1 : messages.length - 1;
|
||||||
if (rowVirtualizer) {
|
if (rowVirtualizer) {
|
||||||
rowVirtualizer.scrollToIndex(index, { align: 'end' });
|
if(divideIndex){
|
||||||
|
rowVirtualizer.scrollToIndex(divideIndex, { align: 'start' })
|
||||||
|
} else {
|
||||||
|
rowVirtualizer.scrollToIndex(index, { align: 'end' })
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handleMessageSeen()
|
handleMessageSeen()
|
||||||
};
|
};
|
||||||
@ -84,9 +104,17 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId, onR
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const sentNewMessageGroupFunc = useCallback(() => {
|
const sentNewMessageGroupFunc = useCallback(() => {
|
||||||
scrollToBottom();
|
const { scrollHeight, scrollTop, clientHeight } = parentRef.current;
|
||||||
|
|
||||||
|
// Check if the user is within 200px from the bottom
|
||||||
|
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
||||||
|
if (distanceFromBottom <= 700) {
|
||||||
|
scrollToBottom();
|
||||||
|
}
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent('sent-new-message-group', sentNewMessageGroupFunc);
|
subscribeToEvent('sent-new-message-group', sentNewMessageGroupFunc);
|
||||||
@ -112,8 +140,63 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId, onR
|
|||||||
(index) => messages[index].signature,
|
(index) => messages[index].signature,
|
||||||
[messages]
|
[messages]
|
||||||
),
|
),
|
||||||
|
observeElementOffset: (instance, cb) => {
|
||||||
|
const offsetCheck = () => {
|
||||||
|
isScrollingRef.current = true;
|
||||||
|
|
||||||
|
const { scrollHeight, scrollTop, clientHeight } = instance.scrollElement;
|
||||||
|
const atBottom = scrollHeight - scrollTop - clientHeight <= 300;
|
||||||
|
if(!isScrollingRef.current){
|
||||||
|
setShowScrollDownButton(false)
|
||||||
|
} else
|
||||||
|
if(showScrollButtonRef.current){
|
||||||
|
setShowScrollDownButton(false)
|
||||||
|
} else
|
||||||
|
if(atBottom){
|
||||||
|
setShowScrollDownButton(false)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setShowScrollDownButton(true)
|
||||||
|
|
||||||
|
}
|
||||||
|
if (scrollTimeoutRef.current) {
|
||||||
|
clearTimeout(scrollTimeoutRef.current); // Clear the previous timeout
|
||||||
|
}
|
||||||
|
scrollTimeoutRef.current = setTimeout(() => {
|
||||||
|
isScrollingRef.current = false; // Mark scrolling as stopped
|
||||||
|
scrollTimeoutRef.current = null; // Clear the timeout reference
|
||||||
|
setShowScrollDownButton(false)
|
||||||
|
}, 2500);
|
||||||
|
cb(scrollTop); // Pass scroll offset to callback
|
||||||
|
// setShowScrollToBottom(!atBottom);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial check and continuous monitoring
|
||||||
|
offsetCheck();
|
||||||
|
instance.scrollElement.addEventListener('scroll', offsetCheck);
|
||||||
|
return () => instance.scrollElement.removeEventListener('scroll', offsetCheck);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const goToMessageFunc = useCallback((e)=> {
|
||||||
|
if(e.detail?.index){
|
||||||
|
rowVirtualizer.scrollToIndex(e.detail?.index)
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
subscribeToEvent('goToMessage', goToMessageFunc);
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent('goToMessage', goToMessageFunc);
|
||||||
|
};
|
||||||
|
}, [goToMessageFunc]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
height: '100%',
|
height: '100%',
|
||||||
@ -223,16 +306,39 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId, onR
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 20,
|
bottom: 20,
|
||||||
right: 20,
|
right: 20,
|
||||||
backgroundColor: '#ff5a5f',
|
backgroundColor: 'var(--unread)',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
padding: '10px 20px',
|
padding: '10px 20px',
|
||||||
borderRadius: '20px',
|
borderRadius: '20px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Scroll to Unread Messages
|
Scroll to Unread Messages
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
|
{showScrollDownButton && (
|
||||||
|
<button
|
||||||
|
onClick={() => scrollToBottom()}
|
||||||
|
style={{
|
||||||
|
bottom: 20,
|
||||||
|
position: 'absolute',
|
||||||
|
right: 20,
|
||||||
|
backgroundColor: 'var(--Mail-Background)',
|
||||||
|
color: 'white',
|
||||||
|
padding: '10px 20px',
|
||||||
|
borderRadius: '20px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
zIndex: 10,
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Scroll to bottom
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
716
src/components/Chat/ChatOptions.tsx
Normal file
716
src/components/Chat/ChatOptions.tsx
Normal file
@ -0,0 +1,716 @@
|
|||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
|
ButtonBase,
|
||||||
|
InputBase,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
|
import { Spacer } from "../../common/Spacer";
|
||||||
|
import AlternateEmailIcon from "@mui/icons-material/AlternateEmail";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import {
|
||||||
|
AppsSearchContainer,
|
||||||
|
AppsSearchLeft,
|
||||||
|
AppsSearchRight,
|
||||||
|
} from "../Apps/Apps-styles";
|
||||||
|
import IconSearch from "../../assets/svgs/Search.svg";
|
||||||
|
import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
||||||
|
import {
|
||||||
|
AutoSizer,
|
||||||
|
CellMeasurer,
|
||||||
|
CellMeasurerCache,
|
||||||
|
List,
|
||||||
|
} from "react-virtualized";
|
||||||
|
import { getBaseApiReact, isMobile } from "../../App";
|
||||||
|
import { MessageDisplay } from "./MessageDisplay";
|
||||||
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
||||||
|
import { formatTimestamp } from "../../utils/time";
|
||||||
|
import { ContextMenuMentions } from "../ContextMenuMentions";
|
||||||
|
import { convert } from 'html-to-text';
|
||||||
|
import { executeEvent } from "../../utils/events";
|
||||||
|
|
||||||
|
const extractTextFromHTML = (htmlString = '') => {
|
||||||
|
return convert(htmlString, {
|
||||||
|
wordwrap: false, // Disable word wrapping
|
||||||
|
})?.toLowerCase();
|
||||||
|
};
|
||||||
|
const cache = new CellMeasurerCache({
|
||||||
|
fixedWidth: true,
|
||||||
|
defaultHeight: 50,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ChatOptions = ({ messages, goToMessage, members, myName, selectedGroup }) => {
|
||||||
|
const [mode, setMode] = useState("default");
|
||||||
|
const [searchValue, setSearchValue] = useState("");
|
||||||
|
const [selectedMember, setSelectedMember] = useState(0);
|
||||||
|
|
||||||
|
const parentRef = useRef();
|
||||||
|
const parentRefMentions = useRef();
|
||||||
|
const [lastMentionTimestamp, setLastMentionTimestamp] = useState(null)
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value
|
||||||
|
|
||||||
|
const getTimestampMention = async () => {
|
||||||
|
try {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
window.sendMessage("getTimestampMention")
|
||||||
|
.then((response) => {
|
||||||
|
if (!response?.error) {
|
||||||
|
if(response && selectedGroup && response[selectedGroup]){
|
||||||
|
setLastMentionTimestamp(response[selectedGroup])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
res(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rej(response.error);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
rej(error.message || "An error occurred");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if(mode === 'mentions' && selectedGroup){
|
||||||
|
window.sendMessage("addTimestampMention", {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
groupId: selectedGroup
|
||||||
|
}).then((res)=> {
|
||||||
|
getTimestampMention()
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to add timestamp:", error.message || "An error occurred");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [mode, selectedGroup])
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
getTimestampMention()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Debounce logic
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setDebouncedValue(searchValue);
|
||||||
|
}, 350);
|
||||||
|
|
||||||
|
// Cleanup timeout if searchValue changes before the timeout completes
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler);
|
||||||
|
};
|
||||||
|
}, [searchValue]); // Runs effect when searchValue changes
|
||||||
|
|
||||||
|
const searchedList = useMemo(() => {
|
||||||
|
if (!debouncedValue?.trim()) {
|
||||||
|
if (selectedMember) {
|
||||||
|
return messages
|
||||||
|
.filter((message) => message?.senderName === selectedMember)
|
||||||
|
?.sort((a, b) => b?.timestamp - a?.timestamp);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (selectedMember) {
|
||||||
|
return messages
|
||||||
|
.filter(
|
||||||
|
(message) =>
|
||||||
|
message?.senderName === selectedMember &&
|
||||||
|
extractTextFromHTML(message?.decryptedData?.message)?.includes(
|
||||||
|
debouncedValue.toLowerCase()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
?.sort((a, b) => b?.timestamp - a?.timestamp);
|
||||||
|
}
|
||||||
|
return messages
|
||||||
|
.filter((message) =>
|
||||||
|
extractTextFromHTML(message?.decryptedData?.message)?.includes(debouncedValue.toLowerCase())
|
||||||
|
)
|
||||||
|
?.sort((a, b) => b?.timestamp - a?.timestamp);
|
||||||
|
}, [debouncedValue, messages, selectedMember]);
|
||||||
|
|
||||||
|
const mentionList = useMemo(() => {
|
||||||
|
if(!messages || messages.length === 0 || !myName) return []
|
||||||
|
|
||||||
|
return messages
|
||||||
|
.filter((message) =>
|
||||||
|
extractTextFromHTML(message?.decryptedData?.message)?.includes(`@${myName}`)
|
||||||
|
)
|
||||||
|
?.sort((a, b) => b?.timestamp - a?.timestamp);
|
||||||
|
}, [messages, myName]);
|
||||||
|
|
||||||
|
const rowVirtualizer = useVirtualizer({
|
||||||
|
count: searchedList.length,
|
||||||
|
getItemKey: React.useCallback(
|
||||||
|
(index) => searchedList[index].signature,
|
||||||
|
[searchedList]
|
||||||
|
),
|
||||||
|
getScrollElement: () => parentRef.current,
|
||||||
|
estimateSize: () => 80, // Provide an estimated height of items, adjust this as needed
|
||||||
|
overscan: 10, // Number of items to render outside the visible area to improve smoothness
|
||||||
|
});
|
||||||
|
|
||||||
|
const rowVirtualizerMentions = useVirtualizer({
|
||||||
|
count: mentionList.length,
|
||||||
|
getItemKey: React.useCallback(
|
||||||
|
(index) => mentionList[index].signature,
|
||||||
|
[mentionList]
|
||||||
|
),
|
||||||
|
getScrollElement: () => parentRefMentions.current,
|
||||||
|
estimateSize: () => 80, // Provide an estimated height of items, adjust this as needed
|
||||||
|
overscan: 10, // Number of items to render outside the visible area to improve smoothness
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (mode === "mentions") {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: isMobile ? '100%' : "300px",
|
||||||
|
height: isMobile ? '60svh' : "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
// alignItems: 'center',
|
||||||
|
backgroundColor: "#1F2023",
|
||||||
|
borderBottomLeftRadius: "20px",
|
||||||
|
borderTopLeftRadius: "20px",
|
||||||
|
overflow: "auto",
|
||||||
|
flexShrink: 0,
|
||||||
|
flexGrow: 0,
|
||||||
|
position: isMobile ? 'fixed' : 'unset',
|
||||||
|
left: isMobile ? 0 : 'unset',
|
||||||
|
right: isMobile ? 0 : 'unset',
|
||||||
|
bottom: isMobile ? 0 : 'unset',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
padding: "10px",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CloseIcon
|
||||||
|
onClick={() => {
|
||||||
|
setMode("default");
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{mentionList?.length === 0 && (
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: "11px",
|
||||||
|
fontWeight: 400,
|
||||||
|
color: "rgba(255, 255, 255, 0.2)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No results
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref={parentRefMentions}
|
||||||
|
className="List"
|
||||||
|
style={{
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: "auto",
|
||||||
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
height: "0px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: rowVirtualizerMentions.getTotalSize(),
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{rowVirtualizerMentions.getVirtualItems().map((virtualRow) => {
|
||||||
|
const index = virtualRow.index;
|
||||||
|
let message = mentionList[index];
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-index={virtualRow.index} //needed for dynamic row height measurement
|
||||||
|
ref={rowVirtualizerMentions.measureElement} //measure dynamic row height
|
||||||
|
key={message.signature}
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: "50%", // Move to the center horizontally
|
||||||
|
transform: `translateY(${virtualRow.start}px) translateX(-50%)`, // Adjust for centering
|
||||||
|
width: "100%", // Control width (90% of the parent)
|
||||||
|
padding: "10px 0",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
overscrollBehavior: "none",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
width: "100%",
|
||||||
|
padding: "0px 20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#27282c",
|
||||||
|
color: "white",
|
||||||
|
height: "25px",
|
||||||
|
width: "25px",
|
||||||
|
}}
|
||||||
|
alt={message?.senderName}
|
||||||
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||||
|
message?.senderName
|
||||||
|
}/qortal_avatar?async=true`}
|
||||||
|
>
|
||||||
|
{message?.senderName?.charAt(0)}
|
||||||
|
</Avatar>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontWight: 600,
|
||||||
|
fontFamily: "Inter",
|
||||||
|
color: "cadetBlue",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{message?.senderName}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Spacer height="5px" />
|
||||||
|
<Typography sx={{
|
||||||
|
fontSize: '12px'
|
||||||
|
}}>{formatTimestamp(message.timestamp)}</Typography>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
const findMsgIndex = messages.findIndex(
|
||||||
|
(item) =>
|
||||||
|
item?.signature === message?.signature
|
||||||
|
);
|
||||||
|
if (findMsgIndex !== -1) {
|
||||||
|
if(isMobile){
|
||||||
|
setMode("default");
|
||||||
|
executeEvent('goToMessage', {index: findMsgIndex})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
goToMessage(findMsgIndex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MessageDisplay
|
||||||
|
htmlContent={
|
||||||
|
message?.decryptedData?.message || "<p></p>"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === "search") {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: isMobile ? '100%' : "300px",
|
||||||
|
height: isMobile ? '60svh' : "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
// alignItems: 'center',
|
||||||
|
backgroundColor: "#1F2023",
|
||||||
|
borderBottomLeftRadius: "20px",
|
||||||
|
borderTopLeftRadius: "20px",
|
||||||
|
overflow: "auto",
|
||||||
|
flexShrink: 0,
|
||||||
|
flexGrow: 0,
|
||||||
|
position: isMobile ? 'fixed' : 'unset',
|
||||||
|
left: isMobile ? 0 : 'unset',
|
||||||
|
right: isMobile ? 0 : 'unset',
|
||||||
|
bottom: isMobile ? 0 : 'unset',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
padding: "10px",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CloseIcon
|
||||||
|
onClick={() => {
|
||||||
|
setMode("default");
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AppsSearchContainer>
|
||||||
|
<AppsSearchLeft>
|
||||||
|
<img src={IconSearch} />
|
||||||
|
<InputBase
|
||||||
|
value={searchValue}
|
||||||
|
onChange={(e) => setSearchValue(e.target.value)}
|
||||||
|
sx={{ ml: 1, flex: 1 }}
|
||||||
|
placeholder="Search chat text"
|
||||||
|
inputProps={{
|
||||||
|
"aria-label": "Search for apps",
|
||||||
|
fontSize: "16px",
|
||||||
|
fontWeight: 400,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AppsSearchLeft>
|
||||||
|
<AppsSearchRight>
|
||||||
|
{searchValue && (
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
setSearchValue("");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img src={IconClearInput} />
|
||||||
|
</ButtonBase>
|
||||||
|
)}
|
||||||
|
</AppsSearchRight>
|
||||||
|
</AppsSearchContainer>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
padding: "10px",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
size="small"
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={selectedMember}
|
||||||
|
label="By member"
|
||||||
|
onChange={(e) => setSelectedMember(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>
|
||||||
|
<em>By member</em>
|
||||||
|
</MenuItem>
|
||||||
|
{members?.map((member) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={member} value={member}>
|
||||||
|
{member}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
{!!selectedMember && (
|
||||||
|
<CloseIcon
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedMember(0);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{debouncedValue && searchedList?.length === 0 && (
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: "11px",
|
||||||
|
fontWeight: 400,
|
||||||
|
color: "rgba(255, 255, 255, 0.2)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No results
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref={parentRef}
|
||||||
|
className="List"
|
||||||
|
style={{
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: "auto",
|
||||||
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
height: "0px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: rowVirtualizer.getTotalSize(),
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
||||||
|
const index = virtualRow.index;
|
||||||
|
let message = searchedList[index];
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-index={virtualRow.index} //needed for dynamic row height measurement
|
||||||
|
ref={rowVirtualizer.measureElement} //measure dynamic row height
|
||||||
|
key={message.signature}
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: "50%", // Move to the center horizontally
|
||||||
|
transform: `translateY(${virtualRow.start}px) translateX(-50%)`, // Adjust for centering
|
||||||
|
width: "100%", // Control width (90% of the parent)
|
||||||
|
padding: "10px 0",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
overscrollBehavior: "none",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
width: "100%",
|
||||||
|
padding: "0px 20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#27282c",
|
||||||
|
color: "white",
|
||||||
|
height: "25px",
|
||||||
|
width: "25px",
|
||||||
|
}}
|
||||||
|
alt={message?.senderName}
|
||||||
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||||
|
message?.senderName
|
||||||
|
}/qortal_avatar?async=true`}
|
||||||
|
>
|
||||||
|
{message?.senderName?.charAt(0)}
|
||||||
|
</Avatar>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontWight: 600,
|
||||||
|
fontFamily: "Inter",
|
||||||
|
color: "cadetBlue",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{message?.senderName}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Spacer height="5px" />
|
||||||
|
<Typography sx={{
|
||||||
|
fontSize: '12px'
|
||||||
|
}}>{formatTimestamp(message.timestamp)}</Typography>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
const findMsgIndex = messages.findIndex(
|
||||||
|
(item) =>
|
||||||
|
item?.signature === message?.signature
|
||||||
|
);
|
||||||
|
if (findMsgIndex !== -1) {
|
||||||
|
if(isMobile){
|
||||||
|
setMode("default");
|
||||||
|
executeEvent('goToMessage', {index: findMsgIndex})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
goToMessage(findMsgIndex);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MessageDisplay
|
||||||
|
htmlContent={
|
||||||
|
message?.decryptedData?.message || "<p></p>"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: isMobile ? 'auto' : "50px",
|
||||||
|
height: "100%",
|
||||||
|
gap: "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
padding: "10px",
|
||||||
|
gap: "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: isMobile ? 'row' : "column",
|
||||||
|
alignItems: "center",
|
||||||
|
backgroundColor: isMobile ? 'transparent' :"#1F2023",
|
||||||
|
borderBottomLeftRadius: "20px",
|
||||||
|
borderTopLeftRadius: "20px",
|
||||||
|
minHeight: isMobile ? 'auto' : "200px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ButtonBase onClick={() => {
|
||||||
|
setMode("search")
|
||||||
|
}}>
|
||||||
|
<SearchIcon />
|
||||||
|
</ButtonBase>
|
||||||
|
<ContextMenuMentions getTimestampMention={getTimestampMention} groupId={selectedGroup}>
|
||||||
|
<ButtonBase onClick={() => {
|
||||||
|
setMode("mentions")
|
||||||
|
setSearchValue('')
|
||||||
|
setSelectedMember(0)
|
||||||
|
}}>
|
||||||
|
<AlternateEmailIcon sx={{
|
||||||
|
color: mentionList?.length > 0 && (!lastMentionTimestamp || lastMentionTimestamp < mentionList[0]?.timestamp) ? 'var(--unread)' : 'white'
|
||||||
|
}} />
|
||||||
|
</ButtonBase>
|
||||||
|
</ContextMenuMentions>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
69
src/components/Chat/MentionList.tsx
Normal file
69
src/components/Chat/MentionList.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import React, {
|
||||||
|
forwardRef, useEffect, useImperativeHandle,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
|
|
||||||
|
export default forwardRef((props, ref) => {
|
||||||
|
const [selectedIndex, setSelectedIndex] = useState(0)
|
||||||
|
|
||||||
|
const selectItem = index => {
|
||||||
|
const item = props.items[index]
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
props.command(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const upHandler = () => {
|
||||||
|
setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
const downHandler = () => {
|
||||||
|
setSelectedIndex((selectedIndex + 1) % props.items.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
const enterHandler = () => {
|
||||||
|
selectItem(selectedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => setSelectedIndex(0), [props.items])
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
onKeyDown: ({ event }) => {
|
||||||
|
if (event.key === 'ArrowUp') {
|
||||||
|
upHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'ArrowDown') {
|
||||||
|
downHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
enterHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dropdown-menu">
|
||||||
|
{props.items.length
|
||||||
|
? props.items.map((item, index) => (
|
||||||
|
<button
|
||||||
|
className={index === selectedIndex ? 'is-selected' : ''}
|
||||||
|
key={item.id || index}
|
||||||
|
onClick={() => selectItem(index)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
: <div className="item">No result</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
@ -45,6 +45,12 @@ export const MessageItem = ({
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{message?.divide && (
|
||||||
|
<div className="unread-divider" id="unread-divider-id">
|
||||||
|
Unread messages below
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
ref={lastSignature === message?.signature ? ref : null}
|
ref={lastSignature === message?.signature ? ref : null}
|
||||||
style={{
|
style={{
|
||||||
@ -305,6 +311,7 @@ export const MessageItem = ({
|
|||||||
></Message> */}
|
></Message> */}
|
||||||
{/* {!message.unread && <span style={{ color: 'green' }}> Seen</span>} */}
|
{/* {!message.unread && <span style={{ color: 'green' }}> Seen</span>} */}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { EditorProvider, useCurrentEditor } from "@tiptap/react";
|
import { EditorProvider, useCurrentEditor, useEditor } from "@tiptap/react";
|
||||||
import StarterKit from "@tiptap/starter-kit";
|
import StarterKit from "@tiptap/starter-kit";
|
||||||
import { Color } from "@tiptap/extension-color";
|
import { Color } from "@tiptap/extension-color";
|
||||||
import ListItem from "@tiptap/extension-list-item";
|
import ListItem from "@tiptap/extension-list-item";
|
||||||
@ -22,10 +22,28 @@ import RedoIcon from "@mui/icons-material/Redo";
|
|||||||
import FormatHeadingIcon from "@mui/icons-material/FormatSize";
|
import FormatHeadingIcon from "@mui/icons-material/FormatSize";
|
||||||
import DeveloperModeIcon from "@mui/icons-material/DeveloperMode";
|
import DeveloperModeIcon from "@mui/icons-material/DeveloperMode";
|
||||||
import Compressor from "compressorjs";
|
import Compressor from "compressorjs";
|
||||||
|
import Mention from '@tiptap/extension-mention';
|
||||||
import ImageResize from "tiptap-extension-resize-image"; // Import the ResizeImage extension
|
import ImageResize from "tiptap-extension-resize-image"; // Import the ResizeImage extension
|
||||||
import { isMobile } from "../../App";
|
import { isMobile } from "../../App";
|
||||||
|
import tippy from "tippy.js";
|
||||||
|
import "tippy.js/dist/tippy.css";
|
||||||
|
import Popover from '@mui/material/Popover';
|
||||||
|
import List from '@mui/material/List';
|
||||||
|
import ListItemMui from '@mui/material/ListItem';
|
||||||
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
|
import { ReactRenderer } from '@tiptap/react'
|
||||||
|
import MentionList from './MentionList.jsx'
|
||||||
|
|
||||||
|
function textMatcher(doc, from) {
|
||||||
|
const textBeforeCursor = doc.textBetween(0, from, ' ', ' ');
|
||||||
|
const match = textBeforeCursor.match(/@[\w]*$/); // Match '@' followed by valid characters
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
const start = from - match[0].length;
|
||||||
|
const query = match[0];
|
||||||
|
return { start, query };
|
||||||
|
}
|
||||||
const MenuBar = ({ setEditorRef, isChat }) => {
|
const MenuBar = ({ setEditorRef, isChat }) => {
|
||||||
const { editor } = useCurrentEditor();
|
const { editor } = useCurrentEditor();
|
||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
@ -279,8 +297,10 @@ export default ({
|
|||||||
isFocusedParent,
|
isFocusedParent,
|
||||||
overrideMobile,
|
overrideMobile,
|
||||||
customEditorHeight,
|
customEditorHeight,
|
||||||
|
membersWithNames,
|
||||||
|
enableMentions
|
||||||
}) => {
|
}) => {
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
|
||||||
const extensionsFiltered = isChat
|
const extensionsFiltered = isChat
|
||||||
? extensions.filter((item) => item?.name !== "image")
|
? extensions.filter((item) => item?.name !== "image")
|
||||||
: extensions;
|
: extensions;
|
||||||
@ -290,6 +310,32 @@ export default ({
|
|||||||
setEditorRef(editorInstance);
|
setEditorRef(editorInstance);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// const users = [
|
||||||
|
// { id: 1, label: 'Alice' },
|
||||||
|
// { id: 2, label: 'Bob' },
|
||||||
|
// { id: 3, label: 'Charlie' },
|
||||||
|
// ];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const users = useMemo(()=> {
|
||||||
|
return (membersWithNames || [])?.map((item)=> {
|
||||||
|
return {
|
||||||
|
id: item,
|
||||||
|
label: item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [membersWithNames])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const usersRef = useRef([]);
|
||||||
|
useEffect(() => {
|
||||||
|
usersRef.current = users; // Keep users up-to-date
|
||||||
|
}, [users]);
|
||||||
|
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
if (!isMobile) return;
|
if (!isMobile) return;
|
||||||
setIsFocusedParent(true);
|
setIsFocusedParent(true);
|
||||||
@ -302,14 +348,91 @@ export default ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const additionalExtensions = useMemo(()=> {
|
||||||
|
if(!enableMentions) return []
|
||||||
|
return [
|
||||||
|
Mention.configure({
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: 'mention',
|
||||||
|
},
|
||||||
|
suggestion: {
|
||||||
|
items: ({ query }) => {
|
||||||
|
if (!query) return usersRef?.current;
|
||||||
|
return usersRef?.current?.filter((user) =>
|
||||||
|
user.label.toLowerCase().includes(query.toLowerCase())
|
||||||
|
);
|
||||||
|
},
|
||||||
|
render: () => {
|
||||||
|
let popup; // Reference to the Tippy.js instance
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
onStart: props => {
|
||||||
|
component = new ReactRenderer(MentionList, {
|
||||||
|
props,
|
||||||
|
editor: props.editor,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!props.clientRect) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
popup = tippy('body', {
|
||||||
|
getReferenceClientRect: props.clientRect,
|
||||||
|
appendTo: () => document.body,
|
||||||
|
content: component.element,
|
||||||
|
showOnCreate: true,
|
||||||
|
interactive: true,
|
||||||
|
trigger: 'manual',
|
||||||
|
placement: 'bottom-start',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onUpdate(props) {
|
||||||
|
component.updateProps(props)
|
||||||
|
|
||||||
|
if (!props.clientRect) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
popup[0].setProps({
|
||||||
|
getReferenceClientRect: props.clientRect,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onKeyDown(props) {
|
||||||
|
if (props.event.key === 'Escape') {
|
||||||
|
popup[0].hide()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return component.ref?.onKeyDown(props)
|
||||||
|
},
|
||||||
|
|
||||||
|
onExit() {
|
||||||
|
popup[0].destroy()
|
||||||
|
component.destroy()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}, [enableMentions])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div style={{
|
||||||
|
flexGrow: 1
|
||||||
|
}}>
|
||||||
<EditorProvider
|
<EditorProvider
|
||||||
slotBefore={
|
slotBefore={
|
||||||
(isFocusedParent || !isMobile || overrideMobile) && (
|
(isFocusedParent || !isMobile || overrideMobile) && (
|
||||||
<MenuBar setEditorRef={setEditorRefFunc} isChat={isChat} />
|
<MenuBar setEditorRef={setEditorRefFunc} isChat={isChat} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
extensions={extensionsFiltered}
|
extensions={[...extensionsFiltered, ...additionalExtensions
|
||||||
|
]}
|
||||||
content={content}
|
content={content}
|
||||||
onCreate={({ editor }) => {
|
onCreate={({ editor }) => {
|
||||||
editor.on("focus", handleFocus); // Listen for focus event
|
editor.on("focus", handleFocus); // Listen for focus event
|
||||||
@ -323,10 +446,10 @@ export default ({
|
|||||||
attributes: {
|
attributes: {
|
||||||
class: "tiptap-prosemirror",
|
class: "tiptap-prosemirror",
|
||||||
style:
|
style:
|
||||||
isMobile &&
|
isMobile ?
|
||||||
`overflow: auto; min-height: ${
|
`overflow: auto; min-height: ${
|
||||||
customEditorHeight ? "200px" : "0px"
|
customEditorHeight ? "200px" : "0px"
|
||||||
}; max-height:calc(100svh - ${customEditorHeight || "140px"})`,
|
}; max-height:calc(100svh - ${customEditorHeight || "140px"})`: `overflow: auto; max-height: 250px`,
|
||||||
},
|
},
|
||||||
handleKeyDown(view, event) {
|
handleKeyDown(view, event) {
|
||||||
if (!disableEnter && event.key === "Enter") {
|
if (!disableEnter && event.key === "Enter") {
|
||||||
@ -348,5 +471,7 @@ export default ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
margin: 1.5rem 0;
|
margin: 1.5rem 0;
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
text-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tiptap pre code {
|
.tiptap pre code {
|
||||||
@ -123,3 +124,51 @@
|
|||||||
.isReply p {
|
.isReply p {
|
||||||
font-size: 12px !important;
|
font-size: 12px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tiptap .mention {
|
||||||
|
box-decoration-break: clone;
|
||||||
|
color: lightblue;
|
||||||
|
padding: 0.1rem 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.unread-divider {
|
||||||
|
width: 90%;
|
||||||
|
color: white;
|
||||||
|
border-bottom: 1px solid white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mention-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.1rem;
|
||||||
|
padding: 0.4rem;
|
||||||
|
position: relative;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
button {
|
||||||
|
align-items: center;
|
||||||
|
background-color: transparent;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover,
|
||||||
|
&:hover.is-selected {
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
src/components/ContextMenuMentions.tsx
Normal file
130
src/components/ContextMenuMentions.tsx
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import React, { useState, useRef, useMemo, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
ListItemIcon,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
Typography,
|
||||||
|
styled,
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
|
import { executeEvent } from "../utils/events";
|
||||||
|
|
||||||
|
const CustomStyledMenu = styled(Menu)(({ theme }) => ({
|
||||||
|
"& .MuiPaper-root": {
|
||||||
|
backgroundColor: "#f9f9f9",
|
||||||
|
borderRadius: "12px",
|
||||||
|
padding: theme.spacing(1),
|
||||||
|
boxShadow: "0 5px 15px rgba(0, 0, 0, 0.2)",
|
||||||
|
},
|
||||||
|
"& .MuiMenuItem-root": {
|
||||||
|
fontSize: "14px", // Smaller font size for the menu item text
|
||||||
|
color: "#444",
|
||||||
|
transition: "0.3s background-color",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#f0f0f0", // Explicit hover state
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const ContextMenuMentions = ({
|
||||||
|
children,
|
||||||
|
groupId,
|
||||||
|
getTimestampMention
|
||||||
|
}) => {
|
||||||
|
const [menuPosition, setMenuPosition] = useState(null);
|
||||||
|
const longPressTimeout = useRef(null);
|
||||||
|
const preventClick = useRef(false); // Flag to prevent click after long-press or right-click
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Handle right-click (context menu) for desktop
|
||||||
|
const handleContextMenu = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation(); // Prevent parent click
|
||||||
|
|
||||||
|
// Set flag to prevent any click event after right-click
|
||||||
|
preventClick.current = true;
|
||||||
|
|
||||||
|
setMenuPosition({
|
||||||
|
mouseX: event.clientX,
|
||||||
|
mouseY: event.clientY,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle long-press for mobile
|
||||||
|
const handleTouchStart = (event) => {
|
||||||
|
longPressTimeout.current = setTimeout(() => {
|
||||||
|
preventClick.current = true; // Prevent the next click after long-press
|
||||||
|
event.stopPropagation(); // Prevent parent click
|
||||||
|
setMenuPosition({
|
||||||
|
mouseX: event.touches[0].clientX,
|
||||||
|
mouseY: event.touches[0].clientY,
|
||||||
|
});
|
||||||
|
}, 500); // Long press duration
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTouchEnd = (event) => {
|
||||||
|
clearTimeout(longPressTimeout.current);
|
||||||
|
|
||||||
|
if (preventClick.current) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation(); // Prevent synthetic click after long-press
|
||||||
|
preventClick.current = false; // Reset the flag
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleClose = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setMenuPosition(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTimestamp = ()=> {
|
||||||
|
window.sendMessage("addTimestampMention", {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
groupId
|
||||||
|
}).then((res)=> {
|
||||||
|
getTimestampMention()
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to add timestamp:", error.message || "An error occurred");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onContextMenu={handleContextMenu} // For desktop right-click
|
||||||
|
onTouchStart={handleTouchStart} // For mobile long-press start
|
||||||
|
onTouchEnd={handleTouchEnd} // For mobile long-press end
|
||||||
|
style={{ width: "100%", height: "100%" }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
|
||||||
|
<CustomStyledMenu
|
||||||
|
disableAutoFocusItem
|
||||||
|
open={!!menuPosition}
|
||||||
|
onClose={handleClose}
|
||||||
|
anchorReference="anchorPosition"
|
||||||
|
anchorPosition={
|
||||||
|
menuPosition
|
||||||
|
? { top: menuPosition.mouseY, left: menuPosition.mouseX }
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
onClick={(e) => {
|
||||||
|
handleClose(e);
|
||||||
|
addTimestamp()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="inherit" sx={{ fontSize: "14px" }}>
|
||||||
|
Unmark
|
||||||
|
</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
</CustomStyledMenu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -1874,17 +1874,17 @@ export const Group = ({
|
|||||||
// getTimestampEnterChat();
|
// getTimestampEnterChat();
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
window.sendMessage("addTimestampEnterChat", {
|
// window.sendMessage("addTimestampEnterChat", {
|
||||||
timestamp: Date.now(),
|
// timestamp: Date.now(),
|
||||||
groupId: group.groupId,
|
// groupId: group.groupId,
|
||||||
}).catch((error) => {
|
// }).catch((error) => {
|
||||||
console.error("Failed to add timestamp:", error.message || "An error occurred");
|
// console.error("Failed to add timestamp:", error.message || "An error occurred");
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
getTimestampEnterChat();
|
// getTimestampEnterChat();
|
||||||
}, 200);
|
// }, 200);
|
||||||
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
@ -2308,6 +2308,8 @@ export const Group = ({
|
|||||||
triedToFetchSecretKey={triedToFetchSecretKey}
|
triedToFetchSecretKey={triedToFetchSecretKey}
|
||||||
myName={userInfo?.name}
|
myName={userInfo?.name}
|
||||||
balance={balance}
|
balance={balance}
|
||||||
|
getTimestampEnterChatParent={getTimestampEnterChat}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{firstSecretKeyInCreation &&
|
{firstSecretKeyInCreation &&
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-container {
|
.image-container {
|
||||||
|
BIN
src/memory-pow.wasm
Normal file
BIN
src/memory-pow.wasm
Normal file
Binary file not shown.
@ -13,7 +13,8 @@ import {
|
|||||||
sendQortFee,
|
sendQortFee,
|
||||||
sendCoin as sendCoinFunc,
|
sendCoin as sendCoinFunc,
|
||||||
isUsingLocal,
|
isUsingLocal,
|
||||||
createBuyOrderTx
|
createBuyOrderTx,
|
||||||
|
performPowTask
|
||||||
} from "../background";
|
} from "../background";
|
||||||
import { getNameInfo } from "../backgroundFunctions/encryption";
|
import { getNameInfo } from "../backgroundFunctions/encryption";
|
||||||
import { showSaveFilePicker } from "../components/Apps/useQortalMessageListener";
|
import { showSaveFilePicker } from "../components/Apps/useQortalMessageListener";
|
||||||
@ -1062,7 +1063,6 @@ export const sendChatMessage = async (data, isFromExtension) => {
|
|||||||
publicKey: uint8PublicKey,
|
publicKey: uint8PublicKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
const difficulty = 8;
|
|
||||||
const tx = await createTransaction(18, keyPair, {
|
const tx = await createTransaction(18, keyPair, {
|
||||||
timestamp: sendTimestamp,
|
timestamp: sendTimestamp,
|
||||||
recipient: recipient,
|
recipient: recipient,
|
||||||
@ -1074,15 +1074,9 @@ export const sendChatMessage = async (data, isFromExtension) => {
|
|||||||
isEncrypted: 1,
|
isEncrypted: 1,
|
||||||
isText: 1,
|
isText: 1,
|
||||||
});
|
});
|
||||||
const path = `${import.meta.env.BASE_URL}memory-pow.wasm.full`;
|
const chatBytes = tx.chatBytes;
|
||||||
|
const difficulty = 8;
|
||||||
|
const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty);
|
||||||
const { nonce, chatBytesArray } = await computePow({
|
|
||||||
chatBytes: tx.chatBytes,
|
|
||||||
path,
|
|
||||||
difficulty,
|
|
||||||
});
|
|
||||||
|
|
||||||
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
||||||
if (_response?.error) {
|
if (_response?.error) {
|
||||||
throw new Error(_response?.message);
|
throw new Error(_response?.message);
|
||||||
@ -1102,7 +1096,6 @@ export const sendChatMessage = async (data, isFromExtension) => {
|
|||||||
publicKey: uint8PublicKey,
|
publicKey: uint8PublicKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
const difficulty = 8;
|
|
||||||
|
|
||||||
const txBody = {
|
const txBody = {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
@ -1121,14 +1114,9 @@ export const sendChatMessage = async (data, isFromExtension) => {
|
|||||||
// if (!hasEnoughBalance) {
|
// if (!hasEnoughBalance) {
|
||||||
// throw new Error("Must have at least 4 QORT to send a chat message");
|
// throw new Error("Must have at least 4 QORT to send a chat message");
|
||||||
// }
|
// }
|
||||||
const path = `${import.meta.env.BASE_URL}memory-pow.wasm.full`;
|
const chatBytes = tx.chatBytes;
|
||||||
|
const difficulty = 8;
|
||||||
|
const { nonce, chatBytesArray } = await performPowTask(chatBytes, difficulty);
|
||||||
const { nonce, chatBytesArray } = await computePow({
|
|
||||||
chatBytes: tx.chatBytes,
|
|
||||||
path,
|
|
||||||
difficulty,
|
|
||||||
});
|
|
||||||
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
let _response = await signChatFunc(chatBytesArray, nonce, null, keyPair);
|
||||||
if (_response?.error) {
|
if (_response?.error) {
|
||||||
throw new Error(_response?.message);
|
throw new Error(_response?.message);
|
||||||
@ -1401,6 +1389,10 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
|
|||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isGateway = await isRunningGateway()
|
||||||
|
|
||||||
|
if(data?.coin === 'ARRR' && isGateway) throw new Error('Cannot view ARRR balance through the gateway. Please use your local node.')
|
||||||
|
|
||||||
const value = (await getPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`)) || false;
|
const value = (await getPermission(`qAPPAutoWalletBalance-${appInfo?.name}-${data.coin}`)) || false;
|
||||||
let skip = false;
|
let skip = false;
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -1454,7 +1446,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
|
|||||||
case "BTC":
|
case "BTC":
|
||||||
_url = await createEndpoint(`/crosschain/btc/walletbalance`);
|
_url = await createEndpoint(`/crosschain/btc/walletbalance`);
|
||||||
|
|
||||||
_body = parsedData.derivedMasterPublicKey;
|
_body = parsedData.btcPublicKey;
|
||||||
break;
|
break;
|
||||||
case "LTC":
|
case "LTC":
|
||||||
_url = await createEndpoint(`/crosschain/ltc/walletbalance`);
|
_url = await createEndpoint(`/crosschain/ltc/walletbalance`);
|
||||||
@ -2095,6 +2087,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
|
fee: fee * QORT_DECIMALS
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
@ -2119,7 +2112,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const btcWalletBalanceDecimals = Number(btcWalletBalance)
|
const btcWalletBalanceDecimals = Number(btcWalletBalance)
|
||||||
const btcAmountDecimals = Number(amount) * QORT_DECIMALS
|
const btcAmountDecimals = Number(amount) * QORT_DECIMALS
|
||||||
const fee = feePerByte * 500 // default 0.00050000
|
const fee = feePerByte * 500 // default 0.00050000
|
||||||
if (btcAmountDecimals + (fee * QORT_DECIMALS) > btcWalletBalanceDecimals) {
|
if (btcAmountDecimals + fee > btcWalletBalanceDecimals) {
|
||||||
throw new Error("INSUFFICIENT_FUNDS")
|
throw new Error("INSUFFICIENT_FUNDS")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2127,7 +2120,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
fee: fee
|
foreignFee: `${fee} BTC`
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
@ -2136,7 +2129,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
xprv58: xprv58,
|
xprv58: xprv58,
|
||||||
receivingAddress: recipient,
|
receivingAddress: recipient,
|
||||||
bitcoinAmount: amount,
|
bitcoinAmount: amount,
|
||||||
feePerByte: feePerByte * QORT_DECIMALS
|
feePerByte: feePerByte
|
||||||
}
|
}
|
||||||
const url = await createEndpoint(`/crosschain/btc/send`);
|
const url = await createEndpoint(`/crosschain/btc/send`);
|
||||||
|
|
||||||
@ -2177,14 +2170,14 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const ltcAmountDecimals = Number(amount) * QORT_DECIMALS
|
const ltcAmountDecimals = Number(amount) * QORT_DECIMALS
|
||||||
const balance = (Number(ltcWalletBalance) / 1e8).toFixed(8)
|
const balance = (Number(ltcWalletBalance) / 1e8).toFixed(8)
|
||||||
const fee = feePerByte * 1000 // default 0.00030000
|
const fee = feePerByte * 1000 // default 0.00030000
|
||||||
if (ltcAmountDecimals + (fee * QORT_DECIMALS) > ltcWalletBalanceDecimals) {
|
if (ltcAmountDecimals + fee > ltcWalletBalanceDecimals) {
|
||||||
throw new Error("Insufficient Funds!")
|
throw new Error("Insufficient Funds!")
|
||||||
}
|
}
|
||||||
const resPermission = await getUserPermission({
|
const resPermission = await getUserPermission({
|
||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
fee: fee
|
foreignFee: `${fee} LTC`
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
@ -2194,7 +2187,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
xprv58: xprv58,
|
xprv58: xprv58,
|
||||||
receivingAddress: recipient,
|
receivingAddress: recipient,
|
||||||
litecoinAmount: amount,
|
litecoinAmount: amount,
|
||||||
feePerByte: feePerByte * QORT_DECIMALS
|
feePerByte: feePerByte
|
||||||
}
|
}
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -2232,7 +2225,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const dogeAmountDecimals = Number(amount) * QORT_DECIMALS
|
const dogeAmountDecimals = Number(amount) * QORT_DECIMALS
|
||||||
const balance = (Number(dogeWalletBalance) / 1e8).toFixed(8)
|
const balance = (Number(dogeWalletBalance) / 1e8).toFixed(8)
|
||||||
const fee = feePerByte * 5000 // default 0.05000000
|
const fee = feePerByte * 5000 // default 0.05000000
|
||||||
if (dogeAmountDecimals + (fee * QORT_DECIMALS) > dogeWalletBalanceDecimals) {
|
if (dogeAmountDecimals + fee > dogeWalletBalanceDecimals) {
|
||||||
let errorMsg = "Insufficient Funds!"
|
let errorMsg = "Insufficient Funds!"
|
||||||
throw new Error(errorMsg)
|
throw new Error(errorMsg)
|
||||||
}
|
}
|
||||||
@ -2241,7 +2234,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
fee: fee
|
foreignFee: `${fee} DOGE`
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
@ -2250,7 +2243,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
xprv58: xprv58,
|
xprv58: xprv58,
|
||||||
receivingAddress: recipient,
|
receivingAddress: recipient,
|
||||||
dogecoinAmount: amount,
|
dogecoinAmount: amount,
|
||||||
feePerByte: feePerByte * QORT_DECIMALS
|
feePerByte: feePerByte
|
||||||
}
|
}
|
||||||
const url = await createEndpoint(`/crosschain/doge/send`);
|
const url = await createEndpoint(`/crosschain/doge/send`);
|
||||||
|
|
||||||
@ -2287,7 +2280,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const dgbWalletBalanceDecimals = Number(dgbWalletBalance)
|
const dgbWalletBalanceDecimals = Number(dgbWalletBalance)
|
||||||
const dgbAmountDecimals = Number(amount) * QORT_DECIMALS
|
const dgbAmountDecimals = Number(amount) * QORT_DECIMALS
|
||||||
const fee = feePerByte * 500 // default 0.00005000
|
const fee = feePerByte * 500 // default 0.00005000
|
||||||
if (dgbAmountDecimals + (fee * QORT_DECIMALS) > dgbWalletBalanceDecimals) {
|
if (dgbAmountDecimals + fee > dgbWalletBalanceDecimals) {
|
||||||
let errorMsg = "Insufficient Funds!"
|
let errorMsg = "Insufficient Funds!"
|
||||||
throw new Error(errorMsg)
|
throw new Error(errorMsg)
|
||||||
}
|
}
|
||||||
@ -2296,7 +2289,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
fee: fee
|
foreignFee: `${fee} DGB`
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
@ -2305,7 +2298,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
xprv58: xprv58,
|
xprv58: xprv58,
|
||||||
receivingAddress: recipient,
|
receivingAddress: recipient,
|
||||||
digibyteAmount: amount,
|
digibyteAmount: amount,
|
||||||
feePerByte: feePerByte * QORT_DECIMALS
|
feePerByte: feePerByte
|
||||||
}
|
}
|
||||||
const url = await createEndpoint(`/crosschain/dgb/send`);
|
const url = await createEndpoint(`/crosschain/dgb/send`);
|
||||||
|
|
||||||
@ -2344,7 +2337,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const rvnAmountDecimals = Number(amount) * QORT_DECIMALS
|
const rvnAmountDecimals = Number(amount) * QORT_DECIMALS
|
||||||
const balance = (Number(rvnWalletBalance) / 1e8).toFixed(8)
|
const balance = (Number(rvnWalletBalance) / 1e8).toFixed(8)
|
||||||
const fee = feePerByte * 500 // default 0.00562500
|
const fee = feePerByte * 500 // default 0.00562500
|
||||||
if (rvnAmountDecimals + (fee * QORT_DECIMALS) > rvnWalletBalanceDecimals) {
|
if (rvnAmountDecimals + fee > rvnWalletBalanceDecimals) {
|
||||||
|
|
||||||
let errorMsg = "Insufficient Funds!"
|
let errorMsg = "Insufficient Funds!"
|
||||||
throw new Error(errorMsg)
|
throw new Error(errorMsg)
|
||||||
@ -2354,7 +2347,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
fee: fee
|
foreignFee: `${fee} RVN`
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
@ -2363,7 +2356,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
xprv58: xprv58,
|
xprv58: xprv58,
|
||||||
receivingAddress: recipient,
|
receivingAddress: recipient,
|
||||||
ravencoinAmount: amount,
|
ravencoinAmount: amount,
|
||||||
feePerByte: feePerByte * QORT_DECIMALS
|
feePerByte: feePerByte
|
||||||
}
|
}
|
||||||
const url = await createEndpoint(`/crosschain/rvn/send`);
|
const url = await createEndpoint(`/crosschain/rvn/send`);
|
||||||
|
|
||||||
@ -2399,7 +2392,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
const arrrWalletBalanceDecimals = Number(arrrWalletBalance)
|
const arrrWalletBalanceDecimals = Number(arrrWalletBalance)
|
||||||
const arrrAmountDecimals = Number(amount) * QORT_DECIMALS
|
const arrrAmountDecimals = Number(amount) * QORT_DECIMALS
|
||||||
const fee = 0.00010000
|
const fee = 0.00010000
|
||||||
if (arrrAmountDecimals + (fee * QORT_DECIMALS) > arrrWalletBalanceDecimals) {
|
if (arrrAmountDecimals + fee > arrrWalletBalanceDecimals) {
|
||||||
let errorMsg = "Insufficient Funds!"
|
let errorMsg = "Insufficient Funds!"
|
||||||
throw new Error(errorMsg)
|
throw new Error(errorMsg)
|
||||||
}
|
}
|
||||||
@ -2408,7 +2401,7 @@ export const sendCoin = async (data, isFromExtension) => {
|
|||||||
text1: "Do you give this application permission to send coins?",
|
text1: "Do you give this application permission to send coins?",
|
||||||
text2: `To: ${recipient}`,
|
text2: `To: ${recipient}`,
|
||||||
highlightedText: `${amount} ${checkCoin}`,
|
highlightedText: `${amount} ${checkCoin}`,
|
||||||
fee: fee
|
foreignFee: `${fee} ARRR`
|
||||||
}, isFromExtension);
|
}, isFromExtension);
|
||||||
const { accepted } = resPermission;
|
const { accepted } = resPermission;
|
||||||
|
|
||||||
|
@ -4,14 +4,12 @@ import react from '@vitejs/plugin-react';
|
|||||||
// Import path module for resolving file paths
|
// Import path module for resolving file paths
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import fixReactVirtualized from 'esbuild-plugin-react-virtualized'
|
import fixReactVirtualized from 'esbuild-plugin-react-virtualized'
|
||||||
|
import wasm from 'vite-plugin-wasm';
|
||||||
|
import topLevelAwait from 'vite-plugin-top-level-await';
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: {
|
|
||||||
environment: 'jsdom',
|
assetsInclude: ['**/*.wasm'],
|
||||||
globals: true,
|
plugins: [react(), wasm(), topLevelAwait()],
|
||||||
setupFiles: ['./src/test/setup.ts']
|
|
||||||
},
|
|
||||||
plugins: [react()],
|
|
||||||
build: {
|
build: {
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
// Specify multiple entry points for Rollup
|
// Specify multiple entry points for Rollup
|
||||||
|
Loading…
x
Reference in New Issue
Block a user