From e20967d0f2e8468b3e216b182bebe42a0692106a Mon Sep 17 00:00:00 2001 From: Puyodead1 Date: Wed, 26 Jun 2024 11:39:44 -0400 Subject: [PATCH] implement new message list fetch more is currently broken --- package.json | 2 +- pnpm-lock.yaml | 205 ++++++++++++++------- src/components/Avatar.tsx | 1 + src/components/messaging/MessageAuthor.tsx | 1 - src/components/messaging/MessageList.tsx | 137 +++++++------- src/stores/MessageStore.ts | 3 +- src/stores/objects/Channel.ts | 5 +- 7 files changed, 213 insertions(+), 141 deletions(-) diff --git a/package.json b/package.json index bc2835e..6b9c53e 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "react-dom": "^18.2.0", "react-fps-stats": "^0.3.1", "react-hook-form": "^7.51.3", - "react-infinite-scroll-component": "^6.1.0", "react-loading-skeleton": "^3.4.0", "react-markdown": "^9.0.1", "react-measure": "^2.5.2", @@ -71,6 +70,7 @@ "reoverlay": "^1.0.3", "styled-components": "5.3.11", "use-resize-observer": "^9.1.0", + "virtua": "^0.33.1", "yup": "^1.4.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7f3556..3baac56 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,9 +149,6 @@ dependencies: react-hook-form: specifier: ^7.51.3 version: 7.51.3(react@18.2.0) - react-infinite-scroll-component: - specifier: ^6.1.0 - version: 6.1.0(react@18.2.0) react-loading-skeleton: specifier: ^3.4.0 version: 3.4.0(react@18.2.0) @@ -206,6 +203,9 @@ dependencies: use-resize-observer: specifier: ^9.1.0 version: 9.1.0(react-dom@18.2.0)(react@18.2.0) + virtua: + specifier: ^0.33.1 + version: 0.33.1(react-dom@18.2.0)(react@18.2.0) yup: specifier: ^1.4.0 version: 1.4.0 @@ -5504,7 +5504,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 get-intrinsic: 1.2.4 is-string: 1.0.7 dev: true @@ -5520,7 +5520,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-array-method-boxes-properly: 1.0.0 is-string: 1.0.7 dev: true @@ -5531,7 +5531,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 dev: true @@ -5542,7 +5542,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true @@ -5552,7 +5552,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true @@ -5562,7 +5562,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-array-method-boxes-properly: 1.0.0 is-string: 1.0.7 dev: true @@ -5572,7 +5572,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 dev: true @@ -5584,7 +5584,7 @@ packages: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 @@ -6838,6 +6838,33 @@ packages: whatwg-mimetype: 2.3.0 whatwg-url: 8.7.0 + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + /dayjs@1.11.10: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} dev: false @@ -7233,16 +7260,20 @@ packages: escape-html: 1.0.3 dev: false - /es-abstract@1.22.4: - resolution: {integrity: sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==} + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 available-typed-arrays: 1.0.7 call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 es-define-property: 1.0.0 es-errors: 1.3.0 + es-object-atoms: 1.0.0 es-set-tostringtag: 2.0.3 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 @@ -7253,10 +7284,11 @@ packages: has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 is-callable: 1.2.7 + is-data-view: 1.0.1 is-negative-zero: 2.0.3 is-regex: 1.1.4 is-shared-array-buffer: 1.0.3 @@ -7267,17 +7299,17 @@ packages: object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.0 + safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.2 typed-array-byte-length: 1.0.1 typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.5 + typed-array-length: 1.0.6 unbox-primitive: 1.0.2 - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true /es-array-method-boxes-properly@1.0.0: @@ -7303,7 +7335,7 @@ packages: asynciterator.prototype: 1.0.0 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 es-set-tostringtag: 2.0.3 function-bind: 1.1.2 @@ -7314,26 +7346,33 @@ packages: has-symbols: 1.0.3 internal-slot: 1.0.7 iterator.prototype: 1.1.2 - safe-array-concat: 1.1.0 + safe-array-concat: 1.1.2 dev: true /es-module-lexer@1.4.1: resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} dev: true + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + /es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: @@ -7721,7 +7760,7 @@ packages: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) - hasown: 2.0.1 + hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 minimatch: 3.1.2 @@ -7775,7 +7814,7 @@ packages: emoji-regex: 9.2.2 es-iterator-helpers: 1.0.17 eslint: 8.57.0 - hasown: 2.0.1 + hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.2 @@ -8440,7 +8479,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 functions-have-names: 1.2.3 dev: true @@ -8464,7 +8503,7 @@ packages: function-bind: 1.1.2 has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 dev: true /get-node-dimensions@1.2.1: @@ -8646,6 +8685,13 @@ packages: dependencies: function-bind: 1.1.2 + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + /hast-util-parse-selector@2.2.5: resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} dev: false @@ -9015,7 +9061,7 @@ packages: engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 - hasown: 2.0.1 + hasown: 2.0.2 side-channel: 1.0.5 dev: true @@ -9116,6 +9162,13 @@ packages: dependencies: hasown: 2.0.1 + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + dev: true + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} @@ -9312,7 +9365,7 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true /is-typedarray@1.0.0: @@ -11523,7 +11576,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 dev: true /object.fromentries@2.0.7: @@ -11532,7 +11585,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 dev: true /object.getownpropertydescriptors@2.1.7: @@ -11542,8 +11595,8 @@ packages: array.prototype.reduce: 1.0.6 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 - safe-array-concat: 1.1.0 + es-abstract: 1.23.3 + safe-array-concat: 1.1.2 dev: true /object.groupby@1.0.2: @@ -11552,7 +11605,7 @@ packages: array.prototype.filter: 1.0.3 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 dev: true @@ -11560,7 +11613,7 @@ packages: resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} dependencies: define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 dev: true /object.values@1.1.7: @@ -11569,7 +11622,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 dev: true /obuf@1.1.2: @@ -12999,15 +13052,6 @@ packages: react: 18.2.0 dev: false - /react-infinite-scroll-component@6.1.0(react@18.2.0): - resolution: {integrity: sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==} - peerDependencies: - react: '>=16.0.0' - dependencies: - react: 18.2.0 - throttle-debounce: 2.3.0 - dev: false - /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -13523,7 +13567,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 globalthis: 1.0.3 @@ -13826,8 +13870,8 @@ packages: dependencies: queue-microtask: 1.2.3 - /safe-array-concat@1.1.0: - resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} dependencies: call-bind: 1.0.7 @@ -14323,7 +14367,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 get-intrinsic: 1.2.4 has-symbols: 1.0.3 internal-slot: 1.0.7 @@ -14332,29 +14376,31 @@ packages: side-channel: 1.0.5 dev: true - /string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-object-atoms: 1.0.0 dev: true /string_decoder@1.1.1: @@ -14745,11 +14791,6 @@ packages: /throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} - /throttle-debounce@2.3.0: - resolution: {integrity: sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==} - engines: {node: '>=8'} - dev: false - /through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} dependencies: @@ -14991,8 +15032,8 @@ packages: is-typed-array: 1.1.13 dev: true - /typed-array-length@1.0.5: - resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -15187,7 +15228,7 @@ packages: resolution: {integrity: sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==} dependencies: define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 has-symbols: 1.0.3 object.getownpropertydescriptors: 2.1.7 dev: true @@ -15236,6 +15277,30 @@ packages: vfile-message: 4.0.2 dev: false + /virtua@0.33.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-xOzF5J+4KN12w1k7rNbocxjLYrWmGP2gXEDXqcHz7zWkf2vrCrsP/N3M/m3RhME/f/bNc5X22cvpIPqQeOP2MA==} + peerDependencies: + react: '>=16.14.0' + react-dom: '>=16.14.0' + solid-js: '>=1.0' + svelte: '>=4.0' + vue: '>=3.2' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vue: + optional: true + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /vite-plugin-chunk-split@0.5.0(vite@5.2.7): resolution: {integrity: sha512-pasNKLhH+ICjoCF6HoKKvgmZ1LEPSCIKAa8Lz0ZpMyQC9bLmCLT7UxgKMULewsc9SUw89OX0udsGiIQCtr8wLA==} peerDependencies: @@ -15640,7 +15705,7 @@ packages: isarray: 2.0.5 which-boxed-primitive: 1.0.2 which-collection: 1.0.1 - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true /which-collection@1.0.1: @@ -15656,8 +15721,8 @@ packages: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} dev: false - /which-typed-array@1.1.14: - resolution: {integrity: sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==} + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 6905145..fd51001 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -12,6 +12,7 @@ const Wrapper = styled(Container)<{ size: number; hasClick?: boolean }>` background-color: transparent; display: flex; flex-direction: column; + user-select: none; `; interface Props { diff --git a/src/components/messaging/MessageAuthor.tsx b/src/components/messaging/MessageAuthor.tsx index d63fc2d..3b8a3cf 100644 --- a/src/components/messaging/MessageAuthor.tsx +++ b/src/components/messaging/MessageAuthor.tsx @@ -13,7 +13,6 @@ import FloatingTrigger from "../floating/FloatingTrigger"; const Container = styled.div` font-size: 16px; font-weight: var(--font-weight-medium); - user-select: none; &:hover { text-decoration: underline; diff --git a/src/components/messaging/MessageList.tsx b/src/components/messaging/MessageList.tsx index 94d39b0..f7d8961 100644 --- a/src/components/messaging/MessageList.tsx +++ b/src/components/messaging/MessageList.tsx @@ -1,9 +1,9 @@ import { observer } from "mobx-react-lite"; -import React from "react"; -import InfiniteScroll from "react-infinite-scroll-component"; -import PulseLoader from "react-spinners/PulseLoader"; +import React, { useEffect, useRef, useState } from "react"; +import { PulseLoader } from "react-spinners"; import styled from "styled-components"; import useResizeObserver from "use-resize-observer"; +import { VList, VListHandle } from "virtua"; import useLogger from "../../hooks/useLogger"; import { useAppStore } from "../../stores/AppStore"; import { MessageGroup as MessageGroupType } from "../../stores/MessageStore"; @@ -17,34 +17,73 @@ export const MessageAreaWidthContext = React.createContext(0); export const MESSAGE_AREA_PADDING = 82; const Container = styled.div` - flex: 1 1 auto; - overflow-y: auto; display: flex; - flex-direction: column-reverse; + flex: 1; `; const EndMessageContainer = styled.div` margin: 16px 16px 0 16px; `; +const Spacer = styled.div` + height: 20px; +`; + interface Props { guild: Guild; channel: Channel; + before?: string; } /** * Main component for rendering the messages list of a channel */ -function MessageList({ guild, channel }: Props) { +function MessageList({ guild, channel, before }: Props) { const app = useAppStore(); const logger = useLogger("MessageList.tsx"); - const [hasMore, setHasMore] = React.useState(true); - const [canView, setCanView] = React.useState(false); + const [hasMore, setHasMore] = useState(true); + const [canView, setCanView] = useState(false); + const [loading, setLoading] = useState(false); const messageGroups = channel.messages.groups; - const ref = React.useRef(null); - const { width } = useResizeObserver({ ref }); + const wrapperRef = useRef(null); + const { width } = useResizeObserver({ ref: wrapperRef }); + const ref = useRef(null); - React.useEffect(() => { + useEffect(() => { + ref.current?.scrollToIndex( + messageGroups.reduce((p, c) => p + c.messages.length, 0) + + 1 /* +1 to account for the spacer that adds some margin to the bottom */, + ); + }, [messageGroups]); + + const fetchMore = React.useCallback(() => { + setLoading(true); + if (!channel.messages.count) { + logger.warn("channel has no messages, aborting!"); + setLoading(false); + return; + } + // get last group + const lastGroup = messageGroups[messageGroups.length - 1]; + if (!lastGroup) { + logger.warn("No last group found, aborting fetchMore"); + setLoading(false); + return; + } + // ignore queued messages + if ("status" in lastGroup.messages[0]) return; + // get first message in the group to use as before + const before = lastGroup.messages[0].id; + logger.debug(`Fetching 50 messages before ${before} for channel ${channel.id}`); + channel.getMessages(app, false, 50, before).then((r) => { + if (r < 50) { + setHasMore(false); + } + }); + setLoading(false); + }, [channel, messageGroups]); + + useEffect(() => { const permission = Permissions.getPermission(app.account!.id, guild, channel); const hasPermission = permission.has("READ_MESSAGE_HISTORY"); setCanView(hasPermission); @@ -55,7 +94,7 @@ function MessageList({ guild, channel }: Props) { } if (guild && channel && channel.messages.count === 0) { - channel.getMessages(app, true).then((r) => { + channel.getMessages(app, true, 50, before).then((r) => { if (r < 50) { setHasMore(false); } @@ -69,29 +108,6 @@ function MessageList({ guild, channel }: Props) { }; }, [guild, channel]); - const fetchMore = React.useCallback(() => { - if (!channel.messages.count) { - logger.warn("channel has no messages, aborting!"); - return; - } - // get last group - const lastGroup = messageGroups[messageGroups.length - 1]; - if (!lastGroup) { - logger.warn("No last group found, aborting fetchMore"); - return; - } - // ignore queued messages - if ("status" in lastGroup.messages[0]) return; - // get first message in the group to use as before - const before = lastGroup.messages[0].id; - logger.debug(`Fetching 50 messages before ${before} for channel ${channel.id}`); - channel.getMessages(app, false, 50, before).then((r) => { - if (r < 50) { - setHasMore(false); - } - }); - }, [channel, messageGroups]); - const renderGroup = React.useCallback( (group: MessageGroupType) => ( @@ -101,20 +117,25 @@ function MessageList({ guild, channel }: Props) { return ( - + {canView ? ( - + {((messageGroups.length === 0 && !loading) || (!loading && !hasMore)) && ( + +

Welcome to #{channel.name}!

+

+ This is the start of the #{channel.name} channel. +

+ +
+ )} + {loading && ( - } - // FIXME: seems to be broken in react-infinite-scroll-component when using inverse - scrollThreshold={0.5} - scrollableTarget="scrollable-div" - endMessage={ - -

Welcome to #{channel.name}!

-

- This is the start of the #{channel.name} channel. -

- -
- } - > - {messageGroups.map((group) => renderGroup(group))} -
+ )} + {messageGroups.map((group, index) => renderGroup(group))} + + ) : (