mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-02-25 18:42:03 +00:00
feat: matrix
This commit is contained in:
@@ -65,6 +65,8 @@ const config = {
|
|||||||
"bolt",
|
"bolt",
|
||||||
"undo",
|
"undo",
|
||||||
"redo",
|
"redo",
|
||||||
|
"replay",
|
||||||
|
"reply",
|
||||||
"navigate_before",
|
"navigate_before",
|
||||||
"navigate_next",
|
"navigate_next",
|
||||||
"print",
|
"print",
|
||||||
@@ -91,6 +93,10 @@ const config = {
|
|||||||
"upload_2",
|
"upload_2",
|
||||||
"stat_minus_2",
|
"stat_minus_2",
|
||||||
"stat_2",
|
"stat_2",
|
||||||
|
"send",
|
||||||
|
"more_horiz",
|
||||||
|
"add_reaction",
|
||||||
|
"stop",
|
||||||
"description",
|
"description",
|
||||||
"add_circle",
|
"add_circle",
|
||||||
"refresh",
|
"refresh",
|
||||||
|
|||||||
@@ -65,10 +65,12 @@
|
|||||||
"fontkit": "^2.0.2",
|
"fontkit": "^2.0.2",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"jsdom": "^24.1.1",
|
"jsdom": "^24.1.1",
|
||||||
|
"matrix-js-sdk": "^34.4.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-svelte": "^3.2.6",
|
"prettier-plugin-svelte": "^3.2.6",
|
||||||
"sass": "^1.77.8",
|
"sass": "^1.77.8",
|
||||||
|
"socket.io-client": "^4.7.5",
|
||||||
"stylelint": "^16.8.1",
|
"stylelint": "^16.8.1",
|
||||||
"stylelint-config-clean-order": "^6.1.0",
|
"stylelint-config-clean-order": "^6.1.0",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
|
|||||||
215
pnpm-lock.yaml
generated
215
pnpm-lock.yaml
generated
@@ -101,6 +101,9 @@ importers:
|
|||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^24.1.1
|
specifier: ^24.1.1
|
||||||
version: 24.1.1
|
version: 24.1.1
|
||||||
|
matrix-js-sdk:
|
||||||
|
specifier: ^34.4.0
|
||||||
|
version: 34.4.0
|
||||||
npm-run-all:
|
npm-run-all:
|
||||||
specifier: ^4.1.5
|
specifier: ^4.1.5
|
||||||
version: 4.1.5
|
version: 4.1.5
|
||||||
@@ -113,6 +116,9 @@ importers:
|
|||||||
sass:
|
sass:
|
||||||
specifier: ^1.77.8
|
specifier: ^1.77.8
|
||||||
version: 1.77.8
|
version: 1.77.8
|
||||||
|
socket.io-client:
|
||||||
|
specifier: ^4.7.5
|
||||||
|
version: 4.7.5
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: ^16.8.1
|
specifier: ^16.8.1
|
||||||
version: 16.8.1(typescript@5.5.4)
|
version: 16.8.1(typescript@5.5.4)
|
||||||
@@ -1015,6 +1021,13 @@ packages:
|
|||||||
'@material/material-color-utilities@0.3.0':
|
'@material/material-color-utilities@0.3.0':
|
||||||
resolution: {integrity: sha512-ztmtTd6xwnuh2/xu+Vb01btgV8SQWYCaK56CkRK8gEkWe5TuDyBcYJ0wgkMRn+2VcE9KUmhvkz+N9GHrqw/C0g==}
|
resolution: {integrity: sha512-ztmtTd6xwnuh2/xu+Vb01btgV8SQWYCaK56CkRK8gEkWe5TuDyBcYJ0wgkMRn+2VcE9KUmhvkz+N9GHrqw/C0g==}
|
||||||
|
|
||||||
|
'@matrix-org/matrix-sdk-crypto-wasm@7.0.0':
|
||||||
|
resolution: {integrity: sha512-MOencXiW/gI5MuTtCNsuojjwT5DXCrjMqv9xOslJC9h2tPdLFFFMGr58dY5Lis4DRd9MRWcgrGowUIHOqieWTA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
|
'@matrix-org/olm@3.2.15':
|
||||||
|
resolution: {integrity: sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q==}
|
||||||
|
|
||||||
'@melt-ui/pp@0.3.2':
|
'@melt-ui/pp@0.3.2':
|
||||||
resolution: {integrity: sha512-xKkPvaIAFinklLXcQOpwZ8YSpqAFxykjWf8Y/fSJQwsixV/0rcFs07hJ49hJjPy5vItvw5Qa0uOjzFUbXzBypQ==}
|
resolution: {integrity: sha512-xKkPvaIAFinklLXcQOpwZ8YSpqAFxykjWf8Y/fSJQwsixV/0rcFs07hJ49hJjPy5vItvw5Qa0uOjzFUbXzBypQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1234,6 +1247,9 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@socket.io/component-emitter@3.1.2':
|
||||||
|
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||||
|
|
||||||
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
||||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||||
|
|
||||||
@@ -1356,6 +1372,9 @@ packages:
|
|||||||
'@types/estree@1.0.5':
|
'@types/estree@1.0.5':
|
||||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||||
|
|
||||||
|
'@types/events@3.0.3':
|
||||||
|
resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==}
|
||||||
|
|
||||||
'@types/flexsearch@0.7.6':
|
'@types/flexsearch@0.7.6':
|
||||||
resolution: {integrity: sha512-H5IXcRn96/gaDmo+rDl2aJuIJsob8dgOXDqf8K0t8rWZd1AFNaaspmRsElESiU+EWE33qfbFPgI0OC/B1g9FCA==}
|
resolution: {integrity: sha512-H5IXcRn96/gaDmo+rDl2aJuIJsob8dgOXDqf8K0t8rWZd1AFNaaspmRsElESiU+EWE33qfbFPgI0OC/B1g9FCA==}
|
||||||
|
|
||||||
@@ -1368,6 +1387,9 @@ packages:
|
|||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
|
'@types/retry@0.12.0':
|
||||||
|
resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
|
||||||
|
|
||||||
'@types/sinonjs__fake-timers@8.1.1':
|
'@types/sinonjs__fake-timers@8.1.1':
|
||||||
resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
|
resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
|
||||||
|
|
||||||
@@ -1436,6 +1458,9 @@ packages:
|
|||||||
ajv@8.16.0:
|
ajv@8.16.0:
|
||||||
resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==}
|
resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==}
|
||||||
|
|
||||||
|
another-json@0.2.0:
|
||||||
|
resolution: {integrity: sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==}
|
||||||
|
|
||||||
ansi-colors@4.1.3:
|
ansi-colors@4.1.3:
|
||||||
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -1558,6 +1583,9 @@ packages:
|
|||||||
balanced-match@2.0.0:
|
balanced-match@2.0.0:
|
||||||
resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==}
|
resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==}
|
||||||
|
|
||||||
|
base-x@5.0.0:
|
||||||
|
resolution: {integrity: sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==}
|
||||||
|
|
||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
@@ -1595,6 +1623,9 @@ packages:
|
|||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
bs58@6.0.0:
|
||||||
|
resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==}
|
||||||
|
|
||||||
buffer-crc32@0.2.13:
|
buffer-crc32@0.2.13:
|
||||||
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
|
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
|
||||||
|
|
||||||
@@ -1726,6 +1757,10 @@ packages:
|
|||||||
concat-map@0.0.1:
|
concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
|
||||||
|
content-type@1.0.5:
|
||||||
|
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
convert-source-map@2.0.0:
|
convert-source-map@2.0.0:
|
||||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||||
|
|
||||||
@@ -2044,6 +2079,13 @@ packages:
|
|||||||
end-of-stream@1.4.4:
|
end-of-stream@1.4.4:
|
||||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||||
|
|
||||||
|
engine.io-client@6.5.4:
|
||||||
|
resolution: {integrity: sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==}
|
||||||
|
|
||||||
|
engine.io-parser@5.2.3:
|
||||||
|
resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
enquirer@2.4.1:
|
enquirer@2.4.1:
|
||||||
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
|
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
@@ -2121,6 +2163,10 @@ packages:
|
|||||||
eventemitter2@6.4.7:
|
eventemitter2@6.4.7:
|
||||||
resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
|
resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
|
||||||
|
|
||||||
|
events@3.3.0:
|
||||||
|
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||||
|
engines: {node: '>=0.8.x'}
|
||||||
|
|
||||||
execa@4.1.0:
|
execa@4.1.0:
|
||||||
resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
|
resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -2674,6 +2720,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
|
resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
|
||||||
engines: {'0': node >=0.6.0}
|
engines: {'0': node >=0.6.0}
|
||||||
|
|
||||||
|
jwt-decode@4.0.0:
|
||||||
|
resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
@@ -2741,6 +2791,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
|
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
loglevel@1.9.2:
|
||||||
|
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
|
||||||
|
engines: {node: '>= 0.6.0'}
|
||||||
|
|
||||||
loupe@3.1.1:
|
loupe@3.1.1:
|
||||||
resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
|
resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
|
||||||
|
|
||||||
@@ -2760,6 +2814,16 @@ packages:
|
|||||||
mathml-tag-names@2.1.3:
|
mathml-tag-names@2.1.3:
|
||||||
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
||||||
|
|
||||||
|
matrix-events-sdk@0.0.1:
|
||||||
|
resolution: {integrity: sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==}
|
||||||
|
|
||||||
|
matrix-js-sdk@34.4.0:
|
||||||
|
resolution: {integrity: sha512-bI5xJZS3/qhjPQqQL5HhOQ1iBvnHxiqhS2zgzk9SarEuXiH08wbVl9gAAuDqOYE3miNGs4WQQJ19MoaUEOnNwg==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
|
||||||
|
matrix-widget-api@1.9.0:
|
||||||
|
resolution: {integrity: sha512-au8mqralNDqrEvaVAkU37bXOb8I9SCe+ACdPk11QWw58FKstVq31q2wRz+qWA6J+42KJ6s1DggWbG/S3fEs3jw==}
|
||||||
|
|
||||||
mdn-data@2.0.30:
|
mdn-data@2.0.30:
|
||||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||||
|
|
||||||
@@ -2893,6 +2957,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
|
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
oidc-client-ts@3.0.1:
|
||||||
|
resolution: {integrity: sha512-xX8unZNtmtw3sOz4FPSqDhkLFnxCDsdo2qhFEH2opgWnF/iXMFoYdBQzkwCxAZVgt3FT3DnuBY3k80EZHT0RYg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||||
|
|
||||||
@@ -2911,6 +2979,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
|
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
p-retry@4.6.2:
|
||||||
|
resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
package-json-from-dist@1.0.0:
|
package-json-from-dist@1.0.0:
|
||||||
resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
|
resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
|
||||||
|
|
||||||
@@ -3173,6 +3245,10 @@ packages:
|
|||||||
restructure@3.0.2:
|
restructure@3.0.2:
|
||||||
resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==}
|
resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==}
|
||||||
|
|
||||||
|
retry@0.13.1:
|
||||||
|
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
reusify@1.0.4:
|
reusify@1.0.4:
|
||||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||||
@@ -3243,6 +3319,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
|
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
|
||||||
engines: {node: '>=v12.22.7'}
|
engines: {node: '>=v12.22.7'}
|
||||||
|
|
||||||
|
sdp-transform@2.14.2:
|
||||||
|
resolution: {integrity: sha512-icY6jVao7MfKCieyo1AyxFYm1baiM+fA00qW/KrNNVlkxHAd34riEKuEkUe4bBb3gJwLJZM+xT60Yj1QL8rHiA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
semver@5.7.2:
|
semver@5.7.2:
|
||||||
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
|
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -3322,6 +3402,14 @@ packages:
|
|||||||
smob@1.5.0:
|
smob@1.5.0:
|
||||||
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
|
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
|
||||||
|
|
||||||
|
socket.io-client@4.7.5:
|
||||||
|
resolution: {integrity: sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
socket.io-parser@4.2.4:
|
||||||
|
resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
sorcery@0.11.1:
|
sorcery@0.11.1:
|
||||||
resolution: {integrity: sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==}
|
resolution: {integrity: sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -3748,6 +3836,9 @@ packages:
|
|||||||
undici-types@5.26.5:
|
undici-types@5.26.5:
|
||||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||||
|
|
||||||
|
unhomoglyph@1.0.6:
|
||||||
|
resolution: {integrity: sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==}
|
||||||
|
|
||||||
unicode-canonical-property-names-ecmascript@2.0.0:
|
unicode-canonical-property-names-ecmascript@2.0.0:
|
||||||
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
|
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -3808,6 +3899,10 @@ packages:
|
|||||||
util-deprecate@1.0.2:
|
util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
|
uuid@10.0.0:
|
||||||
|
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
uuid@8.3.2:
|
uuid@8.3.2:
|
||||||
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -4021,6 +4116,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
|
resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
|
||||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||||
|
|
||||||
|
ws@8.17.1:
|
||||||
|
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: '>=5.0.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
ws@8.18.0:
|
ws@8.18.0:
|
||||||
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
@@ -4040,6 +4147,10 @@ packages:
|
|||||||
xmlchars@2.2.0:
|
xmlchars@2.2.0:
|
||||||
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
|
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@2.0.0:
|
||||||
|
resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
yallist@3.1.1:
|
yallist@3.1.1:
|
||||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||||
|
|
||||||
@@ -5069,6 +5180,10 @@ snapshots:
|
|||||||
|
|
||||||
'@material/material-color-utilities@0.3.0': {}
|
'@material/material-color-utilities@0.3.0': {}
|
||||||
|
|
||||||
|
'@matrix-org/matrix-sdk-crypto-wasm@7.0.0': {}
|
||||||
|
|
||||||
|
'@matrix-org/olm@3.2.15': {}
|
||||||
|
|
||||||
'@melt-ui/pp@0.3.2(@melt-ui/svelte@0.83.0(svelte@5.0.0-next.221))(svelte@5.0.0-next.221)':
|
'@melt-ui/pp@0.3.2(@melt-ui/svelte@0.83.0(svelte@5.0.0-next.221))(svelte@5.0.0-next.221)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@melt-ui/svelte': 0.83.0(svelte@5.0.0-next.221)
|
'@melt-ui/svelte': 0.83.0(svelte@5.0.0-next.221)
|
||||||
@@ -5274,6 +5389,8 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc@4.18.0':
|
'@rollup/rollup-win32-x64-msvc@4.18.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@socket.io/component-emitter@3.1.2': {}
|
||||||
|
|
||||||
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
ejs: 3.1.10
|
ejs: 3.1.10
|
||||||
@@ -5392,6 +5509,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.5': {}
|
'@types/estree@1.0.5': {}
|
||||||
|
|
||||||
|
'@types/events@3.0.3': {}
|
||||||
|
|
||||||
'@types/flexsearch@0.7.6': {}
|
'@types/flexsearch@0.7.6': {}
|
||||||
|
|
||||||
'@types/node@20.14.10':
|
'@types/node@20.14.10':
|
||||||
@@ -5403,6 +5522,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/resolve@1.20.2': {}
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
|
'@types/retry@0.12.0': {}
|
||||||
|
|
||||||
'@types/sinonjs__fake-timers@8.1.1': {}
|
'@types/sinonjs__fake-timers@8.1.1': {}
|
||||||
|
|
||||||
'@types/sizzle@2.3.8': {}
|
'@types/sizzle@2.3.8': {}
|
||||||
@@ -5481,6 +5602,8 @@ snapshots:
|
|||||||
require-from-string: 2.0.2
|
require-from-string: 2.0.2
|
||||||
uri-js: 4.4.1
|
uri-js: 4.4.1
|
||||||
|
|
||||||
|
another-json@0.2.0: {}
|
||||||
|
|
||||||
ansi-colors@4.1.3: {}
|
ansi-colors@4.1.3: {}
|
||||||
|
|
||||||
ansi-escapes@4.3.2:
|
ansi-escapes@4.3.2:
|
||||||
@@ -5606,6 +5729,8 @@ snapshots:
|
|||||||
|
|
||||||
balanced-match@2.0.0: {}
|
balanced-match@2.0.0: {}
|
||||||
|
|
||||||
|
base-x@5.0.0: {}
|
||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
bcrypt-pbkdf@1.0.2:
|
bcrypt-pbkdf@1.0.2:
|
||||||
@@ -5644,6 +5769,10 @@ snapshots:
|
|||||||
node-releases: 2.0.14
|
node-releases: 2.0.14
|
||||||
update-browserslist-db: 1.1.0(browserslist@4.23.1)
|
update-browserslist-db: 1.1.0(browserslist@4.23.1)
|
||||||
|
|
||||||
|
bs58@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
base-x: 5.0.0
|
||||||
|
|
||||||
buffer-crc32@0.2.13: {}
|
buffer-crc32@0.2.13: {}
|
||||||
|
|
||||||
buffer-crc32@1.0.0: {}
|
buffer-crc32@1.0.0: {}
|
||||||
@@ -5773,6 +5902,8 @@ snapshots:
|
|||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
|
||||||
|
content-type@1.0.5: {}
|
||||||
|
|
||||||
convert-source-map@2.0.0: {}
|
convert-source-map@2.0.0: {}
|
||||||
|
|
||||||
cookie@0.6.0: {}
|
cookie@0.6.0: {}
|
||||||
@@ -6142,6 +6273,20 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
|
|
||||||
|
engine.io-client@6.5.4:
|
||||||
|
dependencies:
|
||||||
|
'@socket.io/component-emitter': 3.1.2
|
||||||
|
debug: 4.3.6
|
||||||
|
engine.io-parser: 5.2.3
|
||||||
|
ws: 8.17.1
|
||||||
|
xmlhttprequest-ssl: 2.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- supports-color
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
engine.io-parser@5.2.3: {}
|
||||||
|
|
||||||
enquirer@2.4.1:
|
enquirer@2.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-colors: 4.1.3
|
ansi-colors: 4.1.3
|
||||||
@@ -6277,6 +6422,8 @@ snapshots:
|
|||||||
|
|
||||||
eventemitter2@6.4.7: {}
|
eventemitter2@6.4.7: {}
|
||||||
|
|
||||||
|
events@3.3.0: {}
|
||||||
|
|
||||||
execa@4.1.0:
|
execa@4.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
@@ -6841,6 +6988,8 @@ snapshots:
|
|||||||
json-schema: 0.4.0
|
json-schema: 0.4.0
|
||||||
verror: 1.10.0
|
verror: 1.10.0
|
||||||
|
|
||||||
|
jwt-decode@4.0.0: {}
|
||||||
|
|
||||||
keyv@4.5.4:
|
keyv@4.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
@@ -6903,6 +7052,8 @@ snapshots:
|
|||||||
slice-ansi: 4.0.0
|
slice-ansi: 4.0.0
|
||||||
wrap-ansi: 6.2.0
|
wrap-ansi: 6.2.0
|
||||||
|
|
||||||
|
loglevel@1.9.2: {}
|
||||||
|
|
||||||
loupe@3.1.1:
|
loupe@3.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
get-func-name: 2.0.2
|
get-func-name: 2.0.2
|
||||||
@@ -6923,6 +7074,31 @@ snapshots:
|
|||||||
|
|
||||||
mathml-tag-names@2.1.3: {}
|
mathml-tag-names@2.1.3: {}
|
||||||
|
|
||||||
|
matrix-events-sdk@0.0.1: {}
|
||||||
|
|
||||||
|
matrix-js-sdk@34.4.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
'@matrix-org/matrix-sdk-crypto-wasm': 7.0.0
|
||||||
|
'@matrix-org/olm': 3.2.15
|
||||||
|
another-json: 0.2.0
|
||||||
|
bs58: 6.0.0
|
||||||
|
content-type: 1.0.5
|
||||||
|
jwt-decode: 4.0.0
|
||||||
|
loglevel: 1.9.2
|
||||||
|
matrix-events-sdk: 0.0.1
|
||||||
|
matrix-widget-api: 1.9.0
|
||||||
|
oidc-client-ts: 3.0.1
|
||||||
|
p-retry: 4.6.2
|
||||||
|
sdp-transform: 2.14.2
|
||||||
|
unhomoglyph: 1.0.6
|
||||||
|
uuid: 10.0.0
|
||||||
|
|
||||||
|
matrix-widget-api@1.9.0:
|
||||||
|
dependencies:
|
||||||
|
'@types/events': 3.0.3
|
||||||
|
events: 3.3.0
|
||||||
|
|
||||||
mdn-data@2.0.30: {}
|
mdn-data@2.0.30: {}
|
||||||
|
|
||||||
memorystream@0.3.1: {}
|
memorystream@0.3.1: {}
|
||||||
@@ -7030,6 +7206,10 @@ snapshots:
|
|||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
|
|
||||||
|
oidc-client-ts@3.0.1:
|
||||||
|
dependencies:
|
||||||
|
jwt-decode: 4.0.0
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
@@ -7048,6 +7228,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
aggregate-error: 3.1.0
|
aggregate-error: 3.1.0
|
||||||
|
|
||||||
|
p-retry@4.6.2:
|
||||||
|
dependencies:
|
||||||
|
'@types/retry': 0.12.0
|
||||||
|
retry: 0.13.1
|
||||||
|
|
||||||
package-json-from-dist@1.0.0: {}
|
package-json-from-dist@1.0.0: {}
|
||||||
|
|
||||||
pako@0.2.9: {}
|
pako@0.2.9: {}
|
||||||
@@ -7273,6 +7458,8 @@ snapshots:
|
|||||||
|
|
||||||
restructure@3.0.2: {}
|
restructure@3.0.2: {}
|
||||||
|
|
||||||
|
retry@0.13.1: {}
|
||||||
|
|
||||||
reusify@1.0.4: {}
|
reusify@1.0.4: {}
|
||||||
|
|
||||||
rfdc@1.4.1: {}
|
rfdc@1.4.1: {}
|
||||||
@@ -7361,6 +7548,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
xmlchars: 2.2.0
|
xmlchars: 2.2.0
|
||||||
|
|
||||||
|
sdp-transform@2.14.2: {}
|
||||||
|
|
||||||
semver@5.7.2: {}
|
semver@5.7.2: {}
|
||||||
|
|
||||||
semver@6.3.1: {}
|
semver@6.3.1: {}
|
||||||
@@ -7438,6 +7627,24 @@ snapshots:
|
|||||||
|
|
||||||
smob@1.5.0: {}
|
smob@1.5.0: {}
|
||||||
|
|
||||||
|
socket.io-client@4.7.5:
|
||||||
|
dependencies:
|
||||||
|
'@socket.io/component-emitter': 3.1.2
|
||||||
|
debug: 4.3.6
|
||||||
|
engine.io-client: 6.5.4
|
||||||
|
socket.io-parser: 4.2.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- supports-color
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
socket.io-parser@4.2.4:
|
||||||
|
dependencies:
|
||||||
|
'@socket.io/component-emitter': 3.1.2
|
||||||
|
debug: 4.3.6
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
sorcery@0.11.1:
|
sorcery@0.11.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
@@ -7898,6 +8105,8 @@ snapshots:
|
|||||||
undici-types@5.26.5:
|
undici-types@5.26.5:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
unhomoglyph@1.0.6: {}
|
||||||
|
|
||||||
unicode-canonical-property-names-ecmascript@2.0.0: {}
|
unicode-canonical-property-names-ecmascript@2.0.0: {}
|
||||||
|
|
||||||
unicode-match-property-ecmascript@2.0.0:
|
unicode-match-property-ecmascript@2.0.0:
|
||||||
@@ -7950,6 +8159,8 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
|
uuid@10.0.0: {}
|
||||||
|
|
||||||
uuid@8.3.2: {}
|
uuid@8.3.2: {}
|
||||||
|
|
||||||
validate-npm-package-license@3.0.4:
|
validate-npm-package-license@3.0.4:
|
||||||
@@ -8243,12 +8454,16 @@ snapshots:
|
|||||||
imurmurhash: 0.1.4
|
imurmurhash: 0.1.4
|
||||||
signal-exit: 4.1.0
|
signal-exit: 4.1.0
|
||||||
|
|
||||||
|
ws@8.17.1: {}
|
||||||
|
|
||||||
ws@8.18.0: {}
|
ws@8.18.0: {}
|
||||||
|
|
||||||
xml-name-validator@5.0.0: {}
|
xml-name-validator@5.0.0: {}
|
||||||
|
|
||||||
xmlchars@2.2.0: {}
|
xmlchars@2.2.0: {}
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@2.0.0: {}
|
||||||
|
|
||||||
yallist@3.1.1: {}
|
yallist@3.1.1: {}
|
||||||
|
|
||||||
yauzl@2.10.0:
|
yauzl@2.10.0:
|
||||||
|
|||||||
1
src/env.d.ts
vendored
1
src/env.d.ts
vendored
@@ -14,6 +14,7 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_LEARN_URL: string;
|
readonly VITE_LEARN_URL: string;
|
||||||
readonly VITE_LATEST_FIRMWARE: string;
|
readonly VITE_LATEST_FIRMWARE: string;
|
||||||
readonly VITE_STORE_URL: string;
|
readonly VITE_STORE_URL: string;
|
||||||
|
readonly VITE_MATRIX_URL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
@@ -11,11 +11,13 @@
|
|||||||
cursor = false,
|
cursor = false,
|
||||||
keys = false,
|
keys = false,
|
||||||
children,
|
children,
|
||||||
|
ondone,
|
||||||
}: {
|
}: {
|
||||||
replay: ReplayPlayer | Replay;
|
replay: ReplayPlayer | Replay;
|
||||||
cursor?: boolean;
|
cursor?: boolean;
|
||||||
keys?: boolean;
|
keys?: boolean;
|
||||||
children?: Snippet;
|
children?: Snippet;
|
||||||
|
ondone?: () => void;
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
let replayPlayer: ReplayPlayer | undefined = $state();
|
let replayPlayer: ReplayPlayer | undefined = $state();
|
||||||
@@ -61,6 +63,7 @@
|
|||||||
const unsubscribePlayer = player.subscribe(apply);
|
const unsubscribePlayer = player.subscribe(apply);
|
||||||
textRenderer = renderer;
|
textRenderer = renderer;
|
||||||
|
|
||||||
|
player.onDone = ondone;
|
||||||
player.start();
|
player.start();
|
||||||
apply();
|
apply();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ export class ReplayPlayer {
|
|||||||
|
|
||||||
private subscribers = new Set<(value: TextToken | undefined) => void>();
|
private subscribers = new Set<(value: TextToken | undefined) => void>();
|
||||||
|
|
||||||
|
onDone?: () => void;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly replay: Replay,
|
readonly replay: Replay,
|
||||||
plugins: ReplayPlugin[] = [],
|
plugins: ReplayPlugin[] = [],
|
||||||
@@ -37,8 +39,13 @@ export class ReplayPlayer {
|
|||||||
if (
|
if (
|
||||||
this.replayCursor >= this.replay.keys.length &&
|
this.replayCursor >= this.replay.keys.length &&
|
||||||
this.releaseAt.size === 0
|
this.releaseAt.size === 0
|
||||||
)
|
) {
|
||||||
|
if (this.onDone) {
|
||||||
|
this.onDone();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const now = performance.now() - this.startTime;
|
const now = performance.now() - this.startTime;
|
||||||
|
|
||||||
while (
|
while (
|
||||||
@@ -118,7 +125,12 @@ export class ReplayPlayer {
|
|||||||
start(delay = 200): this {
|
start(delay = 200): this {
|
||||||
this.replayCursor = 0;
|
this.replayCursor = 0;
|
||||||
this.stepper = new ReplayStepper([], this.replay.challenge);
|
this.stepper = new ReplayStepper([], this.replay.challenge);
|
||||||
if (this.replay.keys.length === 0) return this;
|
if (this.replay.keys.length === 0) {
|
||||||
|
if (this.onDone) {
|
||||||
|
this.onDone();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.startTime = performance.now();
|
this.startTime = performance.now();
|
||||||
this.animationFrameId = requestAnimationFrame(this.updateLoop.bind(this));
|
this.animationFrameId = requestAnimationFrame(this.updateLoop.bind(this));
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { ReplayPlayer } from "./player.js";
|
import { ReplayPlayer } from "./player.js";
|
||||||
import type { Replay, ReplayEvent, TransmittableKeyEvent } from "./types.js";
|
import type { Replay, ReplayEvent, TransmittableKeyEvent } from "./types.js";
|
||||||
|
|
||||||
|
function maybeRound<T>(value: T, round: boolean): T {
|
||||||
|
return typeof value === "number" && round ? (Math.round(value) as T) : value;
|
||||||
|
}
|
||||||
|
|
||||||
export class ReplayRecorder {
|
export class ReplayRecorder {
|
||||||
private held = new Map<string, [string, number]>();
|
private held = new Map<string, [string, number]>();
|
||||||
|
|
||||||
@@ -39,7 +43,7 @@ export class ReplayRecorder {
|
|||||||
this.player.playLiveEvent(event.key, event.code),
|
this.player.playLiveEvent(event.key, event.code),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const [key, start] = this.held.get(event.code)!;
|
const [key, start] = this.held.get(event.code) ?? ["", 0];
|
||||||
const delta = event.timeStamp - start;
|
const delta = event.timeStamp - start;
|
||||||
this.held.delete(event.code);
|
this.held.delete(event.code);
|
||||||
|
|
||||||
@@ -50,16 +54,24 @@ export class ReplayRecorder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finish(trim = true) {
|
finish(trim = true, round = true) {
|
||||||
return {
|
return {
|
||||||
start: trim ? this.replay[0]?.[2] : this.start,
|
start: maybeRound(trim ? this.replay[0]?.[2] : this.start, round),
|
||||||
finish: trim
|
finish: maybeRound(
|
||||||
? Math.max(...this.replay.map((it) => it[2] + it[3]))
|
trim
|
||||||
: performance.now(),
|
? Math.max(...this.replay.map((it) => it[2] + it[3]))
|
||||||
|
: performance.now(),
|
||||||
|
round,
|
||||||
|
),
|
||||||
keys: this.replay
|
keys: this.replay
|
||||||
.map(
|
.map(
|
||||||
([key, code, at, duration]) =>
|
([key, code, at, duration]) =>
|
||||||
[key, code, Math.round(at), Math.round(duration)] as const,
|
[
|
||||||
|
key,
|
||||||
|
code,
|
||||||
|
maybeRound(at, round),
|
||||||
|
maybeRound(duration, round),
|
||||||
|
] as const,
|
||||||
)
|
)
|
||||||
.sort((a, b) => a[2] - b[2]),
|
.sort((a, b) => a[2] - b[2]),
|
||||||
};
|
};
|
||||||
|
|||||||
71
src/lib/chat/MatrixRoomMembers.svelte
Normal file
71
src/lib/chat/MatrixRoomMembers.svelte
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { RoomMember } from "matrix-js-sdk";
|
||||||
|
import { matrixClient, memberColor } from "./chat";
|
||||||
|
import { theme } from "$lib/preferences";
|
||||||
|
import { hexFromArgb } from "@material/material-color-utilities";
|
||||||
|
|
||||||
|
let { members }: { members: RoomMember[] } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="member-list">
|
||||||
|
{#each members as member (member.userId)}
|
||||||
|
{@const avatar = member.getMxcAvatarUrl()}
|
||||||
|
<div class="member">
|
||||||
|
{#if avatar}
|
||||||
|
<img
|
||||||
|
class="avatar"
|
||||||
|
src={$matrixClient.mxcUrlToHttp(avatar, 32, 32)}
|
||||||
|
alt={member.name}
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
{@const color = memberColor(member, $theme)}
|
||||||
|
{@const modeColor = $theme.mode === "dark" ? color.dark : color.light}
|
||||||
|
<div
|
||||||
|
style:background={hexFromArgb(modeColor.color)}
|
||||||
|
style:color={hexFromArgb(modeColor.onColor)}
|
||||||
|
class="avatar avatar-placeholder icon"
|
||||||
|
>
|
||||||
|
person
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<span>{member.name}</span>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.avatar {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 8px;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
73
src/lib/chat/MatrixRooms.svelte
Normal file
73
src/lib/chat/MatrixRooms.svelte
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Room } from "matrix-js-sdk";
|
||||||
|
import { matrixClient, currentRoomId } from "./chat";
|
||||||
|
|
||||||
|
let { rooms }: { rooms: Room[] } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="rooms">
|
||||||
|
{#each $matrixClient.getRooms() as room}
|
||||||
|
{@const avatar = room.getMxcAvatarUrl()}
|
||||||
|
<button
|
||||||
|
class:active={$currentRoomId === room.roomId}
|
||||||
|
class="room"
|
||||||
|
onclick={() => ($currentRoomId = room.roomId)}
|
||||||
|
>
|
||||||
|
{#if avatar}
|
||||||
|
<img
|
||||||
|
alt={room.name}
|
||||||
|
src={$matrixClient.mxcUrlToHttp(avatar, 16, 16)}
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div>#</div>
|
||||||
|
{/if}
|
||||||
|
<div>{room.name}</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#await $matrixClient.publicRooms()}
|
||||||
|
<div>Loading...</div>
|
||||||
|
{:then rooms}
|
||||||
|
{#each rooms.chunk as room}
|
||||||
|
<button class="room" onclick={() => ($currentRoomId = room.roomId)}>
|
||||||
|
<div>#</div>
|
||||||
|
<div>{room.name}</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
{:catch error}
|
||||||
|
<div>{error.message}</div>
|
||||||
|
{/await}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.rooms {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
padding-left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-block: 2px;
|
||||||
|
min-height: 0;
|
||||||
|
height: unset;
|
||||||
|
padding-inline: 16px;
|
||||||
|
padding-block: 4px;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: var(--md-sys-color-primary-container);
|
||||||
|
color: var(--md-sys-color-on-primary-container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
251
src/lib/chat/MatrixTimeline.svelte
Normal file
251
src/lib/chat/MatrixTimeline.svelte
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type {
|
||||||
|
EventTimeline,
|
||||||
|
MatrixEvent,
|
||||||
|
MsgType,
|
||||||
|
Room,
|
||||||
|
RoomEvent,
|
||||||
|
RoomMember,
|
||||||
|
RoomMemberEvent,
|
||||||
|
} from "matrix-js-sdk";
|
||||||
|
import { onDestroy, onMount, tick } from "svelte";
|
||||||
|
import { matrixClient } from "./chat";
|
||||||
|
import MatrixEventComponent from "./events/MatrixEvent.svelte";
|
||||||
|
import CharRecorder from "$lib/charrecorder/CharRecorder.svelte";
|
||||||
|
import { ReplayRecorder } from "$lib/charrecorder/core/recorder";
|
||||||
|
import { type Socket, io } from "socket.io-client";
|
||||||
|
import { SvelteMap } from "svelte/reactivity";
|
||||||
|
|
||||||
|
let { timeline }: { timeline: EventTimeline } = $props();
|
||||||
|
|
||||||
|
const excludeEvents = ["m.reaction", "m.room.redaction"];
|
||||||
|
|
||||||
|
let events = $state(
|
||||||
|
timeline
|
||||||
|
.getEvents()
|
||||||
|
.filter((it) => !excludeEvents.includes(it.getType()))
|
||||||
|
.reverse(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let recorder = $state(new ReplayRecorder());
|
||||||
|
let showCursor = $state(false);
|
||||||
|
|
||||||
|
let timelineElement: HTMLElement = $state()!;
|
||||||
|
|
||||||
|
async function onTimeline(
|
||||||
|
event: MatrixEvent,
|
||||||
|
room?: Room,
|
||||||
|
toStartOfTimeline?: boolean,
|
||||||
|
) {
|
||||||
|
if (room?.roomId !== timeline.getRoomId()) return;
|
||||||
|
const sender = event.getSender();
|
||||||
|
if (sender) {
|
||||||
|
live.delete(sender);
|
||||||
|
}
|
||||||
|
if (excludeEvents.includes(event.getType())) return;
|
||||||
|
if (toStartOfTimeline) {
|
||||||
|
events.push(event);
|
||||||
|
} else {
|
||||||
|
const needScroll = timelineElement.scrollTop < 20;
|
||||||
|
events.unshift(event);
|
||||||
|
if (needScroll) {
|
||||||
|
await tick();
|
||||||
|
timelineElement.scroll({
|
||||||
|
top: 0,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let typing = $state<string[]>([]);
|
||||||
|
|
||||||
|
function onTyping(event: MatrixEvent, member: RoomMember) {
|
||||||
|
typing = event.event.content?.["user_ids"] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function send() {
|
||||||
|
const roomId = timeline.getRoomId();
|
||||||
|
if (!roomId) return;
|
||||||
|
const finalText = recorder.player.stepper.text
|
||||||
|
.map((token) => token.text)
|
||||||
|
.join("");
|
||||||
|
const finalRecording = recorder.finish();
|
||||||
|
if (!finalText) return;
|
||||||
|
recorder = new ReplayRecorder();
|
||||||
|
await $matrixClient.sendMessage(roomId, {
|
||||||
|
msgtype: "m.text" as MsgType.Text,
|
||||||
|
body: finalText,
|
||||||
|
// @ts-expect-error
|
||||||
|
"m.replay": finalRecording,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKey(event: KeyboardEvent) {
|
||||||
|
if (event.type === "keyup" && event.key === "Enter" && !event.shiftKey) {
|
||||||
|
send();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
recorder.next(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type === "keyup" && recorder.player.stepper.text.length === 0) {
|
||||||
|
recorder = new ReplayRecorder();
|
||||||
|
} else {
|
||||||
|
socket.emit("message", {
|
||||||
|
timeStamp: event.timeStamp,
|
||||||
|
type: event.type,
|
||||||
|
key: event.key,
|
||||||
|
code: event.code,
|
||||||
|
username: $matrixClient.getUserId(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let socket: Socket = $state()!;
|
||||||
|
let live = new SvelteMap<string, ReplayRecorder>();
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
socket = io("https://srv.charachorder.io");
|
||||||
|
socket.emit("join", timeline.getRoomId());
|
||||||
|
|
||||||
|
socket.on("message", async ({ message }) => {
|
||||||
|
let userRecorder = live.get(message.username);
|
||||||
|
if (!userRecorder) {
|
||||||
|
userRecorder = new ReplayRecorder();
|
||||||
|
live.set(message.username, userRecorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
userRecorder.next(message);
|
||||||
|
|
||||||
|
if (userRecorder.player.stepper.text.length === 0) {
|
||||||
|
live.delete(message.username);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$matrixClient.on("Room.timeline" as RoomEvent.Timeline, onTimeline);
|
||||||
|
$matrixClient.on("RoomMember.typing" as RoomMemberEvent.Typing, onTyping);
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
socket?.disconnect();
|
||||||
|
$matrixClient.off("Room.timeline" as RoomEvent.Timeline, onTimeline);
|
||||||
|
$matrixClient.off("RoomMember.typing" as RoomMemberEvent.Typing, onTyping);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div bind:this={timelineElement} class="timeline">
|
||||||
|
{#each live.entries() as [userId, recorder] (userId)}
|
||||||
|
{@const roomId = timeline.getRoomId()}
|
||||||
|
{#if roomId}
|
||||||
|
{@const room = $matrixClient.getRoom(roomId)}
|
||||||
|
{@const member = room?.getMember(userId)}
|
||||||
|
{#if member}
|
||||||
|
<MatrixEventComponent sender={member} replay={recorder.player} />
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{#each events as event, i (event.event["event_id"])}
|
||||||
|
{@const prev = events[i + 1]}
|
||||||
|
<MatrixEventComponent {event} sender={event.sender} {prev} {timeline} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="static-elements">
|
||||||
|
<div class="indicators"></div>
|
||||||
|
<div class="input-box">
|
||||||
|
<button class="icon">add</button>
|
||||||
|
<div
|
||||||
|
role="textbox"
|
||||||
|
tabindex="0"
|
||||||
|
class="input"
|
||||||
|
onkeydown={onKey}
|
||||||
|
onkeyup={onKey}
|
||||||
|
onfocusin={() => (showCursor = true)}
|
||||||
|
onfocusout={() => (showCursor = false)}
|
||||||
|
>
|
||||||
|
<CharRecorder replay={recorder.player} cursor={showCursor} />
|
||||||
|
</div>
|
||||||
|
<button class="icon" onclick={send}>send</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$border-radius: 16px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
height: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border: 1px solid var(--md-sys-color-outline);
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: text;
|
||||||
|
padding: 0.5em;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
|
||||||
|
text-wrap: wrap;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
padding-block: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.static-elements {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline {
|
||||||
|
contain: content;
|
||||||
|
height: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-present {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-controls {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
min-height: 16px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent,
|
||||||
|
var(--md-sys-color-background)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
35
src/lib/chat/chat.ts
Normal file
35
src/lib/chat/chat.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
import type { MatrixClient, RoomMember } from "matrix-js-sdk";
|
||||||
|
import { persistentWritable } from "$lib/storage";
|
||||||
|
import {
|
||||||
|
themeFromSourceColor,
|
||||||
|
argbFromHex,
|
||||||
|
type CustomColorGroup,
|
||||||
|
} from "@material/material-color-utilities";
|
||||||
|
import type { UserTheme } from "$lib/preferences";
|
||||||
|
|
||||||
|
export const matrixClient: Writable<MatrixClient> = writable();
|
||||||
|
|
||||||
|
export const currentRoomId = persistentWritable<string | null>(
|
||||||
|
"currentRoomId",
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
export function memberColor(
|
||||||
|
member: RoomMember,
|
||||||
|
theme: UserTheme,
|
||||||
|
): CustomColorGroup {
|
||||||
|
let hash = 0;
|
||||||
|
member.userId.split("").forEach((char) => {
|
||||||
|
hash = char.charCodeAt(0) + ((hash << 5) - hash);
|
||||||
|
});
|
||||||
|
let color = "#";
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const value = (hash >> (i * 8)) & 0xff;
|
||||||
|
color += value.toString(16).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return themeFromSourceColor(argbFromHex(theme.color), [
|
||||||
|
{ value: argbFromHex(color), name: "member", blend: true },
|
||||||
|
]).customColors.find((c) => c.color.name === "member")!;
|
||||||
|
}
|
||||||
357
src/lib/chat/events/MatrixEvent.svelte
Normal file
357
src/lib/chat/events/MatrixEvent.svelte
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type {
|
||||||
|
EventTimeline,
|
||||||
|
MatrixEvent,
|
||||||
|
MatrixEventEvent,
|
||||||
|
Relations,
|
||||||
|
RelationsEvent,
|
||||||
|
RoomMember,
|
||||||
|
} from "matrix-js-sdk";
|
||||||
|
import MatrixMessageEvent from "./MatrixMessageEvent.svelte";
|
||||||
|
import { matrixClient, memberColor } from "../chat";
|
||||||
|
import { theme } from "$lib/preferences";
|
||||||
|
import { hexFromArgb } from "@material/material-color-utilities";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
|
import type { Replay } from "$lib/charrecorder/core/types";
|
||||||
|
import CharRecorder from "$lib/charrecorder/CharRecorder.svelte";
|
||||||
|
import type { ReplayPlayer } from "$lib/charrecorder/core/player";
|
||||||
|
import { onDestroy, onMount } from "svelte";
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
let {
|
||||||
|
event,
|
||||||
|
prev,
|
||||||
|
sender,
|
||||||
|
replay: replayPlayer,
|
||||||
|
timeline,
|
||||||
|
}: {
|
||||||
|
event?: MatrixEvent;
|
||||||
|
prev?: MatrixEvent;
|
||||||
|
sender?: RoomMember | null;
|
||||||
|
replay?: Replay | ReplayPlayer;
|
||||||
|
timeline?: EventTimeline;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
let toolbarHover = $state(false);
|
||||||
|
let mainHover = $state(false);
|
||||||
|
|
||||||
|
let hover = $derived(toolbarHover || mainHover);
|
||||||
|
|
||||||
|
let replay: Replay | undefined = $state();
|
||||||
|
|
||||||
|
let reactions: Relations | undefined = $state(
|
||||||
|
timeline && event?.event.event_id
|
||||||
|
? timeline
|
||||||
|
.getTimelineSet()
|
||||||
|
.relations.getChildEventsForEvent(
|
||||||
|
event.event.event_id,
|
||||||
|
"m.annotation",
|
||||||
|
"m.reaction",
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
);
|
||||||
|
let annotations = writable<[string, Set<MatrixEvent>][] | null | undefined>();
|
||||||
|
|
||||||
|
function createRelations() {
|
||||||
|
if (!timeline || !event?.event.event_id) return;
|
||||||
|
reactions?.off("Relations.add" as RelationsEvent.Add, createRelations);
|
||||||
|
reactions?.off(
|
||||||
|
"Relations.remove" as RelationsEvent.Remove,
|
||||||
|
createRelations,
|
||||||
|
);
|
||||||
|
reactions = timeline
|
||||||
|
.getTimelineSet()
|
||||||
|
.relations.getChildEventsForEvent(
|
||||||
|
event.event.event_id,
|
||||||
|
"m.annotation",
|
||||||
|
"m.reaction",
|
||||||
|
);
|
||||||
|
reactions?.on("Relations.add" as RelationsEvent.Add, createRelations);
|
||||||
|
reactions?.on("Relations.remove" as RelationsEvent.Remove, createRelations);
|
||||||
|
reactions?.on(
|
||||||
|
"Relations.redaction" as RelationsEvent.Redaction,
|
||||||
|
createRelations,
|
||||||
|
);
|
||||||
|
annotations.set(
|
||||||
|
reactions?.getSortedAnnotationsByKey()?.filter(([, it]) => it.size > 0),
|
||||||
|
);
|
||||||
|
console.log("create");
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
createRelations();
|
||||||
|
event?.on(
|
||||||
|
"Event.relationsCreated" as MatrixEventEvent.RelationsCreated,
|
||||||
|
createRelations,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
event?.off(
|
||||||
|
"Event.relationsCreated" as MatrixEventEvent.RelationsCreated,
|
||||||
|
createRelations,
|
||||||
|
);
|
||||||
|
reactions?.off("Relations.add" as RelationsEvent.Remove, createRelations);
|
||||||
|
reactions?.off(
|
||||||
|
"Relations.remove" as RelationsEvent.Remove,
|
||||||
|
createRelations,
|
||||||
|
);
|
||||||
|
reactions?.off(
|
||||||
|
"Relations.redaction" as RelationsEvent.Redaction,
|
||||||
|
createRelations,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="event"
|
||||||
|
role="log"
|
||||||
|
onmouseover={() => (mainHover = true)}
|
||||||
|
onfocus={() => (mainHover = true)}
|
||||||
|
onmouseout={() => (mainHover = false)}
|
||||||
|
onblur={() => (mainHover = false)}
|
||||||
|
>
|
||||||
|
{#if event && hover}
|
||||||
|
<div class="backdrop" transition:fade={{ duration: 100 }}></div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if sender && !(prev && prev?.getType() === event?.getType() && prev.sender?.userId === event.sender?.userId)}
|
||||||
|
{@const color = memberColor(sender, $theme)}
|
||||||
|
{@const avatarMxc = sender.getMxcAvatarUrl()}
|
||||||
|
{#if avatarMxc}
|
||||||
|
{@const avatar = $matrixClient.mxcUrlToHttp(avatarMxc, 32, 32)}
|
||||||
|
<img
|
||||||
|
class="avatar"
|
||||||
|
src={avatar}
|
||||||
|
alt={sender.name}
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div
|
||||||
|
class="avatar avatar-placeholder icon"
|
||||||
|
style:background={hexFromArgb(
|
||||||
|
$theme.mode === "dark" ? color.dark.color : color.light.color,
|
||||||
|
)}
|
||||||
|
style:color={hexFromArgb(
|
||||||
|
$theme.mode === "dark" ? color.dark.onColor : color.light.onColor,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
person
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="sender"
|
||||||
|
style:color={hexFromArgb(
|
||||||
|
$theme.mode === "dark" ? color.dark.color : color.light.color,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<strong>{sender.name}</strong>
|
||||||
|
{#if replay || replayPlayer}
|
||||||
|
<div class="dots">
|
||||||
|
{#each new Array(3) as _, i}
|
||||||
|
<div
|
||||||
|
style:animation-delay={i * 0.2 + "s"}
|
||||||
|
style:background={hexFromArgb(
|
||||||
|
$theme.mode === "dark" ? color.dark.color : color.light.color,
|
||||||
|
)}
|
||||||
|
class="dot"
|
||||||
|
></div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{#if event}
|
||||||
|
{#if event.getType() === "m.room.message"}
|
||||||
|
<MatrixMessageEvent {event} bind:replay />
|
||||||
|
{:else}
|
||||||
|
<details>
|
||||||
|
<summary>{event.getType()}</summary>
|
||||||
|
<pre>{JSON.stringify(event.event, null, 2)}</pre>
|
||||||
|
</details>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{#if replayPlayer}
|
||||||
|
<CharRecorder replay={replayPlayer} cursor={true} keys={true} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if event && hover}
|
||||||
|
<div
|
||||||
|
role="toolbar"
|
||||||
|
tabindex="0"
|
||||||
|
class="toolbar"
|
||||||
|
transition:fade={{ duration: 100 }}
|
||||||
|
onmouseover={() => (toolbarHover = true)}
|
||||||
|
onfocus={() => (toolbarHover = true)}
|
||||||
|
onmouseout={() => (toolbarHover = false)}
|
||||||
|
onblur={() => (toolbarHover = false)}
|
||||||
|
>
|
||||||
|
<button class="icon">add_reaction</button>
|
||||||
|
<button class="icon">reply</button>
|
||||||
|
{#if event.event.content?.["m.replay"]}
|
||||||
|
{#if replay}
|
||||||
|
<button class="icon" onclick={() => (replay = undefined)}>stop</button
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
class="icon"
|
||||||
|
onclick={() => (replay = event.event.content?.["m.replay"])}
|
||||||
|
>replay</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
<button class="icon">more_horiz</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if $annotations && $annotations.length > 0}
|
||||||
|
<div class="reactions">
|
||||||
|
{#each $annotations as [reaction, events]}
|
||||||
|
<button class="reaction"
|
||||||
|
>{reaction} <span class="count">{events.size}</span></button
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
details {
|
||||||
|
opacity: 0.5;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
text-wrap: wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: -26px;
|
||||||
|
right: 0;
|
||||||
|
background: var(--md-sys-color-secondary-container);
|
||||||
|
color: var(--md-sys-color-on-secondary-container);
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 16px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: bounce 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sender,
|
||||||
|
.avatar {
|
||||||
|
margin-block: 2px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
grid-area: avatar;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
translate: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.avatar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sender {
|
||||||
|
display: flex;
|
||||||
|
grid-area: sender;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reactions {
|
||||||
|
grid-area: reactions;
|
||||||
|
margin-top: 2px;
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reaction {
|
||||||
|
border: 1px solid var(--md-sys-color-outline);
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
> .count {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.event {
|
||||||
|
display: grid;
|
||||||
|
position: relative;
|
||||||
|
padding-inline: 0.5em;
|
||||||
|
margin-inline: 0.5em;
|
||||||
|
padding-block: 0.25em;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
grid-template-areas:
|
||||||
|
"avatar sender date"
|
||||||
|
"avatar content content"
|
||||||
|
"none reactions reactions";
|
||||||
|
grid-template-columns: 32px 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
grid-area: content;
|
||||||
|
text-wrap: wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reactions,
|
||||||
|
.content,
|
||||||
|
.sender {
|
||||||
|
margin-inline: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0.25;
|
||||||
|
|
||||||
|
background: var(--md-sys-color-surface-variant);
|
||||||
|
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
56
src/lib/chat/events/MatrixMessageEvent.svelte
Normal file
56
src/lib/chat/events/MatrixMessageEvent.svelte
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import CharRecorder from "$lib/charrecorder/CharRecorder.svelte";
|
||||||
|
import type { Replay } from "$lib/charrecorder/core/types";
|
||||||
|
import type { MatrixClient, MatrixEvent } from "matrix-js-sdk";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
|
import { matrixClient } from "../chat";
|
||||||
|
|
||||||
|
let { event, replay = $bindable() }: { event: MatrixEvent; replay?: Replay } =
|
||||||
|
$props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{#if event.event.content?.msgtype === "m.image"}
|
||||||
|
<img
|
||||||
|
src={$matrixClient.mxcUrlToHttp(event.event.content["url"])}
|
||||||
|
alt={event.event.content["body"]}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<span class="content" style:opacity={replay && 0}
|
||||||
|
>{event.event.content?.["body"]}</span
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
{#if replay}
|
||||||
|
<div class="replay" out:fade>
|
||||||
|
<CharRecorder
|
||||||
|
{replay}
|
||||||
|
cursor={true}
|
||||||
|
keys={true}
|
||||||
|
ondone={() => (replay = undefined)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
min-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 16em;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
11
src/lib/learn/stats.ts
Normal file
11
src/lib/learn/stats.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { persistentWritable } from "$lib/storage";
|
||||||
|
|
||||||
|
interface ChordStats {
|
||||||
|
level: number;
|
||||||
|
lastUprank: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const chordStats = persistentWritable<Record<string, ChordStats>>(
|
||||||
|
"chord-stats",
|
||||||
|
{},
|
||||||
|
);
|
||||||
@@ -6,9 +6,14 @@ export interface UserPreferences {
|
|||||||
autoConnect: boolean;
|
autoConnect: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const theme = persistentWritable("user-theme", {
|
export interface UserTheme {
|
||||||
|
color: string;
|
||||||
|
mode: "light" | "dark" | "auto";
|
||||||
|
}
|
||||||
|
|
||||||
|
export const theme = persistentWritable<UserTheme>("user-theme", {
|
||||||
color: "#6D81C7",
|
color: "#6D81C7",
|
||||||
mode: "dark" as "light" | "dark" | "auto",
|
mode: "dark",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const userPreferences = persistentWritable<UserPreferences>(
|
export const userPreferences = persistentWritable<UserPreferences>(
|
||||||
|
|||||||
@@ -56,3 +56,9 @@
|
|||||||
{@render children()}
|
{@render children()}
|
||||||
</main>
|
</main>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
main {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1 +1,184 @@
|
|||||||
<h2>WIP</h2>
|
<script lang="ts">
|
||||||
|
import { browser } from "$app/environment";
|
||||||
|
import { onDestroy, onMount, setContext } from "svelte";
|
||||||
|
import type {
|
||||||
|
IndexedDBStore,
|
||||||
|
IndexedDBCryptoStore,
|
||||||
|
LoginResponse,
|
||||||
|
} from "matrix-js-sdk";
|
||||||
|
import MatrixTimeline from "$lib/chat/MatrixTimeline.svelte";
|
||||||
|
import { matrixClient, currentRoomId } from "$lib/chat/chat";
|
||||||
|
import MatrixRooms from "$lib/chat/MatrixRooms.svelte";
|
||||||
|
import MatrixRoomMembers from "$lib/chat/MatrixRoomMembers.svelte";
|
||||||
|
|
||||||
|
let loggedIn = $state(false);
|
||||||
|
let ready = $state(false);
|
||||||
|
|
||||||
|
let store: IndexedDBStore;
|
||||||
|
let cryptoStore: IndexedDBCryptoStore;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if (!browser) return;
|
||||||
|
const { createClient, IndexedDBStore, IndexedDBCryptoStore } = await import(
|
||||||
|
"matrix-js-sdk"
|
||||||
|
);
|
||||||
|
|
||||||
|
const storedLogin = getStoredLogin();
|
||||||
|
|
||||||
|
store = new IndexedDBStore({
|
||||||
|
dbName: "matrix",
|
||||||
|
indexedDB: window.indexedDB,
|
||||||
|
});
|
||||||
|
cryptoStore = new IndexedDBCryptoStore(window.indexedDB, "matrix-crypto");
|
||||||
|
|
||||||
|
$matrixClient = createClient({
|
||||||
|
baseUrl: import.meta.env.VITE_MATRIX_URL,
|
||||||
|
userId: storedLogin?.user_id,
|
||||||
|
accessToken: storedLogin?.access_token,
|
||||||
|
timelineSupport: true,
|
||||||
|
store,
|
||||||
|
cryptoStore,
|
||||||
|
});
|
||||||
|
|
||||||
|
const loginToken = new URLSearchParams(window.location.search).get(
|
||||||
|
"loginToken",
|
||||||
|
);
|
||||||
|
if (loginToken) {
|
||||||
|
await handleLogin(await $matrixClient.loginWithToken(loginToken));
|
||||||
|
window.history.replaceState({}, document.title, window.location.pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
await postLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function passwordLogin(event: SubmitEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
const form = event.target as HTMLFormElement;
|
||||||
|
const username = (form.elements.namedItem("username") as HTMLInputElement)
|
||||||
|
.value;
|
||||||
|
const password = (form.elements.namedItem("password") as HTMLInputElement)
|
||||||
|
.value;
|
||||||
|
|
||||||
|
await handleLogin(
|
||||||
|
await $matrixClient.loginWithPassword(username, password),
|
||||||
|
);
|
||||||
|
await postLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleLogin(response: LoginResponse) {
|
||||||
|
localStorage.setItem("matrix-login", JSON.stringify(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postLogin() {
|
||||||
|
loggedIn = $matrixClient.isLoggedIn();
|
||||||
|
|
||||||
|
if (loggedIn) {
|
||||||
|
await store.startup();
|
||||||
|
await cryptoStore.startup();
|
||||||
|
await $matrixClient.startClient();
|
||||||
|
$matrixClient.once("sync", function (state, prevState, res) {
|
||||||
|
ready = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStoredLogin(): LoginResponse | undefined {
|
||||||
|
try {
|
||||||
|
return JSON.parse(localStorage.getItem("matrix-login")!);
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if ($matrixClient) {
|
||||||
|
$matrixClient.stopClient();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $matrixClient && loggedIn}
|
||||||
|
{#if ready}
|
||||||
|
<div class="chat">
|
||||||
|
<div class="rooms">
|
||||||
|
<button
|
||||||
|
onclick={() => {
|
||||||
|
$matrixClient.logout(true);
|
||||||
|
$matrixClient.clearStores();
|
||||||
|
localStorage.removeItem("matrix-login");
|
||||||
|
window.location.reload();
|
||||||
|
}}>logout</button
|
||||||
|
>
|
||||||
|
<MatrixRooms rooms={$matrixClient.getRooms()} />
|
||||||
|
</div>
|
||||||
|
{#if $currentRoomId}
|
||||||
|
{@const room = $matrixClient.getRoom($currentRoomId)}
|
||||||
|
{#key room}
|
||||||
|
{#if room}
|
||||||
|
<div class="timeline">
|
||||||
|
<MatrixTimeline timeline={room.getLiveTimeline()} />
|
||||||
|
</div>
|
||||||
|
<div class="members">
|
||||||
|
<MatrixRoomMembers members={room.getJoinedMembers()} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/key}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{:else if $matrixClient}
|
||||||
|
{#await $matrixClient.loginFlows() then flows}
|
||||||
|
{#each flows.flows as flow}
|
||||||
|
{#if flow.type === "m.login.sso"}
|
||||||
|
<a
|
||||||
|
href={$matrixClient.getSsoLoginUrl(`${window.location.origin}/chat/`)}
|
||||||
|
>
|
||||||
|
{#each flow.identity_providers as idp}
|
||||||
|
{#if idp.icon}
|
||||||
|
<img src={$matrixClient.mxcUrlToHttp(idp.icon)} alt={idp.name} />
|
||||||
|
{:else}
|
||||||
|
{idp.name}
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</a>
|
||||||
|
{:else if flow.type === "m.login.password"}
|
||||||
|
<form onsubmit={passwordLogin}>
|
||||||
|
<input name="username" type="text" placeholder="Username" />
|
||||||
|
<input name="password" type="password" placeholder="Password" />
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.chat {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> *:not(:last-child) {
|
||||||
|
border-right: 1px solid var(--md-sys-color-outline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.room {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members {
|
||||||
|
width: 200px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -262,9 +262,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{#each $items.slice(page * $pageSize - (page === 0 ? 0 : 1), (page + 1) * $pageSize - 1) as [chord] (JSON.stringify(chord?.id))}
|
{#each $items.slice(page * $pageSize - (page === 0 ? 0 : 1), (page + 1) * $pageSize - 1) as [chord] (JSON.stringify(chord?.id))}
|
||||||
{#if chord}
|
{#if chord}
|
||||||
<tr>
|
<ChordEdit {chord} onduplicate={() => (page = 0)} />
|
||||||
<ChordEdit {chord} onduplicate={() => (page = 0)} />
|
|
||||||
</tr>
|
|
||||||
{/if}
|
{/if}
|
||||||
{/each}</tbody
|
{/each}</tbody
|
||||||
>
|
>
|
||||||
@@ -397,7 +395,7 @@
|
|||||||
|
|
||||||
table {
|
table {
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
overflow: hidden;
|
overflow-y: hidden;
|
||||||
transition: all 1s ease;
|
transition: all 1s ease;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -89,33 +89,37 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<th>
|
<tr>
|
||||||
<ChordActionEdit {chord} onsubmit={() => {}} />
|
<th>
|
||||||
</th>
|
<ChordActionEdit {chord} onsubmit={() => {}} />
|
||||||
<td>
|
</th>
|
||||||
<ChordPhraseEdit {chord} />
|
<td class="phrase-edit">
|
||||||
</td>
|
<ChordPhraseEdit {chord} />
|
||||||
<td class="table-buttons">
|
</td>
|
||||||
{#if !chord.deleted}
|
<td>
|
||||||
<button transition:slide class="icon compact" onclick={remove}
|
<div class="table-buttons">
|
||||||
>delete</button
|
{#if !chord.deleted}
|
||||||
>
|
<button transition:slide class="icon compact" onclick={remove}
|
||||||
{:else}
|
>delete</button
|
||||||
<button transition:slide class="icon compact" onclick={restore}
|
>
|
||||||
>restore_from_trash</button
|
{:else}
|
||||||
>
|
<button transition:slide class="icon compact" onclick={restore}
|
||||||
{/if}
|
>restore_from_trash</button
|
||||||
<button disabled={chord.deleted} class="icon compact" onclick={duplicate}
|
>
|
||||||
>content_copy</button
|
{/if}
|
||||||
>
|
<button disabled={chord.deleted} class="icon compact" onclick={duplicate}
|
||||||
<button
|
>content_copy</button
|
||||||
class="icon compact"
|
>
|
||||||
class:disabled={chord.isApplied}
|
<button
|
||||||
onclick={restore}>undo</button
|
class="icon compact"
|
||||||
>
|
class:disabled={chord.isApplied}
|
||||||
<div class="separator"></div>
|
onclick={restore}>undo</button
|
||||||
<button class="icon compact" onclick={share}>share</button>
|
>
|
||||||
</td>
|
<div class="separator"></div>
|
||||||
|
<button class="icon compact" onclick={share}>share</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.separator {
|
.separator {
|
||||||
@@ -132,17 +136,29 @@
|
|||||||
transition: opacity 75ms ease;
|
transition: opacity 75ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
.phrase-edit {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-buttons {
|
.table-buttons {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 75ms ease;
|
transition: opacity 75ms ease;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
transform: translate(100%, -50%);
|
||||||
|
background: var(--md-sys-color-surface-variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(tr):focus-within > .table-buttons,
|
.icon {
|
||||||
:global(tr):hover > .table-buttons {
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover .table-buttons {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
21
src/routes/(app)/config/chords/ChordEditActions.svelte
Normal file
21
src/routes/(app)/config/chords/ChordEditActions.svelte
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<div class="table-buttons">
|
||||||
|
{#if !chord.deleted}
|
||||||
|
<button transition:slide class="icon compact" onclick={remove}
|
||||||
|
>delete</button
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<button transition:slide class="icon compact" onclick={restore}
|
||||||
|
>restore_from_trash</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
<button disabled={chord.deleted} class="icon compact" onclick={duplicate}
|
||||||
|
>content_copy</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="icon compact"
|
||||||
|
class:disabled={chord.isApplied}
|
||||||
|
onclick={restore}>undo</button
|
||||||
|
>
|
||||||
|
<div class="separator"></div>
|
||||||
|
<button class="icon compact" onclick={share}>share</button>
|
||||||
|
</div>
|
||||||
0
src/routes/(app)/learn/Pick.svelte
Normal file
0
src/routes/(app)/learn/Pick.svelte
Normal file
0
src/routes/(app)/stats/+page.svelte
Normal file
0
src/routes/(app)/stats/+page.svelte
Normal file
@@ -1,12 +0,0 @@
|
|||||||
RewriteEngine On
|
|
||||||
|
|
||||||
# force https
|
|
||||||
RewriteCond %{HTTPS} off
|
|
||||||
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
|
|
||||||
|
|
||||||
# https://kit.svelte.dev/docs/single-page-apps#apache
|
|
||||||
# RewriteBase /
|
|
||||||
# RewriteRule ^index\.html$ - [L]
|
|
||||||
# RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
# RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
# RewriteRule . /index.html [QSA,L]
|
|
||||||
@@ -22,6 +22,7 @@ process.env["VITE_BUGS_URL"] = bugs.url;
|
|||||||
process.env["VITE_LEARN_URL"] = "https://www.iq-eq.io/";
|
process.env["VITE_LEARN_URL"] = "https://www.iq-eq.io/";
|
||||||
process.env["VITE_LATEST_FIRMWARE"] = "1.1.4";
|
process.env["VITE_LATEST_FIRMWARE"] = "1.1.4";
|
||||||
process.env["VITE_STORE_URL"] = "https://www.charachorder.com/";
|
process.env["VITE_STORE_URL"] = "https://www.charachorder.com/";
|
||||||
|
process.env["VITE_MATRIX_URL"] = "https://charachorder.io/";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
@@ -32,6 +33,9 @@ export default defineConfig({
|
|||||||
external: isTauri ? [/virtual:pwa.*/] : [],
|
external: isTauri ? [/virtual:pwa.*/] : [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
define: {
|
||||||
|
global: "window",
|
||||||
|
},
|
||||||
envPrefix: ["TAURI_", "VITE_"],
|
envPrefix: ["TAURI_", "VITE_"],
|
||||||
plugins: [
|
plugins: [
|
||||||
ViteYaml(),
|
ViteYaml(),
|
||||||
@@ -42,6 +46,7 @@ export default defineConfig({
|
|||||||
SvelteKitPWA({
|
SvelteKitPWA({
|
||||||
kit: {
|
kit: {
|
||||||
trailingSlash: "always",
|
trailingSlash: "always",
|
||||||
|
adapterFallback: "404.html",
|
||||||
},
|
},
|
||||||
scope: "/",
|
scope: "/",
|
||||||
base: "/",
|
base: "/",
|
||||||
@@ -52,7 +57,7 @@ export default defineConfig({
|
|||||||
"client/**/*.{js,map,css,ico,woff2,csv,png,webp,svg,webmanifest}",
|
"client/**/*.{js,map,css,ico,woff2,csv,png,webp,svg,webmanifest}",
|
||||||
"prerendered/**/*.html",
|
"prerendered/**/*.html",
|
||||||
],
|
],
|
||||||
ignoreURLParametersMatching: [/^import$/],
|
ignoreURLParametersMatching: [/^import|redirectUrl|loginToken$/],
|
||||||
},
|
},
|
||||||
manifest: {
|
manifest: {
|
||||||
name: "CharaChorder Device Manager",
|
name: "CharaChorder Device Manager",
|
||||||
|
|||||||
Reference in New Issue
Block a user