From 8380c8e091b025f1857eedaeabab5121a1f1bca5 Mon Sep 17 00:00:00 2001 From: danidfra Date: Thu, 3 Oct 2024 15:30:51 -0300 Subject: [PATCH 01/40] Update: Add NIP-05 warning to Post Composer --- src/features/compose/components/compose-form.tsx | 5 +++-- src/features/compose/editor/index.tsx | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 79946dcf6..ea0a5341d 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -17,7 +17,7 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest import { Button, HStack, Stack } from 'soapbox/components/ui'; import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container'; import { ComposeEditor } from 'soapbox/features/ui/util/async-components'; -import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, useOwnAccount, usePrevious } from 'soapbox/hooks'; import QuotedStatusContainer from '../containers/quoted-status-container'; import ReplyIndicatorContainer from '../containers/reply-indicator-container'; @@ -69,6 +69,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const intl = useIntl(); const dispatch = useAppDispatch(); const { configuration } = useInstance(); + const { account } = useOwnAccount(); const compose = useCompose(id); const showSearch = useAppSelector((state) => state.search.submitted && !state.search.hidden); @@ -108,7 +109,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const isEmpty = !(fulltext.trim() || anyMedia); const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading; const shouldAutoFocus = autoFocus && !showSearch; - const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars; + const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars && account?.source?.nostr?.nip05 !== undefined; const getClickableArea = () => { return clickableAreaRef ? clickableAreaRef.current : formRef.current; diff --git a/src/features/compose/editor/index.tsx b/src/features/compose/editor/index.tsx index eeb6c1f02..024268de2 100644 --- a/src/features/compose/editor/index.tsx +++ b/src/features/compose/editor/index.tsx @@ -18,7 +18,8 @@ import { $createParagraphNode, $createTextNode, $getRoot, type LexicalEditor } f import React, { useMemo, useState } from 'react'; import { FormattedMessage } from 'react-intl'; -import { useAppDispatch } from 'soapbox/hooks'; +import Warning from 'soapbox/features/compose/components/warning'; +import { useAppDispatch, useOwnAccount, useSettingsNotifications } from 'soapbox/hooks'; import { useNodes } from './nodes'; import AutosuggestPlugin from './plugins/autosuggest-plugin'; @@ -84,6 +85,8 @@ const ComposeEditor = React.forwardRef(({ }, ref) => { const dispatch = useAppDispatch(); const nodes = useNodes(); + const { account } = useOwnAccount(); + const settingsNotifications = useSettingsNotifications(); const [suggestionsHidden, setSuggestionsHidden] = useState(true); @@ -132,6 +135,9 @@ const ComposeEditor = React.forwardRef(({ return ( + { account?.source?.nostr?.nip05 === undefined ? + Identity\' before continuing.'} /> : } /> : null + }
Date: Thu, 3 Oct 2024 15:32:45 -0300 Subject: [PATCH 02/40] Add new translation messages --- src/locales/en.json | 2 ++ src/locales/pt-BR.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/locales/en.json b/src/locales/en.json index 0accc3497..f85730a24 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -501,6 +501,8 @@ "compose_form.spoiler_placeholder": "Write your warning here (optional)", "compose_form.spoiler_remove": "Remove sensitive", "compose_form.spoiler_title": "Sensitive content", + "compose_form.warning": "Warning: To post, you need a valid username. Please configure your username in 'Settings > Identity' before continuing.", + "compose_form.warning_waiting": "Warning: To post, you need a valid username. Your username request is pending validation. Please wait until your username is validated.", "compose_group.share_to_followers": "Share with my followers", "confirmation_modal.cancel": "Cancel", "confirmations.admin.deactivate_user.confirm": "Deactivate @{name}", diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index 8a0a94928..1064debe8 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -478,6 +478,8 @@ "compose_form.markdown.marked": "Markdown do post ativado", "compose_form.markdown.unmarked": "Markdown do post desativado", "compose_form.message": "Mensagem", + "compose_form.warning": "Aviso: Para postar, é necessário ter um nome de usuário válido. Por favor, configure seu nome de usuário em 'Configurações > Identidade', antes de continuar.", + "compose_form.warning_waiting": "Aviso: Para postar, é necessário ter um nome de usuário válido. Sua solicitação de nome de usuário está pendente de validação. Por favor, aguarde até que seu usuário seja validado.", "compose_form.placeholder": "No que você está pensando?", "compose_form.poll.add_option": "Adicionar uma resposta", "compose_form.poll.duration": "Duração da enquete", From adc783761c71b87970a59146a6d107fb352046e3 Mon Sep 17 00:00:00 2001 From: danidfra Date: Thu, 3 Oct 2024 15:34:44 -0300 Subject: [PATCH 03/40] Add export for useSettingsNotifications hook --- src/hooks/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 8d3b7a510..abfbd726c 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -21,4 +21,5 @@ export { useRegistrationStatus } from './useRegistrationStatus'; export { useSettings } from './useSettings'; export { useSoapboxConfig } from './useSoapboxConfig'; export { useSystemTheme } from './useSystemTheme'; -export { useTheme } from './useTheme'; \ No newline at end of file +export { useTheme } from './useTheme'; +export { useSettingsNotifications } from './useSettingsNotifications'; \ No newline at end of file From 105394cea1f57a41420c642f45910fab29c44c5c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 13 Oct 2024 18:08:43 -0500 Subject: [PATCH 04/40] Upgrade tabler to 3.19 --- package.json | 2 +- src/components/status-action-bar.tsx | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 4574cd63d..3e137b1f1 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@sentry/types": "^8.34.0", "@soapbox.pub/wasmboy": "^0.8.0", "@soapbox/weblock": "npm:@jsr/soapbox__weblock", - "@tabler/icons": "^3.1.0", + "@tabler/icons": "^3.19.0", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.10", diff --git a/src/components/status-action-bar.tsx b/src/components/status-action-bar.tsx index ad6376cac..5223214f7 100644 --- a/src/components/status-action-bar.tsx +++ b/src/components/status-action-bar.tsx @@ -741,7 +741,7 @@ const StatusActionBar: React.FC = ({ > Date: Sun, 13 Oct 2024 18:14:25 -0500 Subject: [PATCH 05/40] Upgrade Tailwind and scss deps --- package.json | 14 +- src/styles/components/status.scss | 4 +- yarn.lock | 430 +++++++++++++++++++----------- 3 files changed, 289 insertions(+), 159 deletions(-) diff --git a/package.json b/package.json index 3e137b1f1..7b697fc82 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@soapbox/weblock": "npm:@jsr/soapbox__weblock", "@tabler/icons": "^3.19.0", "@tailwindcss/aspect-ratio": "^0.4.2", - "@tailwindcss/forms": "^0.5.7", - "@tailwindcss/typography": "^0.5.10", + "@tailwindcss/forms": "^0.5.9", + "@tailwindcss/typography": "^0.5.15", "@tanstack/react-query": "^5.0.0", "@types/escape-html": "^1.0.1", "@types/http-link-header": "^1.0.3", @@ -149,7 +149,7 @@ "redux": "^5.0.0", "redux-thunk": "^3.1.0", "reselect": "^5.0.0", - "sass": "^1.69.5", + "sass": "^1.79.5", "semver": "^7.3.8", "stringz": "^2.0.0", "twemoji": "https://github.com/twitter/twemoji#v14.0.2", @@ -181,15 +181,15 @@ "eslint-plugin-promise": "^6.0.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-tailwindcss": "^3.13.0", + "eslint-plugin-tailwindcss": "^3.17.5", "fake-indexeddb": "^5.0.0", "husky": "^9.0.0", "jsdom": "^24.0.0", "lint-staged": ">=10", "rollup-plugin-visualizer": "^5.9.2", - "stylelint": "^16.0.2", - "stylelint-config-standard-scss": "^12.0.0", - "tailwindcss": "^3.4.0", + "stylelint": "^16.10.0", + "stylelint-config-standard-scss": "^13.1.0", + "tailwindcss": "^3.4.13", "vite-plugin-checker": "^0.8.0", "vite-plugin-pwa": "^0.20.5", "vitest": "^2.1.1" diff --git a/src/styles/components/status.scss b/src/styles/components/status.scss index b5a0571c1..3c7863062 100644 --- a/src/styles/components/status.scss +++ b/src/styles/components/status.scss @@ -1,5 +1,7 @@ .status { @apply min-h-[54px] cursor-default; + opacity: 1; + animation: fade 150ms linear; @supports (-ms-overflow-style: -ms-autohiding-scrollbar) { // Add margin to avoid Edge auto-hiding scrollbar appearing over content. @@ -11,8 +13,6 @@ 0% { opacity: 0; } 100% { opacity: 1; } } - opacity: 1; - animation: fade 150ms linear; } [column-type='filled'] .status__wrapper, diff --git a/yarn.lock b/yarn.lock index 16e5a4587..82b4aa172 100644 --- a/yarn.lock +++ b/yarn.lock @@ -984,25 +984,30 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" -"@csstools/css-parser-algorithms@^2.3.2": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.4.0.tgz#88c7b62b8e00c391b24c585f9db5a0b62ed665b0" - integrity sha512-/PPLr2g5PAUCKAPEbfyk6/baZA+WJHQtUhPkoCQMpyRE8I0lXrG1QFRN8e5s3ZYxM8d/g5BZc6lH3s8Op7/VEg== +"@csstools/css-parser-algorithms@^3.0.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.2.tgz#be03c710a60b34f95ea62e332c9ca0c2674f6d5f" + integrity sha512-6tC/MnlEvs5suR4Ahef4YlBccJDHZuxGsAlxXmybWjZ5jPxlzLSMlRZ9mVHSRvlD+CmtE7+hJ+UQbfXrws/rUQ== -"@csstools/css-tokenizer@^2.2.1": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.2.2.tgz#bcd85cef4468c356833b21e96d38b940c9760605" - integrity sha512-wCDUe/MAw7npAHFLyW3QjSyLA66S5QFaV1jIXlNQvdJ8RzXDSgALa49eWcUO6P55ARQaz0TsDdAgdRgkXFYY8g== +"@csstools/css-tokenizer@^3.0.1": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.2.tgz#1c1d7298f6a7b3db94afe53d949b9a7d6a8ebc57" + integrity sha512-IuTRcD53WHsXPCZ6W7ubfGqReTJ9Ra0yRRFmXYP/Re8hFYYfoIYIK4080X5luslVLWimhIeFq0hj09urVMQzTw== -"@csstools/media-query-list-parser@^2.1.5": - version "2.1.6" - resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.6.tgz#e4e9a8a35be7a066836389b03ec19e584bc61af3" - integrity sha512-R6AKl9vaU0It7D7TR2lQn0pre5aQfdeqHRePlaRCY8rHL3l9eVlNRpsEVDKFi/zAjzv68CxH2M5kqbhPFPKjvw== +"@csstools/media-query-list-parser@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz#9474e08e6d7767cf68c56bf1581b59d203360cb0" + integrity sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw== -"@csstools/selector-specificity@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247" - integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g== +"@csstools/selector-specificity@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz#7dfccb9df5499e627e7bfdbb4021a06813a45dba" + integrity sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ== + +"@dual-bundle/import-meta-resolve@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#519c1549b0e147759e7825701ecffd25e5819f7b" + integrity sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg== "@emoji-mart/data@^1.1.2": version "1.1.2" @@ -1860,6 +1865,89 @@ websocket-ts "^2.1.5" zod "^3.23.4" +"@parcel/watcher-android-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" + integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg== + +"@parcel/watcher-darwin-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34" + integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA== + +"@parcel/watcher-darwin-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020" + integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg== + +"@parcel/watcher-freebsd-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8" + integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w== + +"@parcel/watcher-linux-arm-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d" + integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA== + +"@parcel/watcher-linux-arm64-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7" + integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA== + +"@parcel/watcher-linux-arm64-musl@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635" + integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA== + +"@parcel/watcher-linux-x64-glibc@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39" + integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg== + +"@parcel/watcher-linux-x64-musl@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16" + integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ== + +"@parcel/watcher-win32-arm64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc" + integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg== + +"@parcel/watcher-win32-ia32@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7" + integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw== + +"@parcel/watcher-win32-x64@2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf" + integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A== + +"@parcel/watcher@^2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8" + integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.4.1" + "@parcel/watcher-darwin-arm64" "2.4.1" + "@parcel/watcher-darwin-x64" "2.4.1" + "@parcel/watcher-freebsd-x64" "2.4.1" + "@parcel/watcher-linux-arm-glibc" "2.4.1" + "@parcel/watcher-linux-arm64-glibc" "2.4.1" + "@parcel/watcher-linux-arm64-musl" "2.4.1" + "@parcel/watcher-linux-x64-glibc" "2.4.1" + "@parcel/watcher-linux-x64-musl" "2.4.1" + "@parcel/watcher-win32-arm64" "2.4.1" + "@parcel/watcher-win32-ia32" "2.4.1" + "@parcel/watcher-win32-x64" "2.4.1" + "@popperjs/core@^2.9.2": version "2.11.5" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" @@ -2293,17 +2381,17 @@ resolved "https://registry.yarnpkg.com/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz#9ffd52fee8e3c8b20623ff0dcb29e5c21fb0a9ba" integrity sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ== -"@tailwindcss/forms@^0.5.7": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821" - integrity sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw== +"@tailwindcss/forms@^0.5.9": + version "0.5.9" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.9.tgz#b495c12575d6eae5865b2cbd9876b26d89f16f61" + integrity sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg== dependencies: mini-svg-data-uri "^1.2.3" -"@tailwindcss/typography@^0.5.10": - version "0.5.10" - resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.10.tgz#2abde4c6d5c797ab49cf47610830a301de4c1e0a" - integrity sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw== +"@tailwindcss/typography@^0.5.15": + version "0.5.15" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.15.tgz#007ab9870c86082a1c76e5b3feda9392c7c8d648" + integrity sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA== dependencies: lodash.castarray "^4.4.0" lodash.isplainobject "^4.0.6" @@ -3149,11 +3237,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3455,12 +3538,12 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.21.10, browserslist@^4.21.4, browserslist@^4.23.1: version "4.24.0" @@ -3604,7 +3687,7 @@ check-error@^2.1.1: resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.1, chokidar@^3.5.3: +chokidar@^3.5.1, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -3619,6 +3702,13 @@ check-error@^2.1.1: optionalDependencies: fsevents "~2.3.2" +chokidar@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41" + integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA== + dependencies: + readdirp "^4.0.1" + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -3830,10 +3920,10 @@ css-declaration-sorter@^6.3.1: resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== -css-functions-list@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.1.tgz#2eb205d8ce9f9ce74c5c1d7490b66b77c45ce3ea" - integrity sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ== +css-functions-list@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.3.tgz#95652b0c24f0f59b291a9fc386041a19d4f40dbe" + integrity sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA== css-select@^4.2.1: version "4.3.0" @@ -3857,7 +3947,7 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" -css-tree@^2.2.1, css-tree@^2.3.1: +css-tree@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== @@ -3865,6 +3955,14 @@ css-tree@^2.2.1, css-tree@^2.3.1: mdn-data "2.0.30" source-map-js "^1.0.1" +css-tree@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.0.0.tgz#079c7b87e465a28cedbc826502f9a227213db0f3" + integrity sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw== + dependencies: + mdn-data "2.10.0" + source-map-js "^1.0.1" + css-tree@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.2.1.tgz#36115d382d60afd271e377f9c5f67d02bd48c032" @@ -3973,7 +4071,7 @@ date-fns@^2.0.1, date-fns@^2.24.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -4067,6 +4165,11 @@ detect-it@^4.0.1: resolved "https://registry.yarnpkg.com/detect-it/-/detect-it-4.0.1.tgz#3f8de6b8330f5086270571251bedf10aec049e18" integrity sha512-dg5YBTJYvogK1+dA2mBUDKzOWfYZtHVba89SyZUhc4+e3i2tzgjANFg5lDRCd3UOtRcw00vUTMK8LELcMdicug== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + detect-passive-events@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-passive-events/-/detect-passive-events-2.0.3.tgz#1f75ebf80660a66c615d8be23c3241cdda6977e0" @@ -4617,10 +4720,10 @@ eslint-plugin-react@^7.33.2: semver "^6.3.1" string.prototype.matchall "^4.0.8" -eslint-plugin-tailwindcss@^3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-3.13.0.tgz#60858cdc8888da2deda5f200c1b163b211c4b8fa" - integrity sha512-Fcep4KDRLWaK3KmkQbdyKHG0P4GdXFmXdDaweTIPcgOP60OOuWFbh1++dufRT28Q4zpKTKaHwTsXPJ4O/EjU2Q== +eslint-plugin-tailwindcss@^3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-3.17.5.tgz#6bf9403e77a5f3f930fb3444a3e22b29cd0fee07" + integrity sha512-8Mi7p7dm+mO1dHgRHHFdPu4RDTBk69Cn4P0B40vRQR+MrguUpwmKwhZy1kqYe3Km8/4nb+cyrCF+5SodOEmaow== dependencies: fast-glob "^3.2.5" postcss "^8.4.4" @@ -4824,12 +4927,12 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-entry-cache@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-7.0.2.tgz#2d61bb70ba89b9548e3035b7c9173fe91deafff0" - integrity sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g== +file-entry-cache@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-9.1.0.tgz#2e66ad98ce93f49aed1b178c57b0b5741591e075" + integrity sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg== dependencies: - flat-cache "^3.2.0" + flat-cache "^5.0.0" filelist@^1.0.4: version "1.0.4" @@ -4838,10 +4941,10 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -4858,7 +4961,7 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4, flat-cache@^3.2.0: +flat-cache@^3.0.4: version "3.2.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== @@ -4867,10 +4970,18 @@ flat-cache@^3.0.4, flat-cache@^3.2.0: keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== +flat-cache@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-5.0.0.tgz#26c4da7b0f288b408bb2b506b2cb66c240ddf062" + integrity sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ== + dependencies: + flatted "^3.3.1" + keyv "^4.5.4" + +flatted@^3.2.9, flatted@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.15.0: version "1.15.1" @@ -5353,11 +5464,16 @@ idb@^7.0.1: resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== -ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.0: +ignore@^5.2.0, ignore@^5.2.4: version "5.3.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== +ignore@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-6.0.2.tgz#77cccb72a55796af1b6d2f9eb14fa326d24f4283" + integrity sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -5749,10 +5865,10 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jiti@^1.19.1: - version "1.21.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" - integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +jiti@^1.21.0: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== js-base64@^3.6.0: version "3.7.5" @@ -5939,7 +6055,7 @@ keycode@^2.1.7: resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04" integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ= -keyv@^4.0.0, keyv@^4.5.3: +keyv@^4.0.0, keyv@^4.5.3, keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== @@ -5956,6 +6072,11 @@ known-css-properties@^0.29.0: resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.29.0.tgz#e8ba024fb03886f23cb882e806929f32d814158f" integrity sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ== +known-css-properties@^0.34.0: + version "0.34.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.34.0.tgz#ccd7e9f4388302231b3f174a8b1d5b1f7b576cea" + integrity sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ== + kysely@^0.27.3: version "0.27.3" resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.27.3.tgz#6cc6c757040500b43c4ac596cdbb12be400ee276" @@ -6241,10 +6362,15 @@ mdn-data@2.0.30: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== -meow@^12.1.1: - version "12.1.1" - resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6" - integrity sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw== +mdn-data@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.10.0.tgz#701da407f8fbc7a42aa0ba0c149ec897daef8986" + integrity sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw== + +meow@^13.2.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f" + integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA== merge-stream@^2.0.0: version "2.0.0" @@ -6256,12 +6382,12 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.49.0: @@ -6389,6 +6515,11 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + node-html-parser@^5.3.3: version "5.4.2" resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.4.2.tgz#93e004038c17af80226c942336990a0eaed8136a" @@ -6947,15 +7078,15 @@ postcss-reduce-transforms@^6.0.0: dependencies: postcss-value-parser "^4.2.0" -postcss-resolve-nested-selector@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= +postcss-resolve-nested-selector@^0.1.1, postcss-resolve-nested-selector@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz#3d84dec809f34de020372c41b039956966896686" + integrity sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw== -postcss-safe-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz#6273d4e5149e286db5a45bc6cf6eafcad464014a" - integrity sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg== +postcss-safe-parser@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz#36e4f7e608111a0ca940fd9712ce034718c40ec0" + integrity sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A== postcss-scss@^4.0.9: version "4.0.9" @@ -6970,10 +7101,10 @@ postcss-selector-parser@6.0.10: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.13, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" - integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== +postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.13, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -6998,7 +7129,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.23, postcss@^8.4.29, postcss@^8.4.32, postcss@^8.4.4, postcss@^8.4.43, postcss@^8.4.47: +postcss@^8.4.23, postcss@^8.4.29, postcss@^8.4.4, postcss@^8.4.43, postcss@^8.4.47: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== @@ -7441,6 +7572,11 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +readdirp@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" + integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -7732,12 +7868,13 @@ safe-regex-test@^1.0.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@^1.69.5: - version "1.69.5" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.5.tgz#23e18d1c757a35f2e52cc81871060b9ad653dfde" - integrity sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ== +sass@^1.79.5: + version "1.79.5" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.79.5.tgz#646c627601cd5f84c64f7b1485b9292a313efae4" + integrity sha512-W1h5kp6bdhqFh2tk3DsI771MoEJjvrSY/2ihJRJS4pjIyfJCw0nTsxqhnrUzaLMOJjFchj8rOvraI/YUVjtx5g== dependencies: - chokidar ">=3.0.0 <4.0.0" + "@parcel/watcher" "^2.4.1" + chokidar "^4.0.0" immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" @@ -8036,13 +8173,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -8101,25 +8231,25 @@ stylelint-config-recommended-scss@^14.0.0: stylelint-config-recommended "^14.0.0" stylelint-scss "^6.0.0" -stylelint-config-recommended@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz#b395c7014838d2aaca1755eebd914d0bb5274994" - integrity sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ== +stylelint-config-recommended@^14.0.0, stylelint-config-recommended@^14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz#d25e86409aaf79ee6c6085c2c14b33c7e23c90c6" + integrity sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg== -stylelint-config-standard-scss@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard-scss/-/stylelint-config-standard-scss-12.0.0.tgz#fbd7881080eb3585ca63c1ce6791a5ff42c94489" - integrity sha512-ATh3EcEOLZq0iwlFaBdIsSavrla0lNtJ7mO7hdE7DgVT6imozRggFSqd4cFcjzVnOLKv/uJT63MmqA1acIflbw== +stylelint-config-standard-scss@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard-scss/-/stylelint-config-standard-scss-13.1.0.tgz#2be36ca13087325a42c1f26df8267808667cc886" + integrity sha512-Eo5w7/XvwGHWkeGLtdm2FZLOMYoZl1omP2/jgFCXyl2x5yNz7/8vv4Tj6slHvMSSUNTaGoam/GAZ0ZhukvalfA== dependencies: stylelint-config-recommended-scss "^14.0.0" - stylelint-config-standard "^35.0.0" + stylelint-config-standard "^36.0.0" -stylelint-config-standard@^35.0.0: - version "35.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-35.0.0.tgz#f4574670affb72b6c99d2b5ca5ad010a11ee8d19" - integrity sha512-JyQrNZk2BZwVKFauGGxW2U6RuhIfQ4XoHHo+rBzMHcAkLnwI/knpszwXjzxiMgSfcxbZBckM7Vq4LHoANTR85g== +stylelint-config-standard@^36.0.0: + version "36.0.1" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-36.0.1.tgz#727cbb2a1ef3e210f5ce8329cde531129f156609" + integrity sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw== dependencies: - stylelint-config-recommended "^14.0.0" + stylelint-config-recommended "^14.0.1" stylelint-scss@^6.0.0: version "6.0.0" @@ -8132,48 +8262,48 @@ stylelint-scss@^6.0.0: postcss-selector-parser "^6.0.13" postcss-value-parser "^4.2.0" -stylelint@^16.0.2: - version "16.0.2" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.0.2.tgz#fe49e9ff7460d9ae98501e9116884238432ea31e" - integrity sha512-SxA/rg3VWxdoHZlW0nmVueWO1E7TAKW4W6mmA3iTxxEF9bIeQdFZu2oiBlQYyNe1pGnOamOqo2XYnI7cs5Bgow== +stylelint@^16.10.0: + version "16.10.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.10.0.tgz#452b42a5d82f2ad910954eb2ba2b3a2ec583cd75" + integrity sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ== dependencies: - "@csstools/css-parser-algorithms" "^2.3.2" - "@csstools/css-tokenizer" "^2.2.1" - "@csstools/media-query-list-parser" "^2.1.5" - "@csstools/selector-specificity" "^3.0.0" + "@csstools/css-parser-algorithms" "^3.0.1" + "@csstools/css-tokenizer" "^3.0.1" + "@csstools/media-query-list-parser" "^3.0.1" + "@csstools/selector-specificity" "^4.0.0" + "@dual-bundle/import-meta-resolve" "^4.1.0" balanced-match "^2.0.0" colord "^2.9.3" cosmiconfig "^9.0.0" - css-functions-list "^3.2.1" - css-tree "^2.3.1" - debug "^4.3.4" + css-functions-list "^3.2.3" + css-tree "^3.0.0" + debug "^4.3.7" fast-glob "^3.3.2" fastest-levenshtein "^1.0.16" - file-entry-cache "^7.0.2" + file-entry-cache "^9.1.0" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" html-tags "^3.3.1" - ignore "^5.3.0" + ignore "^6.0.2" imurmurhash "^0.1.4" is-plain-object "^5.0.0" - known-css-properties "^0.29.0" + known-css-properties "^0.34.0" mathml-tag-names "^2.1.3" - meow "^12.1.1" - micromatch "^4.0.5" + meow "^13.2.0" + micromatch "^4.0.8" normalize-path "^3.0.0" - picocolors "^1.0.0" - postcss "^8.4.32" - postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^7.0.0" - postcss-selector-parser "^6.0.13" + picocolors "^1.0.1" + postcss "^8.4.47" + postcss-resolve-nested-selector "^0.1.6" + postcss-safe-parser "^7.0.1" + postcss-selector-parser "^6.1.2" postcss-value-parser "^4.2.0" resolve-from "^5.0.0" string-width "^4.2.3" - strip-ansi "^7.1.0" - supports-hyperlinks "^3.0.0" + supports-hyperlinks "^3.1.0" svg-tags "^1.0.0" - table "^6.8.1" + table "^6.8.2" write-file-atomic "^5.0.1" sucrase@^3.32.0: @@ -8210,10 +8340,10 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz#c711352a5c89070779b4dad54c05a2f14b15c94b" - integrity sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA== +supports-hyperlinks@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz#b56150ff0173baacc15f21956450b61f2b18d3ac" + integrity sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" @@ -8255,10 +8385,10 @@ tabbable@^6.0.1: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.0.1.tgz#427a09b13c83ae41eed3e88abb76a4af28bde1a6" integrity sha512-SYJSIgeyXW7EuX1ytdneO5e8jip42oHWg9xl/o3oTYhmXusZVgiA+VlPvjIN+kHii9v90AmzTZEBcsEvuAY+TA== -table@^6.8.1: - version "6.8.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" - integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== +table@^6.8.2: + version "6.8.2" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" + integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== dependencies: ajv "^8.0.1" lodash.truncate "^4.4.2" @@ -8266,10 +8396,10 @@ table@^6.8.1: string-width "^4.2.3" strip-ansi "^6.0.1" -tailwindcss@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.0.tgz#045a9c474e6885ebd0436354e611a76af1c76839" - integrity sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA== +tailwindcss@^3.4.13: + version "3.4.13" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.13.tgz#3d11e5510660f99df4f1bfb2d78434666cb8f831" + integrity sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" @@ -8279,7 +8409,7 @@ tailwindcss@^3.4.0: fast-glob "^3.3.0" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.19.1" + jiti "^1.21.0" lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" From ad6e1bc099b5840801f51d1aae3e7932033e528c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 13 Oct 2024 18:28:26 -0500 Subject: [PATCH 06/40] Upgrade react-query --- package.json | 2 +- src/api/hooks/instance/useInstanceV1.ts | 7 +++++-- src/api/hooks/instance/useInstanceV2.ts | 7 +++++-- src/features/admin/announcements.tsx | 2 +- src/hooks/useInstance.ts | 6 ++++-- yarn.lock | 18 +++++++++--------- 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 7b697fc82..825cb97b9 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", - "@tanstack/react-query": "^5.0.0", + "@tanstack/react-query": "^5.59.13", "@types/escape-html": "^1.0.1", "@types/http-link-header": "^1.0.3", "@types/leaflet": "^1.8.0", diff --git a/src/api/hooks/instance/useInstanceV1.ts b/src/api/hooks/instance/useInstanceV1.ts index 2ca494287..c1e802156 100644 --- a/src/api/hooks/instance/useInstanceV1.ts +++ b/src/api/hooks/instance/useInstanceV1.ts @@ -1,11 +1,14 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { useApi } from 'soapbox/hooks'; import { InstanceV1, instanceV1Schema } from 'soapbox/schemas/instance'; -interface Opts extends Pick, 'enabled' | 'retryOnMount' | 'staleTime'> { +interface Opts { /** The base URL of the instance. */ baseUrl?: string; + enabled?: boolean; + retryOnMount?: boolean; + staleTime?: number; } /** Get the Instance for the current backend. */ diff --git a/src/api/hooks/instance/useInstanceV2.ts b/src/api/hooks/instance/useInstanceV2.ts index d3376063a..25b1de014 100644 --- a/src/api/hooks/instance/useInstanceV2.ts +++ b/src/api/hooks/instance/useInstanceV2.ts @@ -1,11 +1,14 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { useApi } from 'soapbox/hooks'; import { InstanceV2, instanceV2Schema } from 'soapbox/schemas/instance'; -interface Opts extends Pick, 'enabled' | 'retryOnMount' | 'staleTime'> { +interface Opts { /** The base URL of the instance. */ baseUrl?: string; + enabled?: boolean; + retryOnMount?: boolean; + staleTime?: number; } /** Get the Instance for the current backend. */ diff --git a/src/features/admin/announcements.tsx b/src/features/admin/announcements.tsx index 18f0e6cb4..7af9d28c6 100644 --- a/src/features/admin/announcements.tsx +++ b/src/features/admin/announcements.tsx @@ -115,7 +115,7 @@ const Announcements: React.FC = () => { emptyMessage={emptyMessage} itemClassName='py-3 first:pt-0 last:pb-0' isLoading={isLoading} - showLoading={isLoading && !announcements?.length} + showLoading={isLoading} > {announcements!.map((announcement) => ( diff --git a/src/hooks/useInstance.ts b/src/hooks/useInstance.ts index eb7bed170..46557f587 100644 --- a/src/hooks/useInstance.ts +++ b/src/hooks/useInstance.ts @@ -1,4 +1,3 @@ -import { UseQueryOptions } from '@tanstack/react-query'; import { useEffect, useMemo } from 'react'; import { HTTPError } from 'soapbox/api/HTTPError'; @@ -8,9 +7,12 @@ import { instanceV2Schema, upgradeInstance } from 'soapbox/schemas/instance'; import { useAppDispatch } from './useAppDispatch'; -interface Opts extends Pick, 'enabled' | 'retryOnMount' | 'staleTime'> { +interface Opts { /** The base URL of the instance. */ baseUrl?: string; + enabled?: boolean; + retryOnMount?: boolean; + staleTime?: number; } /** Get the Instance for the current backend. */ diff --git a/yarn.lock b/yarn.lock index 82b4aa172..02e4db89a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2398,17 +2398,17 @@ lodash.merge "^4.6.2" postcss-selector-parser "6.0.10" -"@tanstack/query-core@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.0.0.tgz#b37a50bb3a4f54336b6131db00b72cd29e79b480" - integrity sha512-Y1BpiA6BblJd/UlVqxEVeAG7IACn568YJuTTItAiecBI7En+33g780kg+/8lhgl+BzcUPN7o+NjBrSRGJoemyQ== +"@tanstack/query-core@5.59.13": + version "5.59.13" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.13.tgz#8c962980af174bbd446b7e9b9999f7432897df80" + integrity sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ== -"@tanstack/react-query@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.0.0.tgz#707fecb71cf53ae098f682f45520d7b1640bcaa9" - integrity sha512-diQoC8FNBcO5Uf5yuaJlXthTtbO1xM8kzOX+pSBUMT9n/cqQ/u1wJGCtukvhDWA+6j07WmIj4bfqNbd2KOB6jQ== +"@tanstack/react-query@^5.59.13": + version "5.59.13" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.13.tgz#decac9c15ddc29a54dc3520a41a1dcedb1a9596a" + integrity sha512-GB2ELtiH8tL0rcFiM4sWvnXhazt1xRXX/LolMEV12kfEKu58aNA4lQoieslP61PO4vZO9JJMwm+6lqyS0E1HOA== dependencies: - "@tanstack/query-core" "5.0.0" + "@tanstack/query-core" "5.59.13" "@testing-library/dom@^9.0.0": version "9.0.1" From 29bdd54dd19e4c16f445632a1b3dc0bf2a7d73dc Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Oct 2024 11:50:51 -0500 Subject: [PATCH 07/40] Refactor NIP-05 warnings --- .../compose/components/compose-form.tsx | 30 ++--------- .../compose/containers/warning-container.tsx | 51 ++++++++++++++++++- src/features/compose/editor/index.tsx | 8 +-- src/locales/en.json | 5 +- 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 478a6c0db..8b0f7b19a 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -1,8 +1,8 @@ import clsx from 'clsx'; import { CLEAR_EDITOR_COMMAND, TextNode, type LexicalEditor, $getRoot } from 'lexical'; import React, { Suspense, useCallback, useEffect, useRef, useState } from 'react'; -import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { Link, useHistory } from 'react-router-dom'; +import { defineMessages, useIntl } from 'react-intl'; +import { useHistory } from 'react-router-dom'; import { length } from 'stringz'; import { @@ -17,7 +17,7 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest import { Button, HStack, Stack } from 'soapbox/components/ui'; import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container'; import { ComposeEditor } from 'soapbox/features/ui/util/async-components'; -import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, useOwnAccount, usePrevious } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks'; import QuotedStatusContainer from '../containers/quoted-status-container'; import ReplyIndicatorContainer from '../containers/reply-indicator-container'; @@ -39,7 +39,6 @@ import SpoilerInput from './spoiler-input'; import TextCharacterCounter from './text-character-counter'; import UploadForm from './upload-form'; import VisualCharacterCounter from './visual-character-counter'; -import Warning from './warning'; import type { Emoji } from 'soapbox/features/emoji'; @@ -68,13 +67,11 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const history = useHistory(); const intl = useIntl(); const dispatch = useAppDispatch(); - const { account } = useOwnAccount(); const { instance } = useInstance(); const compose = useCompose(id); const showSearch = useAppSelector((state) => state.search.submitted && !state.search.hidden); const maxTootChars = instance.configuration.statuses.max_characters; - const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size); const features = useFeatures(); const { @@ -109,7 +106,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const isEmpty = !(fulltext.trim() || anyMedia); const condensed = shouldCondense && !isDraggedOver && !composeFocused && isEmpty && !isUploading; const shouldAutoFocus = autoFocus && !showSearch; - const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars && account?.source?.nostr?.nip05 !== undefined; + const canSubmit = !!editorRef.current && !isSubmitting && !isUploading && !isChangingUpload && !isEmpty && length(fulltext) <= maxTootChars; const getClickableArea = () => { return clickableAreaRef ? clickableAreaRef.current : formRef.current; @@ -247,25 +244,6 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab return ( - {scheduledStatusCount > 0 && !event && !group && ( - - - - ) }} - />) - } - /> - )} - {!shouldCondense && !event && !group && groupId && } diff --git a/src/features/compose/containers/warning-container.tsx b/src/features/compose/containers/warning-container.tsx index 858404c27..1ecc99359 100644 --- a/src/features/compose/containers/warning-container.tsx +++ b/src/features/compose/containers/warning-container.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; -import { useAppSelector, useCompose } from 'soapbox/hooks'; +import { useAppSelector, useCompose, useOwnAccount, useSettingsNotifications } from 'soapbox/hooks'; import { selectOwnAccount } from 'soapbox/selectors'; import Warning from '../components/warning'; @@ -15,11 +15,60 @@ interface IWarningWrapper { const WarningWrapper: React.FC = ({ composeId }) => { const compose = useCompose(composeId); + const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size); + const { account } = useOwnAccount(); + const settingsNotifications = useSettingsNotifications(); const needsLockWarning = useAppSelector((state) => compose.privacy === 'private' && !selectOwnAccount(state)!.locked); const hashtagWarning = (compose.privacy !== 'public' && compose.privacy !== 'group') && APPROX_HASHTAG_RE.test(compose.text); const directMessageWarning = compose.privacy === 'direct'; + if (scheduledStatusCount > 0) { + return ( + + + + ) }} + />) + } + /> + ); + } + + if (account?.source?.nostr?.nip05 === undefined) { + if (settingsNotifications.has('needsNip05')) { + return ( + + + + ), + }} + /> + ); + } else { + return ( + + ); + } + } + if (needsLockWarning) { return ( (({ }, ref) => { const dispatch = useAppDispatch(); const nodes = useNodes(); - const { account } = useOwnAccount(); - const settingsNotifications = useSettingsNotifications(); const [suggestionsHidden, setSuggestionsHidden] = useState(true); @@ -135,9 +132,6 @@ const ComposeEditor = React.forwardRef(({ return ( - { account?.source?.nostr?.nip05 === undefined ? - Identity\' before continuing.'} /> : } /> : null - }
Identity' before continuing.", - "compose_form.warning_waiting": "Warning: To post, you need a valid username. Your username request is pending validation. Please wait until your username is validated.", "compose_group.share_to_followers": "Share with my followers", "confirmation_modal.cancel": "Cancel", "confirmations.admin.deactivate_user.confirm": "Deactivate @{name}", From 9692b15715e6dbf56ef0aade3227048cbb7f10cf Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Oct 2024 11:57:25 -0500 Subject: [PATCH 08/40] Update nip05 portuguese translation --- src/locales/pt-BR.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index 1064debe8..3176ebb46 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -478,8 +478,9 @@ "compose_form.markdown.marked": "Markdown do post ativado", "compose_form.markdown.unmarked": "Markdown do post desativado", "compose_form.message": "Mensagem", - "compose_form.warning": "Aviso: Para postar, é necessário ter um nome de usuário válido. Por favor, configure seu nome de usuário em 'Configurações > Identidade', antes de continuar.", - "compose_form.warning_waiting": "Aviso: Para postar, é necessário ter um nome de usuário válido. Sua solicitação de nome de usuário está pendente de validação. Por favor, aguarde até que seu usuário seja validado.", + "compose_form.nip05.pending": "Seu pedido de nome de usuário está em revisão.", + "compose_form.nip05.warning": "Você não tem um nome de usuário configurado. {click} para configurá-lo.", + "compose_form.nip05.warning.click": "Clique aqui", "compose_form.placeholder": "No que você está pensando?", "compose_form.poll.add_option": "Adicionar uma resposta", "compose_form.poll.duration": "Duração da enquete", From 0207a299143952507f8d7fdff64e03eb4fdbb1ab Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Oct 2024 15:19:26 -0500 Subject: [PATCH 09/40] ComposeForm: wrap NIP05 text in a component --- .../compose/containers/warning-container.tsx | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/features/compose/containers/warning-container.tsx b/src/features/compose/containers/warning-container.tsx index 1ecc99359..cf80aee6c 100644 --- a/src/features/compose/containers/warning-container.tsx +++ b/src/features/compose/containers/warning-container.tsx @@ -45,28 +45,28 @@ const WarningWrapper: React.FC = ({ composeId }) => { } if (account?.source?.nostr?.nip05 === undefined) { - if (settingsNotifications.has('needsNip05')) { - return ( - - - - ), - }} - /> - ); - } else { - return ( - - ); - } + return ( + + + + ), + }} + /> + ) : ( + + )} + /> + ); } if (needsLockWarning) { From 76a7cd5f0a654947d9b8611ceb19a83cbaca9b0f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Oct 2024 19:25:03 -0500 Subject: [PATCH 10/40] Pull VAPID key from V2 instance --- src/actions/push-notifications/registerer.ts | 12 +++++------- src/features/ui/index.tsx | 7 ++++--- src/utils/auth.ts | 4 ---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/actions/push-notifications/registerer.ts b/src/actions/push-notifications/registerer.ts index 9937fd938..c521534c3 100644 --- a/src/actions/push-notifications/registerer.ts +++ b/src/actions/push-notifications/registerer.ts @@ -1,6 +1,5 @@ import { createPushSubscription, updatePushSubscription } from 'soapbox/actions/push-subscriptions'; import { pushNotificationsSetting } from 'soapbox/settings'; -import { getVapidKey } from 'soapbox/utils/auth'; import { decode as decodeBase64 } from 'soapbox/utils/base64'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; @@ -30,10 +29,10 @@ const getPushSubscription = (registration: ServiceWorkerRegistration) => registration.pushManager.getSubscription() .then(subscription => ({ registration, subscription })); -const subscribe = (registration: ServiceWorkerRegistration, getState: () => RootState) => +const subscribe = (vapidKey: string, registration: ServiceWorkerRegistration) => registration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())), + applicationServerKey: urlBase64ToUint8Array(vapidKey), }); const unsubscribe = ({ registration, subscription }: { @@ -61,10 +60,9 @@ const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) => // eslint-disable-next-line compat/compat const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype); -const register = () => +const register = (vapidKey: string) => (dispatch: AppDispatch, getState: () => RootState) => { const me = getState().me; - const vapidKey = getVapidKey(getState()); dispatch(setBrowserSupport(supportsPushNotifications)); @@ -98,14 +96,14 @@ const register = () => } else { // Something went wrong, try to subscribe again return unsubscribe({ registration, subscription }).then((registration: ServiceWorkerRegistration) => { - return subscribe(registration, getState); + return subscribe(vapidKey, registration); }).then( (subscription: PushSubscription) => dispatch(sendSubscriptionToBackend(subscription, me) as any)); } } // No subscription, try to subscribe - return subscribe(registration, getState) + return subscribe(vapidKey, registration) .then(subscription => dispatch(sendSubscriptionToBackend(subscription, me) as any)); }) .then(({ subscription }: { subscription: PushSubscription | Record }) => { diff --git a/src/features/ui/index.tsx b/src/features/ui/index.tsx index 711f14289..ca65bc492 100644 --- a/src/features/ui/index.tsx +++ b/src/features/ui/index.tsx @@ -34,7 +34,6 @@ import ProfilePage from 'soapbox/pages/profile-page'; import RemoteInstancePage from 'soapbox/pages/remote-instance-page'; import SearchPage from 'soapbox/pages/search-page'; import StatusPage from 'soapbox/pages/status-page'; -import { getVapidKey } from 'soapbox/utils/auth'; import BackgroundShapes from './components/background-shapes'; import FloatingActionButton from './components/floating-action-button'; @@ -388,7 +387,7 @@ const UI: React.FC = ({ children }) => { const { account } = useOwnAccount(); const instance = useInstance(); const features = useFeatures(); - const vapidKey = useAppSelector(state => getVapidKey(state)); + const vapidKey = instance.instance.configuration.vapid.public_key; const dropdownMenuIsOpen = useAppSelector(state => state.dropdown_menu.isOpen); @@ -470,7 +469,9 @@ const UI: React.FC = ({ children }) => { }, [!!account]); useEffect(() => { - dispatch(registerPushNotifications()); + if (vapidKey) { + dispatch(registerPushNotifications(vapidKey)); + } }, [vapidKey]); const shouldHideFAB = (): boolean => { diff --git a/src/utils/auth.ts b/src/utils/auth.ts index b5d9fb120..73757fb80 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -62,8 +62,4 @@ export const getAuthUserUrl = (state: RootState) => { ].filter(url => url)).find(isURL); }; -/** Get the VAPID public key. */ -export const getVapidKey = (state: RootState) => - state.auth.app.vapid_key || state.instance.pleroma.vapid_public_key; - export const getMeUrl = (state: RootState) => selectOwnAccount(state)?.url; \ No newline at end of file From 514f6965b492f194f5b3cfcfb848197ebb2f8a53 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Oct 2024 21:42:37 -0500 Subject: [PATCH 11/40] Guard nip05 with features --- src/features/compose/containers/warning-container.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/features/compose/containers/warning-container.tsx b/src/features/compose/containers/warning-container.tsx index cf80aee6c..8ebfd5f8f 100644 --- a/src/features/compose/containers/warning-container.tsx +++ b/src/features/compose/containers/warning-container.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; -import { useAppSelector, useCompose, useOwnAccount, useSettingsNotifications } from 'soapbox/hooks'; +import { useAppSelector, useCompose, useFeatures, useOwnAccount, useSettingsNotifications } from 'soapbox/hooks'; import { selectOwnAccount } from 'soapbox/selectors'; import Warning from '../components/warning'; @@ -18,6 +18,7 @@ const WarningWrapper: React.FC = ({ composeId }) => { const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size); const { account } = useOwnAccount(); const settingsNotifications = useSettingsNotifications(); + const features = useFeatures(); const needsLockWarning = useAppSelector((state) => compose.privacy === 'private' && !selectOwnAccount(state)!.locked); const hashtagWarning = (compose.privacy !== 'public' && compose.privacy !== 'group') && APPROX_HASHTAG_RE.test(compose.text); @@ -44,7 +45,7 @@ const WarningWrapper: React.FC = ({ composeId }) => { ); } - if (account?.source?.nostr?.nip05 === undefined) { + if (features.nostr && account?.source?.nostr?.nip05 === undefined) { return ( Date: Tue, 15 Oct 2024 15:59:53 -0500 Subject: [PATCH 12/40] Rewrite push registerer --- src/actions/push-notifications/index.ts | 25 --- src/actions/push-notifications/registerer.ts | 207 +++++++------------ src/actions/push-notifications/setter.ts | 39 ---- src/features/ui/index.tsx | 7 +- src/reducers/index.ts | 2 - src/reducers/push-notifications.test.ts | 19 -- src/reducers/push-notifications.ts | 47 ----- src/schemas/web-push.ts | 6 +- 8 files changed, 88 insertions(+), 264 deletions(-) delete mode 100644 src/actions/push-notifications/index.ts delete mode 100644 src/actions/push-notifications/setter.ts delete mode 100644 src/reducers/push-notifications.test.ts delete mode 100644 src/reducers/push-notifications.ts diff --git a/src/actions/push-notifications/index.ts b/src/actions/push-notifications/index.ts deleted file mode 100644 index 69fdf2787..000000000 --- a/src/actions/push-notifications/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { register, saveSettings } from './registerer'; -import { - SET_BROWSER_SUPPORT, - SET_SUBSCRIPTION, - CLEAR_SUBSCRIPTION, - SET_ALERTS, - setAlerts, -} from './setter'; - -import type { AppDispatch } from 'soapbox/store'; - -export { - SET_BROWSER_SUPPORT, - SET_SUBSCRIPTION, - CLEAR_SUBSCRIPTION, - SET_ALERTS, - register, - changeAlerts, -}; - -const changeAlerts = (path: Array, value: any) => - (dispatch: AppDispatch) => { - dispatch(setAlerts(path, value)); - dispatch(saveSettings() as any); - }; diff --git a/src/actions/push-notifications/registerer.ts b/src/actions/push-notifications/registerer.ts index c521534c3..4a7df6a2b 100644 --- a/src/actions/push-notifications/registerer.ts +++ b/src/actions/push-notifications/registerer.ts @@ -1,157 +1,110 @@ -import { createPushSubscription, updatePushSubscription } from 'soapbox/actions/push-subscriptions'; -import { pushNotificationsSetting } from 'soapbox/settings'; +/* eslint-disable compat/compat */ +import { HTTPError } from 'soapbox/api/HTTPError'; +import { MastodonClient } from 'soapbox/api/MastodonClient'; +import { WebPushSubscription, webPushSubscriptionSchema } from 'soapbox/schemas/web-push'; import { decode as decodeBase64 } from 'soapbox/utils/base64'; -import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; - -import type { AppDispatch, RootState } from 'soapbox/store'; -import type { Me } from 'soapbox/types/soapbox'; - -// Taken from https://www.npmjs.com/package/web-push -const urlBase64ToUint8Array = (base64String: string) => { +/** Taken from https://www.npmjs.com/package/web-push */ +function urlBase64ToUint8Array(base64String: string): Uint8Array { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/-/g, '+') .replace(/_/g, '/'); return decodeBase64(base64); -}; +} -const getRegistration = () => { - if (navigator.serviceWorker) { - return navigator.serviceWorker.ready; - } else { - throw 'Your browser does not support Service Workers.'; +async function getBackendSubscription(api: MastodonClient): Promise { + try { + const response = await api.get('/api/v1/push/subscription'); + const data = await response.json(); + return webPushSubscriptionSchema.parse(data); + } catch (e) { + if (e instanceof HTTPError && e.response.status === 404) { + return null; + } else { + throw e; + } } -}; +} -const getPushSubscription = (registration: ServiceWorkerRegistration) => - registration.pushManager.getSubscription() - .then(subscription => ({ registration, subscription })); +async function sendSubscriptionToBackend(api: MastodonClient, subscription: PushSubscription): Promise { + const params = { + subscription: subscription.toJSON(), + }; -const subscribe = (vapidKey: string, registration: ServiceWorkerRegistration) => - registration.pushManager.subscribe({ + const response = await api.post('/api/v1/push/subscription', params); + const data = await response.json(); + + return webPushSubscriptionSchema.parse(data); +} + +async function createSubscription(vapidKey: string): Promise { + const registration = await navigator.serviceWorker.ready; + + return registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidKey), }); +} -const unsubscribe = ({ registration, subscription }: { - registration: ServiceWorkerRegistration; - subscription: PushSubscription | null; -}) => - subscription ? subscription.unsubscribe().then(() => registration) : new Promise(r => r(registration)); +async function getOrCreateSubscription(vapidKey: string): Promise<{ subscription: PushSubscription; created: boolean }> { + const registration = await navigator.serviceWorker.ready; + const subscription = await registration.pushManager.getSubscription(); -const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) => - (dispatch: AppDispatch, getState: () => RootState) => { - const alerts = getState().push_notifications.alerts.toJS(); - const params = { subscription: subscription.toJSON(), data: { alerts } }; - - if (me) { - const data = pushNotificationsSetting.get(me); - if (data) { - params.data = data; - } - } - - return dispatch(createPushSubscription(params)); - }; + if (subscription) { + return { subscription, created: false }; + } else { + const subscription = await createSubscription(vapidKey); + return { subscription, created: true }; + } +} // Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload -// eslint-disable-next-line compat/compat const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype); -const register = (vapidKey: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - const me = getState().me; +export async function registerPushNotifications(api: MastodonClient, vapidKey: string) { + if (!supportsPushNotifications) { + console.warn('Your browser does not support Web Push Notifications.'); + return; + } - dispatch(setBrowserSupport(supportsPushNotifications)); + const { subscription, created } = await getOrCreateSubscription(vapidKey); - if (!supportsPushNotifications) { - console.warn('Your browser does not support Web Push Notifications.'); - return; - } + if (created) { + await sendSubscriptionToBackend(api, subscription); + return; + } - if (!vapidKey) { - console.error('The VAPID public key is not set. You will not be able to receive Web Push Notifications.'); - return; - } + // We have a subscription, check if it is still valid. + const backend = await getBackendSubscription(api); - getRegistration() - .then(getPushSubscription) - // @ts-ignore - .then(({ registration, subscription }: { - registration: ServiceWorkerRegistration; - subscription: PushSubscription | null; - }) => { - if (subscription !== null) { - // We have a subscription, check if it is still valid - const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey!)).toString(); - const subscriptionServerKey = urlBase64ToUint8Array(vapidKey).toString(); - const serverEndpoint = getState().push_notifications.subscription?.endpoint; + // If the VAPID public key did not change and the endpoint corresponds + // to the endpoint saved in the backend, the subscription is valid. + if (backend && subscriptionMatchesBackend(subscription, backend)) { + return; + } else { + // Something went wrong, try to subscribe again. + await subscription.unsubscribe(); + const newSubscription = await createSubscription(vapidKey); + await sendSubscriptionToBackend(api, newSubscription); + } +} - // If the VAPID public key did not change and the endpoint corresponds - // to the endpoint saved in the backend, the subscription is valid - if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint) { - return { subscription }; - } else { - // Something went wrong, try to subscribe again - return unsubscribe({ registration, subscription }).then((registration: ServiceWorkerRegistration) => { - return subscribe(vapidKey, registration); - }).then( - (subscription: PushSubscription) => dispatch(sendSubscriptionToBackend(subscription, me) as any)); - } - } +/** Check if the VAPID key and endpoint of the subscription match the data in the backend. */ +function subscriptionMatchesBackend(subscription: PushSubscription, backend: WebPushSubscription): boolean { + const { applicationServerKey } = subscription.options; - // No subscription, try to subscribe - return subscribe(vapidKey, registration) - .then(subscription => dispatch(sendSubscriptionToBackend(subscription, me) as any)); - }) - .then(({ subscription }: { subscription: PushSubscription | Record }) => { - // If we got a PushSubscription (and not a subscription object from the backend) - // it means that the backend subscription is valid (and was set during hydration) - if (!(subscription instanceof PushSubscription)) { - dispatch(setSubscription(subscription as PushSubscription)); - if (me) { - pushNotificationsSetting.set(me, { alerts: subscription.alerts }); - } - } - }) - .catch(error => { - if (error.code === 20 && error.name === 'AbortError') { - console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.'); - } else if (error.code === 5 && error.name === 'InvalidCharacterError') { - console.error('The VAPID public key seems to be invalid:', vapidKey); - } + if (subscription.endpoint !== backend.endpoint) { + return false; + } - // Clear alerts and hide UI settings - dispatch(clearSubscription()); + if (!applicationServerKey) { + return false; + } - if (me) { - pushNotificationsSetting.remove(me); - } + const backendKeyBytes: Uint8Array = urlBase64ToUint8Array(backend.server_key); + const subscriptionKeyBytes: Uint8Array = new Uint8Array(applicationServerKey); - return getRegistration() - .then(getPushSubscription) - .then(unsubscribe); - }) - .catch(console.warn); - }; - -const saveSettings = () => - (dispatch: AppDispatch, getState: () => RootState) => { - const state = getState().push_notifications; - const alerts = state.alerts; - const data = { alerts }; - const me = getState().me; - - return dispatch(updatePushSubscription({ data })).then(() => { - if (me) { - pushNotificationsSetting.set(me, data); - } - }).catch(console.warn); - }; - -export { - register, - saveSettings, -}; + return backendKeyBytes.toString() === subscriptionKeyBytes.toString(); +} \ No newline at end of file diff --git a/src/actions/push-notifications/setter.ts b/src/actions/push-notifications/setter.ts deleted file mode 100644 index 739427e7e..000000000 --- a/src/actions/push-notifications/setter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { AnyAction } from 'redux'; - -const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT'; -const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION'; -const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION'; -const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS'; - -const setBrowserSupport = (value: boolean) => ({ - type: SET_BROWSER_SUPPORT, - value, -}); - -const setSubscription = (subscription: PushSubscription) => ({ - type: SET_SUBSCRIPTION, - subscription, -}); - -const clearSubscription = () => ({ - type: CLEAR_SUBSCRIPTION, -}); - -const setAlerts = (path: Array, value: any) => - (dispatch: React.Dispatch) => - dispatch({ - type: SET_ALERTS, - path, - value, - }); - -export { - SET_BROWSER_SUPPORT, - SET_SUBSCRIPTION, - CLEAR_SUBSCRIPTION, - SET_ALERTS, - setBrowserSupport, - setSubscription, - clearSubscription, - setAlerts, -}; diff --git a/src/features/ui/index.tsx b/src/features/ui/index.tsx index ca65bc492..38a06855b 100644 --- a/src/features/ui/index.tsx +++ b/src/features/ui/index.tsx @@ -8,7 +8,7 @@ import { fetchCustomEmojis } from 'soapbox/actions/custom-emojis'; import { fetchFilters } from 'soapbox/actions/filters'; import { fetchMarker } from 'soapbox/actions/markers'; import { expandNotifications } from 'soapbox/actions/notifications'; -import { register as registerPushNotifications } from 'soapbox/actions/push-notifications'; +import { registerPushNotifications } from 'soapbox/actions/push-notifications/registerer'; import { fetchScheduledStatuses } from 'soapbox/actions/scheduled-statuses'; import { fetchSuggestionsForTimeline } from 'soapbox/actions/suggestions'; import { expandHomeTimeline } from 'soapbox/actions/timelines'; @@ -16,7 +16,7 @@ import { useUserStream } from 'soapbox/api/hooks'; import SidebarNavigation from 'soapbox/components/sidebar-navigation'; import ThumbNavigation from 'soapbox/components/thumb-navigation'; import { Layout } from 'soapbox/components/ui'; -import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useDraggedFiles, useInstance, useLoggedIn } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useDraggedFiles, useInstance, useLoggedIn, useApi } from 'soapbox/hooks'; import AdminPage from 'soapbox/pages/admin-page'; import ChatsPage from 'soapbox/pages/chats-page'; import DefaultPage from 'soapbox/pages/default-page'; @@ -380,6 +380,7 @@ interface IUI { } const UI: React.FC = ({ children }) => { + const api = useApi(); const history = useHistory(); const dispatch = useAppDispatch(); const node = useRef(null); @@ -470,7 +471,7 @@ const UI: React.FC = ({ children }) => { useEffect(() => { if (vapidKey) { - dispatch(registerPushNotifications(vapidKey)); + registerPushNotifications(api, vapidKey).catch(console.warn); } }, [vapidKey]); diff --git a/src/reducers/index.ts b/src/reducers/index.ts index 4534812dd..925e40d8a 100644 --- a/src/reducers/index.ts +++ b/src/reducers/index.ts @@ -39,7 +39,6 @@ import patron from './patron'; import pending_statuses from './pending-statuses'; import polls from './polls'; import profile_hover_card from './profile-hover-card'; -import push_notifications from './push-notifications'; import relationships from './relationships'; import reports from './reports'; import scheduled_statuses from './scheduled-statuses'; @@ -97,7 +96,6 @@ const reducers = { pending_statuses, polls, profile_hover_card, - push_notifications, relationships, reports, scheduled_statuses, diff --git a/src/reducers/push-notifications.test.ts b/src/reducers/push-notifications.test.ts deleted file mode 100644 index 021cb1771..000000000 --- a/src/reducers/push-notifications.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import reducer from './push-notifications'; - -describe('push_notifications reducer', () => { - it('should return the initial state', () => { - expect(reducer(undefined, {} as any).toJS()).toEqual({ - subscription: null, - alerts: { - follow: true, - follow_request: true, - favourite: true, - reblog: true, - mention: true, - poll: true, - }, - isSubscribed: false, - browserSupport: false, - }); - }); -}); diff --git a/src/reducers/push-notifications.ts b/src/reducers/push-notifications.ts deleted file mode 100644 index a2b8ca51f..000000000 --- a/src/reducers/push-notifications.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Map as ImmutableMap, Record as ImmutableRecord } from 'immutable'; - -import { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION, SET_ALERTS } from '../actions/push-notifications'; - -import type { AnyAction } from 'redux'; - -const SubscriptionRecord = ImmutableRecord({ - id: '', - endpoint: '', -}); - -const ReducerRecord = ImmutableRecord({ - subscription: null as Subscription | null, - alerts: ImmutableMap({ - follow: true, - follow_request: true, - favourite: true, - reblog: true, - mention: true, - poll: true, - }), - isSubscribed: false, - browserSupport: false, -}); - -type Subscription = ReturnType; - -export default function push_subscriptions(state = ReducerRecord(), action: AnyAction) { - switch (action.type) { - case SET_SUBSCRIPTION: - return state - .set('subscription', SubscriptionRecord({ - id: action.subscription.id, - endpoint: action.subscription.endpoint, - })) - .set('alerts', ImmutableMap(action.subscription.alerts)) - .set('isSubscribed', true); - case SET_BROWSER_SUPPORT: - return state.set('browserSupport', action.value); - case CLEAR_SUBSCRIPTION: - return ReducerRecord(); - case SET_ALERTS: - return state.setIn(action.path, action.value); - default: - return state; - } -} diff --git a/src/schemas/web-push.ts b/src/schemas/web-push.ts index 9162f2bfb..f0553dc32 100644 --- a/src/schemas/web-push.ts +++ b/src/schemas/web-push.ts @@ -1,10 +1,12 @@ import { z } from 'zod'; +import { coerceObject } from './utils'; + /** https://docs.joinmastodon.org/entities/WebPushSubscription/ */ const webPushSubscriptionSchema = z.object({ id: z.coerce.string(), endpoint: z.string().url(), - alerts: z.object({ + alerts: coerceObject({ mention: z.boolean().optional(), status: z.boolean().optional(), reblog: z.boolean().optional(), @@ -15,7 +17,7 @@ const webPushSubscriptionSchema = z.object({ update: z.boolean().optional(), 'admin.sign_up': z.boolean().optional(), 'admin.report': z.boolean().optional(), - }).optional(), + }), server_key: z.string(), }); From d0211c8af1c07e5bd1493603132b8fe52969c24f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 15 Oct 2024 16:08:14 -0500 Subject: [PATCH 13/40] Reorganize functions in push registerer so they make logical sense --- src/actions/push-notifications/registerer.ts | 114 +++++++++---------- src/utils/base64.ts | 14 ++- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/actions/push-notifications/registerer.ts b/src/actions/push-notifications/registerer.ts index 4a7df6a2b..f3e4d4a6f 100644 --- a/src/actions/push-notifications/registerer.ts +++ b/src/actions/push-notifications/registerer.ts @@ -2,67 +2,15 @@ import { HTTPError } from 'soapbox/api/HTTPError'; import { MastodonClient } from 'soapbox/api/MastodonClient'; import { WebPushSubscription, webPushSubscriptionSchema } from 'soapbox/schemas/web-push'; -import { decode as decodeBase64 } from 'soapbox/utils/base64'; - -/** Taken from https://www.npmjs.com/package/web-push */ -function urlBase64ToUint8Array(base64String: string): Uint8Array { - const padding = '='.repeat((4 - base64String.length % 4) % 4); - const base64 = (base64String + padding) - .replace(/-/g, '+') - .replace(/_/g, '/'); - - return decodeBase64(base64); -} - -async function getBackendSubscription(api: MastodonClient): Promise { - try { - const response = await api.get('/api/v1/push/subscription'); - const data = await response.json(); - return webPushSubscriptionSchema.parse(data); - } catch (e) { - if (e instanceof HTTPError && e.response.status === 404) { - return null; - } else { - throw e; - } - } -} - -async function sendSubscriptionToBackend(api: MastodonClient, subscription: PushSubscription): Promise { - const params = { - subscription: subscription.toJSON(), - }; - - const response = await api.post('/api/v1/push/subscription', params); - const data = await response.json(); - - return webPushSubscriptionSchema.parse(data); -} - -async function createSubscription(vapidKey: string): Promise { - const registration = await navigator.serviceWorker.ready; - - return registration.pushManager.subscribe({ - userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(vapidKey), - }); -} - -async function getOrCreateSubscription(vapidKey: string): Promise<{ subscription: PushSubscription; created: boolean }> { - const registration = await navigator.serviceWorker.ready; - const subscription = await registration.pushManager.getSubscription(); - - if (subscription) { - return { subscription, created: false }; - } else { - const subscription = await createSubscription(vapidKey); - return { subscription, created: true }; - } -} +import { decodeBase64Url } from 'soapbox/utils/base64'; // Last one checks for payload support: https://web-push-book.gauntface.com/chapter-06/01-non-standards-browsers/#no-payload const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype); +/** + * Register web push notifications. + * This function creates a subscription if one hasn't been created already, and syncronizes it with the backend. + */ export async function registerPushNotifications(api: MastodonClient, vapidKey: string) { if (!supportsPushNotifications) { console.warn('Your browser does not support Web Push Notifications.'); @@ -91,6 +39,56 @@ export async function registerPushNotifications(api: MastodonClient, vapidKey: s } } +/** Get an existing subscription object from the browser if it exists, or ask the browser to create one. */ +async function getOrCreateSubscription(vapidKey: string): Promise<{ subscription: PushSubscription; created: boolean }> { + const registration = await navigator.serviceWorker.ready; + const subscription = await registration.pushManager.getSubscription(); + + if (subscription) { + return { subscription, created: false }; + } else { + const subscription = await createSubscription(vapidKey); + return { subscription, created: true }; + } +} + +/** Request a subscription object from the web browser. */ +async function createSubscription(vapidKey: string): Promise { + const registration = await navigator.serviceWorker.ready; + + return registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: decodeBase64Url(vapidKey), + }); +} + +/** Fetch the API for an existing subscription saved in the backend, if any. */ +async function getBackendSubscription(api: MastodonClient): Promise { + try { + const response = await api.get('/api/v1/push/subscription'); + const data = await response.json(); + return webPushSubscriptionSchema.parse(data); + } catch (e) { + if (e instanceof HTTPError && e.response.status === 404) { + return null; + } else { + throw e; + } + } +} + +/** Publish a new subscription to the backend. */ +async function sendSubscriptionToBackend(api: MastodonClient, subscription: PushSubscription): Promise { + const params = { + subscription: subscription.toJSON(), + }; + + const response = await api.post('/api/v1/push/subscription', params); + const data = await response.json(); + + return webPushSubscriptionSchema.parse(data); +} + /** Check if the VAPID key and endpoint of the subscription match the data in the backend. */ function subscriptionMatchesBackend(subscription: PushSubscription, backend: WebPushSubscription): boolean { const { applicationServerKey } = subscription.options; @@ -103,7 +101,7 @@ function subscriptionMatchesBackend(subscription: PushSubscription, backend: Web return false; } - const backendKeyBytes: Uint8Array = urlBase64ToUint8Array(backend.server_key); + const backendKeyBytes: Uint8Array = decodeBase64Url(backend.server_key); const subscriptionKeyBytes: Uint8Array = new Uint8Array(applicationServerKey); return backendKeyBytes.toString() === subscriptionKeyBytes.toString(); diff --git a/src/utils/base64.ts b/src/utils/base64.ts index c512a6594..ebdf57ae8 100644 --- a/src/utils/base64.ts +++ b/src/utils/base64.ts @@ -1,4 +1,4 @@ -export const decode = (base64: string) => { +export function decodeBase64(base64: string): Uint8Array { const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); @@ -7,4 +7,14 @@ export const decode = (base64: string) => { } return outputArray; -}; +} + +/** Taken from https://www.npmjs.com/package/web-push */ +export function decodeBase64Url(base64String: string): Uint8Array { + const padding = '='.repeat((4 - base64String.length % 4) % 4); + const base64 = (base64String + padding) + .replace(/-/g, '+') + .replace(/_/g, '/'); + + return decodeBase64(base64); +} \ No newline at end of file From f5c9b7d1b251a55600e4441f9f50b02a06291312 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 15 Oct 2024 16:10:15 -0500 Subject: [PATCH 14/40] Fix base64 test --- src/utils/base64.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/utils/base64.test.ts b/src/utils/base64.test.ts index ae0782677..d2537d99b 100644 --- a/src/utils/base64.test.ts +++ b/src/utils/base64.test.ts @@ -1,10 +1,8 @@ -import * as base64 from './base64'; +import { decodeBase64 } from './base64'; -describe('base64', () => { - describe('decode', () => { - it('returns a uint8 array', () => { - const arr = base64.decode('dGVzdA=='); - expect(arr).toEqual(new Uint8Array([116, 101, 115, 116])); - }); +describe('decodeBase64', () => { + it('returns a uint8 array', () => { + const arr = decodeBase64('dGVzdA=='); + expect(arr).toEqual(new Uint8Array([116, 101, 115, 116])); }); }); From 11a0c3cc67bdc92a9bd09411f0f6bdb2c1c2afbf Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 15 Oct 2024 16:21:18 -0500 Subject: [PATCH 15/40] Delete actions/push-subscriptions.ts --- src/actions/push-subscriptions.ts | 86 ------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 src/actions/push-subscriptions.ts diff --git a/src/actions/push-subscriptions.ts b/src/actions/push-subscriptions.ts deleted file mode 100644 index 19b047950..000000000 --- a/src/actions/push-subscriptions.ts +++ /dev/null @@ -1,86 +0,0 @@ -import api from '../api'; - -const PUSH_SUBSCRIPTION_CREATE_REQUEST = 'PUSH_SUBSCRIPTION_CREATE_REQUEST'; -const PUSH_SUBSCRIPTION_CREATE_SUCCESS = 'PUSH_SUBSCRIPTION_CREATE_SUCCESS'; -const PUSH_SUBSCRIPTION_CREATE_FAIL = 'PUSH_SUBSCRIPTION_CREATE_FAIL'; - -const PUSH_SUBSCRIPTION_FETCH_REQUEST = 'PUSH_SUBSCRIPTION_FETCH_REQUEST'; -const PUSH_SUBSCRIPTION_FETCH_SUCCESS = 'PUSH_SUBSCRIPTION_FETCH_SUCCESS'; -const PUSH_SUBSCRIPTION_FETCH_FAIL = 'PUSH_SUBSCRIPTION_FETCH_FAIL'; - -const PUSH_SUBSCRIPTION_UPDATE_REQUEST = 'PUSH_SUBSCRIPTION_UPDATE_REQUEST'; -const PUSH_SUBSCRIPTION_UPDATE_SUCCESS = 'PUSH_SUBSCRIPTION_UPDATE_SUCCESS'; -const PUSH_SUBSCRIPTION_UPDATE_FAIL = 'PUSH_SUBSCRIPTION_UPDATE_FAIL'; - -const PUSH_SUBSCRIPTION_DELETE_REQUEST = 'PUSH_SUBSCRIPTION_DELETE_REQUEST'; -const PUSH_SUBSCRIPTION_DELETE_SUCCESS = 'PUSH_SUBSCRIPTION_DELETE_SUCCESS'; -const PUSH_SUBSCRIPTION_DELETE_FAIL = 'PUSH_SUBSCRIPTION_DELETE_FAIL'; - -import type { AppDispatch, RootState } from 'soapbox/store'; - -interface CreatePushSubscriptionParams { - subscription: PushSubscriptionJSON; - data?: { - alerts?: Record; - policy?: 'all' | 'followed' | 'follower' | 'none'; - }; -} - -const createPushSubscription = (params: CreatePushSubscriptionParams) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: PUSH_SUBSCRIPTION_CREATE_REQUEST, params }); - return api(getState).post('/api/v1/push/subscription', params).then(({ data: subscription }) => - dispatch({ type: PUSH_SUBSCRIPTION_CREATE_SUCCESS, params, subscription }), - ).catch(error => - dispatch({ type: PUSH_SUBSCRIPTION_CREATE_FAIL, params, error }), - ); - }; - -const fetchPushSubscription = () => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: PUSH_SUBSCRIPTION_FETCH_REQUEST }); - return api(getState).get('/api/v1/push/subscription').then(({ data: subscription }) => - dispatch({ type: PUSH_SUBSCRIPTION_FETCH_SUCCESS, subscription }), - ).catch(error => - dispatch({ type: PUSH_SUBSCRIPTION_FETCH_FAIL, error }), - ); - }; - -const updatePushSubscription = (params: Record) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_REQUEST, params }); - return api(getState).put('/api/v1/push/subscription', params).then(({ data: subscription }) => - dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_SUCCESS, params, subscription }), - ).catch(error => - dispatch({ type: PUSH_SUBSCRIPTION_UPDATE_FAIL, params, error }), - ); - }; - -const deletePushSubscription = () => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: PUSH_SUBSCRIPTION_DELETE_REQUEST }); - return api(getState).delete('/api/v1/push/subscription').then(() => - dispatch({ type: PUSH_SUBSCRIPTION_DELETE_SUCCESS }), - ).catch(error => - dispatch({ type: PUSH_SUBSCRIPTION_DELETE_FAIL, error }), - ); - }; - -export { - PUSH_SUBSCRIPTION_CREATE_REQUEST, - PUSH_SUBSCRIPTION_CREATE_SUCCESS, - PUSH_SUBSCRIPTION_CREATE_FAIL, - PUSH_SUBSCRIPTION_FETCH_REQUEST, - PUSH_SUBSCRIPTION_FETCH_SUCCESS, - PUSH_SUBSCRIPTION_FETCH_FAIL, - PUSH_SUBSCRIPTION_UPDATE_REQUEST, - PUSH_SUBSCRIPTION_UPDATE_SUCCESS, - PUSH_SUBSCRIPTION_UPDATE_FAIL, - PUSH_SUBSCRIPTION_DELETE_REQUEST, - PUSH_SUBSCRIPTION_DELETE_SUCCESS, - PUSH_SUBSCRIPTION_DELETE_FAIL, - createPushSubscription, - fetchPushSubscription, - updatePushSubscription, - deletePushSubscription, -}; From 93a464d210f1a080d88258cec6ec1a58a4f5c6ab Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Wed, 16 Oct 2024 20:03:24 -0300 Subject: [PATCH 16/40] refactor: remove irrelevant type assertion --- src/features/ui/components/modals/zaps-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/ui/components/modals/zaps-modal.tsx b/src/features/ui/components/modals/zaps-modal.tsx index dbcf99169..acf15e09e 100644 --- a/src/features/ui/components/modals/zaps-modal.tsx +++ b/src/features/ui/components/modals/zaps-modal.tsx @@ -47,7 +47,7 @@ const ZapsModal: React.FC = ({ onClose, statusId }) => { const handleLoadMore = () => { if (next) { - dispatch(expandZaps(statusId, next!)); + dispatch(expandZaps(statusId, next)); } }; From d6d62e43bba0de51dd8027a0f86dc053d5d99909 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 18 Oct 2024 16:21:56 -0500 Subject: [PATCH 17/40] Swap out twemoji for @twemoji/svg Related: https://gitlab.com/soapbox-pub/soapbox/-/issues/1756 --- package.json | 2 +- vite.config.ts | 2 +- yarn.lock | 49 +++++-------------------------------------------- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index 4574cd63d..24cb8f220 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.10", "@tanstack/react-query": "^5.0.0", + "@twemoji/svg": "^15.0.0", "@types/escape-html": "^1.0.1", "@types/http-link-header": "^1.0.3", "@types/leaflet": "^1.8.0", @@ -152,7 +153,6 @@ "sass": "^1.69.5", "semver": "^7.3.8", "stringz": "^2.0.0", - "twemoji": "https://github.com/twitter/twemoji#v14.0.2", "type-fest": "^4.0.0", "typescript": "^5.6.2", "vite": "^5.4.8", diff --git a/vite.config.ts b/vite.config.ts index 9e3d58410..21836551e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -76,7 +76,7 @@ export default defineConfig(({ command }) => ({ }), viteStaticCopy({ targets: [{ - src: './node_modules/twemoji/assets/svg/*', + src: './node_modules/@twemoji/svg/*', dest: 'packs/emoji/', }, { src: './src/instance', diff --git a/yarn.lock b/yarn.lock index 2c6d98610..f844ef6a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2377,6 +2377,11 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== +"@twemoji/svg@^15.0.0": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@twemoji/svg/-/svg-15.0.0.tgz#0e3828c654726f1848fe11f31ef4e8a75854cc7f" + integrity sha512-ZSPef2B6nBaYnfgdTbAy4jgW95o7pi2xPGwGCU+WMTxo7J6B1lMPTWwSq/wTuiMq+N0khQ90CcvYp1wFoQpo/w== + "@types/aria-query@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" @@ -4916,15 +4921,6 @@ fs-extra@^11.1.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^9.0.1: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -5862,22 +5858,6 @@ json5@^2.1.2, json5@^2.2.0, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922" - integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w== - dependencies: - universalify "^0.1.2" - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -8478,20 +8458,6 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -twemoji-parser@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-14.0.0.tgz#13dabcb6d3a261d9efbf58a1666b182033bf2b62" - integrity sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA== - -"twemoji@https://github.com/twitter/twemoji#v14.0.2": - version "14.0.2" - resolved "https://github.com/twitter/twemoji#7a3dad4a4da30497093dab22eafba135f02308e1" - dependencies: - fs-extra "^8.0.1" - jsonfile "^5.0.0" - twemoji-parser "14.0.0" - universalify "^0.1.2" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -8618,11 +8584,6 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -universalify@^0.1.0, universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - universalify@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" From 79117535893a8f37b1aed70c9ba72f01c60f1028 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 18 Oct 2024 17:07:37 -0500 Subject: [PATCH 18/40] Upgrade to Twemoji 15 --- package.json | 6 +++--- src/features/emoji/data.ts | 2 +- yarn.lock | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 24cb8f220..82f712fe5 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ ], "dependencies": { "@akryum/flexsearch-es": "^0.7.32", - "@emoji-mart/data": "^1.1.2", + "@emoji-mart/data": "^1.2.1", "@floating-ui/react": "^0.26.0", "@fontsource/inter": "^5.0.0", "@fontsource/noto-sans-javanese": "^5.0.16", @@ -103,8 +103,8 @@ "cryptocurrency-icons": "^0.18.1", "cssnano": "^6.0.0", "detect-passive-events": "^2.0.0", - "emoji-datasource": "14.0.0", - "emoji-mart": "^5.5.2", + "emoji-datasource": "15.0.1", + "emoji-mart": "^5.6.0", "escape-html": "^1.0.3", "eslint-plugin-formatjs": "^4.12.2", "exifr": "^7.1.3", diff --git a/src/features/emoji/data.ts b/src/features/emoji/data.ts index 1d840e03f..732fec5ee 100644 --- a/src/features/emoji/data.ts +++ b/src/features/emoji/data.ts @@ -1,4 +1,4 @@ -import data from '@emoji-mart/data/sets/14/twitter.json'; +import data from '@emoji-mart/data/sets/15/twitter.json'; export interface NativeEmoji { unified: string; diff --git a/yarn.lock b/yarn.lock index f844ef6a7..0e07f417c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1004,10 +1004,10 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247" integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g== -"@emoji-mart/data@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.1.2.tgz#777c976f8f143df47cbb23a7077c9ca9fe5fc513" - integrity sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg== +"@emoji-mart/data@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.2.1.tgz#0ad70c662e3bc603e23e7d98413bd1e64c4fcb6c" + integrity sha512-no2pQMWiBy6gpBEiqGeU77/bFejDqUTRY7KX+0+iur13op3bqUsXdnwoZs6Xb1zbv0gAj5VvS1PWoUUckSr5Dw== "@es-joy/jsdoccomment@~0.41.0": version "0.41.0" @@ -4224,15 +4224,15 @@ electron-to-chromium@^1.5.28: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz#aee074e202c6ee8a0030a9c2ef0b3fe9f967d576" integrity sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw== -emoji-datasource@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/emoji-datasource/-/emoji-datasource-14.0.0.tgz#99529a62f3a86546fc670c09b672ddc9f24f3d44" - integrity sha512-SoOv0lSa+9/2X9ulSRDhu2u1zAOaOv5vtMY3OYUDcQCoReEh0/3eQAMuBM9LyD7Hy3G4K7mDPDqVeHUWvy7cow== +emoji-datasource@15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/emoji-datasource/-/emoji-datasource-15.0.1.tgz#6cc7676e4d48d7559c2e068ffcacf84ec653584c" + integrity sha512-aF5Q6LCKXzJzpG4K0ETiItuzz0xLYxNexR9qWw45/shuuEDWZkOIbeGHA23uopOSYA/LmeZIXIFsySCx+YKg2g== -emoji-mart@^5.5.2: - version "5.5.2" - resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af" - integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A== +emoji-mart@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.6.0.tgz#71b3ed0091d3e8c68487b240d9d6d9a73c27f023" + integrity sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow== emoji-regex@10.3.0, emoji-regex@^10.2.1: version "10.3.0" From 4cda1e2866d7b5d4471761b1e457bed5f51116ca Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Fri, 18 Oct 2024 19:32:56 -0300 Subject: [PATCH 19/40] feat: create pagination with Link Headers for trending statuses --- src/actions/trending-statuses.ts | 55 +++++++++++++++++-- .../compose/components/search-results.tsx | 13 ++++- src/reducers/trending-statuses.ts | 10 +++- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/actions/trending-statuses.ts b/src/actions/trending-statuses.ts index e22448784..c6a26e316 100644 --- a/src/actions/trending-statuses.ts +++ b/src/actions/trending-statuses.ts @@ -1,6 +1,7 @@ +import { APIEntity } from 'soapbox/types/entities'; import { getFeatures } from 'soapbox/utils/features'; -import api from '../api'; +import api, { getLinks } from '../api'; import { importFetchedStatuses } from './importer'; @@ -9,6 +10,8 @@ import type { AppDispatch, RootState } from 'soapbox/store'; const TRENDING_STATUSES_FETCH_REQUEST = 'TRENDING_STATUSES_FETCH_REQUEST'; const TRENDING_STATUSES_FETCH_SUCCESS = 'TRENDING_STATUSES_FETCH_SUCCESS'; const TRENDING_STATUSES_FETCH_FAIL = 'TRENDING_STATUSES_FETCH_FAIL'; +const TRENDING_STATUSES_EXPAND_FAIL = 'TRENDING_STATUSES_EXPAND_FAIL'; +const TRENDING_STATUSES_EXPAND_SUCCESS = 'TRENDING_STATUSES_EXPAND_SUCCESS'; const fetchTrendingStatuses = () => (dispatch: AppDispatch, getState: () => RootState) => { @@ -20,18 +23,62 @@ const fetchTrendingStatuses = () => if (!features.trendingStatuses) return; dispatch({ type: TRENDING_STATUSES_FETCH_REQUEST }); - return api(getState).get('/api/v1/trends/statuses').then(({ data: statuses }) => { + return api(getState).get('/api/v1/trends/statuses').then((response) => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + const statuses = response.data; + dispatch(importFetchedStatuses(statuses)); - dispatch({ type: TRENDING_STATUSES_FETCH_SUCCESS, statuses }); + dispatch(fetchTrendingStatusesSuccess(statuses, next ? next.uri : null)); return statuses; }).catch(error => { - dispatch({ type: TRENDING_STATUSES_FETCH_FAIL, error }); + dispatch(fetchTrendingStatusesFail(error)); }); }; +const fetchTrendingStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({ + type: TRENDING_STATUSES_FETCH_SUCCESS, + statuses, + next, +}); + + +const fetchTrendingStatusesFail = (error: unknown) => ({ + type: TRENDING_STATUSES_FETCH_FAIL, + error, +}); + +const expandTrendingStatuses = (path: string) => + (dispatch: AppDispatch, getState: () => RootState) => { + api(getState).get(path).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + const statuses = response.data; + + dispatch(importFetchedStatuses(statuses)); + dispatch(expandTrendingStatusesSuccess(statuses, next ? next.uri : null)); + }).catch(error => { + dispatch(expandTrendingStatusesFail(error)); + }); + }; + +const expandTrendingStatusesSuccess = (statuses: APIEntity[], next: string | null) => ({ + type: TRENDING_STATUSES_EXPAND_SUCCESS, + statuses, + next, +}); + +const expandTrendingStatusesFail = (error: unknown) => ({ + type: TRENDING_STATUSES_EXPAND_FAIL, + error, +}); + export { TRENDING_STATUSES_FETCH_REQUEST, TRENDING_STATUSES_FETCH_SUCCESS, TRENDING_STATUSES_FETCH_FAIL, + TRENDING_STATUSES_EXPAND_SUCCESS, + TRENDING_STATUSES_EXPAND_FAIL, fetchTrendingStatuses, + expandTrendingStatuses, }; diff --git a/src/features/compose/components/search-results.tsx b/src/features/compose/components/search-results.tsx index 18bfa496c..edf6e859d 100644 --- a/src/features/compose/components/search-results.tsx +++ b/src/features/compose/components/search-results.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useRef } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { expandSearch, setFilter, setSearchAccount } from 'soapbox/actions/search'; -import { fetchTrendingStatuses } from 'soapbox/actions/trending-statuses'; +import { expandTrendingStatuses, fetchTrendingStatuses } from 'soapbox/actions/trending-statuses'; import { useAccount } from 'soapbox/api/hooks'; import Hashtag from 'soapbox/components/hashtag'; import IconButton from 'soapbox/components/icon-button'; @@ -36,13 +36,20 @@ const SearchResults = () => { const results = useAppSelector((state) => state.search.results); const suggestions = useAppSelector((state) => state.suggestions.items); const trendingStatuses = useAppSelector((state) => state.trending_statuses.items); + const nextTrendingStatuses = useAppSelector((state) => state.trending_statuses.next); const trends = useAppSelector((state) => state.trends.items); const submitted = useAppSelector((state) => state.search.submitted); const selectedFilter = useAppSelector((state) => state.search.filter); const filterByAccount = useAppSelector((state) => state.search.accountId || undefined); const { account } = useAccount(filterByAccount); - const handleLoadMore = () => dispatch(expandSearch(selectedFilter)); + const handleLoadMore = () => { + if (results.accounts.size || results.statuses.size || results.hashtags.size) { + dispatch(expandSearch(selectedFilter)); + } else if (nextTrendingStatuses) { + dispatch(expandTrendingStatuses(nextTrendingStatuses)); + } + }; const handleUnsetAccount = () => dispatch(setSearchAccount(null)); @@ -224,7 +231,7 @@ const SearchResults = () => { scrollKey={`${selectedFilter}:${value}`} isLoading={submitted && !loaded} showLoading={submitted && !loaded && searchResults?.isEmpty()} - hasMore={hasMore} + hasMore={(!!nextTrendingStatuses) || hasMore} onLoadMore={handleLoadMore} placeholderComponent={placeholderComponent} placeholderCount={20} diff --git a/src/reducers/trending-statuses.ts b/src/reducers/trending-statuses.ts index e6f5bb72e..a86d66c11 100644 --- a/src/reducers/trending-statuses.ts +++ b/src/reducers/trending-statuses.ts @@ -3,6 +3,7 @@ import { OrderedSet as ImmutableOrderedSet, Record as ImmutableRecord } from 'im import { TRENDING_STATUSES_FETCH_REQUEST, TRENDING_STATUSES_FETCH_SUCCESS, + TRENDING_STATUSES_EXPAND_SUCCESS, } from 'soapbox/actions/trending-statuses'; import type { AnyAction } from 'redux'; @@ -11,6 +12,7 @@ import type { APIEntity } from 'soapbox/types/entities'; const ReducerRecord = ImmutableRecord({ items: ImmutableOrderedSet(), isLoading: false, + next: null as string | null, }); type State = ReturnType; @@ -18,10 +20,11 @@ type APIEntities = Array; const toIds = (items: APIEntities) => ImmutableOrderedSet(items.map(item => item.id)); -const importStatuses = (state: State, statuses: APIEntities) => { +const importStatuses = (state: State, statuses: APIEntities, next: string|null) => { return state.withMutations(state => { - state.set('items', toIds(statuses)); + state.update('items', list => list.concat(toIds(statuses))); state.set('isLoading', false); + state.set('next', next ? next : null); }); }; @@ -29,8 +32,9 @@ export default function trending_statuses(state: State = ReducerRecord(), action switch (action.type) { case TRENDING_STATUSES_FETCH_REQUEST: return state.set('isLoading', true); + case TRENDING_STATUSES_EXPAND_SUCCESS: case TRENDING_STATUSES_FETCH_SUCCESS: - return importStatuses(state, action.statuses); + return importStatuses(state, action.statuses, action.next); default: return state; } From 90d130e8a0b225dbbacaa26186da43ebdfee3b5e Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Fri, 18 Oct 2024 19:33:29 -0300 Subject: [PATCH 20/40] fix: yarn lint fix --- src/api/hooks/zap-split/useZapSplit.ts | 4 ++-- src/schemas/zap-split.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/hooks/zap-split/useZapSplit.ts b/src/api/hooks/zap-split/useZapSplit.ts index f77b79c71..2790a0129 100644 --- a/src/api/hooks/zap-split/useZapSplit.ts +++ b/src/api/hooks/zap-split/useZapSplit.ts @@ -18,9 +18,9 @@ interface SplitValue { * * @param {StatusEntity | undefined} status - The current status entity. * @param {AccountEntity} account - The account for which the zap split calculation is done. -* +* * @returns {Object} An object containing the zap split arrays, zap split data, and a function to calculate the received amount. -* +* * @property {ZapSplitData[]} zapArrays - Array of zap split data returned from the API. * @property {Object} zapSplitData - Contains the total split amount, amount to receive, and individual split values. * @property {Function} receiveAmount - A function to calculate the zap amount based on the split configuration. diff --git a/src/schemas/zap-split.ts b/src/schemas/zap-split.ts index c2323d773..e830e676b 100644 --- a/src/schemas/zap-split.ts +++ b/src/schemas/zap-split.ts @@ -7,7 +7,7 @@ const addMethodsToAccount = (account: Account) => { ...account, get: (key: string) => (account as any)[key], getIn: (path: string[]) => path.reduce((acc, key) => (acc as any)[key], account), - toJS: () => account, + toJS: () => account, }; }; From 6d5b4189e56e4d34ba45f4f69842d7c7df79cb5f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 18 Oct 2024 22:00:13 -0500 Subject: [PATCH 21/40] eslint --fix --- src/api/hooks/zap-split/useZapSplit.ts | 4 ++-- src/components/account-search.tsx | 4 ++-- src/components/account.tsx | 6 +++--- src/components/announcements/reaction.tsx | 2 +- src/components/authorize-reject-buttons.tsx | 4 ++-- src/components/big-card.tsx | 4 ++-- src/components/dropdown-menu/dropdown-menu-item.tsx | 4 ++-- src/components/dropdown-menu/dropdown-menu.tsx | 2 +- src/components/emoji-graphic.tsx | 2 +- src/components/event-preview.tsx | 2 +- src/components/gameboy.tsx | 2 +- src/components/group-card.tsx | 4 ++-- src/components/groups/popover/group-popover.tsx | 2 +- src/components/media-gallery.tsx | 4 ++-- src/components/pending-items-row.tsx | 2 +- src/components/polls/poll-option.tsx | 6 +++--- src/components/preview-card.tsx | 8 ++++---- src/components/profile-hover-card.tsx | 2 +- src/components/quoted-status-indicator.tsx | 2 +- src/components/radio.tsx | 2 +- src/components/scroll-top-button.tsx | 2 +- src/components/sidebar-menu.tsx | 8 ++++---- src/components/sidebar-navigation-link.tsx | 2 +- src/components/site-error-boundary.tsx | 2 +- src/components/status-action-button.tsx | 4 ++-- src/components/status-content.tsx | 2 +- src/components/status.tsx | 8 ++++---- src/components/statuses/status-info.tsx | 2 +- src/components/still-image.tsx | 2 +- src/components/ui/accordion/accordion.tsx | 4 ++-- src/components/ui/avatar/avatar.tsx | 2 +- src/components/ui/button/button.tsx | 2 +- src/components/ui/card/card.tsx | 2 +- src/components/ui/carousel/carousel.tsx | 4 ++-- src/components/ui/checkbox/checkbox.tsx | 2 +- src/components/ui/emoji-selector/emoji-selector.tsx | 2 +- src/components/ui/input/input.tsx | 4 ++-- .../ui/language-dropdown/language-dropdown.tsx | 4 ++-- src/components/ui/modal/modal.tsx | 4 ++-- src/components/ui/radio-button/radio-button.tsx | 2 +- src/components/ui/select/select.tsx | 2 +- src/components/ui/slider/slider.tsx | 2 +- src/components/ui/tag-input/tag-input.tsx | 2 +- src/components/ui/textarea/textarea.tsx | 2 +- src/components/ui/toast/toast.tsx | 8 ++++---- src/components/ui/widget/widget.tsx | 2 +- src/components/upload-progress.tsx | 2 +- src/components/upload.tsx | 4 ++-- src/features/account-gallery/components/media-item.tsx | 2 +- src/features/account/components/header.tsx | 10 +++++----- src/features/admin/tabs/dashboard.tsx | 2 +- src/features/aliases/components/search.tsx | 2 +- src/features/auth-login/components/consumers-list.tsx | 2 +- src/features/bookmark-folders/index.tsx | 2 +- src/features/chats/components/chat-list-item.tsx | 2 +- .../chats/components/chat-message-list-intro.tsx | 2 +- src/features/chats/components/chat-message.tsx | 8 ++++---- src/features/chats/components/chat-page/chat-page.tsx | 4 ++-- .../components/chat-page/components/chat-page-main.tsx | 6 +++--- .../components/chat-page/components/chat-page-new.tsx | 2 +- .../chat-page/components/chat-page-settings.tsx | 2 +- src/features/chats/components/chat-pending-upload.tsx | 2 +- src/features/chats/components/chat-search-input.tsx | 2 +- .../chats/components/chat-search/chat-search.tsx | 2 +- src/features/chats/components/chat-textarea.tsx | 6 +++--- src/features/chats/components/chat-upload-preview.tsx | 8 ++++---- src/features/chats/components/chat-upload.tsx | 10 +++++----- .../chats/components/chat-widget/chat-pane-header.tsx | 2 +- .../chats/components/chat-widget/chat-settings.tsx | 6 +++--- .../chats/components/chat-widget/chat-window.tsx | 2 +- .../chat-widget/headers/chat-search-header.tsx | 2 +- src/features/chats/components/ui/pane.tsx | 2 +- src/features/compose/components/search-zap-split.tsx | 2 +- src/features/compose/components/search.tsx | 4 ++-- src/features/compose/editor/nodes/emoji-node.tsx | 4 ++-- src/features/developers/service-worker-info.tsx | 2 +- src/features/edit-identity/index.tsx | 4 ++-- src/features/edit-profile/components/avatar-picker.tsx | 6 +++--- src/features/edit-profile/components/header-picker.tsx | 8 ++++---- src/features/event/components/event-header.tsx | 6 +++--- src/features/events/components/event-carousel.tsx | 8 ++++---- .../components/instance-restrictions.tsx | 2 +- src/features/feed-suggestions/feed-suggestions.tsx | 4 ++-- src/features/group/components/group-header-image.tsx | 2 +- src/features/group/components/group-header.tsx | 10 +++++----- src/features/group/components/group-privacy.tsx | 4 ++-- src/features/group/components/group-relationship.tsx | 2 +- src/features/group/components/group-tag-list-item.tsx | 2 +- src/features/group/edit-group.tsx | 2 +- src/features/group/group-tag-timeline.tsx | 2 +- src/features/group/group-tags.tsx | 2 +- src/features/group/group-timeline.tsx | 2 +- .../groups/components/discover/group-grid-item.tsx | 2 +- .../groups/components/discover/group-list-item.tsx | 2 +- .../groups/components/discover/layout-buttons.tsx | 4 ++-- .../components/discover/search/recent-searches.tsx | 4 ++-- src/features/groups/discover.tsx | 2 +- src/features/groups/tag.tsx | 4 ++-- src/features/notifications/components/notification.tsx | 2 +- .../placeholder/components/placeholder-group-card.tsx | 2 +- .../components/placeholder-group-discover.tsx | 4 ++-- .../components/placeholder-group-search.tsx | 2 +- .../components/placeholder-notification.tsx | 2 +- .../components/placeholder-sidebar-suggestions.tsx | 2 +- .../soapbox-config/components/color-with-picker.tsx | 2 +- .../soapbox-config/components/icon-picker-dropdown.tsx | 2 +- .../soapbox-config/components/icon-picker-menu.tsx | 2 +- src/features/status/components/detailed-status.tsx | 6 +++--- .../status/components/status-interaction-bar.tsx | 2 +- src/features/status/components/thread-status.tsx | 2 +- src/features/theme-editor/components/color.tsx | 2 +- src/features/ui/components/floating-action-button.tsx | 4 ++-- .../ui/components/modals/compare-history-modal.tsx | 2 +- .../modals/compose-event-modal/compose-event-modal.tsx | 6 +++--- .../modals/compose-event-modal/upload-button.tsx | 4 ++-- .../components/modals/edit-bookmark-folder-modal.tsx | 4 ++-- .../ui/components/modals/landing-page-modal.tsx | 2 +- .../manage-group-modal/steps/confirmation-step.tsx | 6 +++--- src/features/ui/components/modals/media-modal.tsx | 8 ++++---- .../modals/nostr-login-modal/steps/extension-step.tsx | 2 +- .../modals/onboarding-flow-modal/steps/avatar-step.tsx | 6 +++--- .../modals/onboarding-flow-modal/steps/bio-step.tsx | 6 +++--- .../onboarding-flow-modal/steps/completed-step.tsx | 6 +++--- .../steps/cover-photo-selection-step.tsx | 8 ++++---- .../onboarding-flow-modal/steps/display-name-step.tsx | 6 +++--- .../steps/suggested-accounts-step.tsx | 6 +++--- src/features/ui/components/modals/reactions-modal.tsx | 2 +- .../ui/components/modals/report-modal/report-modal.tsx | 2 +- .../modals/report-modal/steps/reason-step.tsx | 2 +- .../components/modals/select-bookmark-folder-modal.tsx | 2 +- src/features/ui/components/modals/zap-invoice.tsx | 2 +- .../ui/components/modals/zap-split/zap-split.tsx | 2 +- src/features/ui/components/profile-dropdown.tsx | 2 +- src/features/ui/components/profile-info-panel.tsx | 10 +++++----- src/features/ui/components/theme-selector.tsx | 4 ++-- src/features/ui/components/user-panel.tsx | 2 +- src/features/ui/index.tsx | 2 +- src/features/zap/components/zap-pay-request-form.tsx | 4 ++-- src/pages/group-page.tsx | 6 +++--- src/pages/landing-page.tsx | 2 +- src/schemas/zap-split.ts | 2 +- 141 files changed, 248 insertions(+), 248 deletions(-) diff --git a/src/api/hooks/zap-split/useZapSplit.ts b/src/api/hooks/zap-split/useZapSplit.ts index f77b79c71..2790a0129 100644 --- a/src/api/hooks/zap-split/useZapSplit.ts +++ b/src/api/hooks/zap-split/useZapSplit.ts @@ -18,9 +18,9 @@ interface SplitValue { * * @param {StatusEntity | undefined} status - The current status entity. * @param {AccountEntity} account - The account for which the zap split calculation is done. -* +* * @returns {Object} An object containing the zap split arrays, zap split data, and a function to calculate the received amount. -* +* * @property {ZapSplitData[]} zapArrays - Array of zap split data returned from the API. * @property {Object} zapSplitData - Contains the total split amount, amount to receive, and individual split values. * @property {Function} receiveAmount - A function to calculate the zap amount based on the split configuration. diff --git a/src/components/account-search.tsx b/src/components/account-search.tsx index dec244674..cec7fc8f8 100644 --- a/src/components/account-search.tsx +++ b/src/components/account-search.tsx @@ -77,12 +77,12 @@ const AccountSearch: React.FC = ({ onSelected, ...rest }) => { >
diff --git a/src/components/account.tsx b/src/components/account.tsx index ddee09385..f61029250 100644 --- a/src/components/account.tsx +++ b/src/components/account.tsx @@ -50,7 +50,7 @@ const InstanceFavicon: React.FC = ({ account, disabled }) => { return ( @@ -199,7 +199,7 @@ const PreviewCard: React.FC = ({ > )} @@ -220,7 +220,7 @@ const PreviewCard: React.FC = ({ embed = (
= ({ visible = true } diff --git a/src/components/quoted-status-indicator.tsx b/src/components/quoted-status-indicator.tsx index 493db5f19..c70e00f5f 100644 --- a/src/components/quoted-status-indicator.tsx +++ b/src/components/quoted-status-indicator.tsx @@ -18,7 +18,7 @@ const QuotedStatusIndicator: React.FC = ({ statusId }) = return ( - + {status.url} ); diff --git a/src/components/radio.tsx b/src/components/radio.tsx index 2104b9985..9c1714e9d 100644 --- a/src/components/radio.tsx +++ b/src/components/radio.tsx @@ -31,7 +31,7 @@ const RadioItem: React.FC = ({ label, hint, checked = false, onChang checked={checked} onChange={onChange} value={value} - className='h-4 w-4 border-gray-300 text-primary-600 focus:ring-primary-500' + className='size-4 border-gray-300 text-primary-600 focus:ring-primary-500' /> ); diff --git a/src/components/scroll-top-button.tsx b/src/components/scroll-top-button.tsx index 9e2dfafe4..489aa0503 100644 --- a/src/components/scroll-top-button.tsx +++ b/src/components/scroll-top-button.tsx @@ -91,7 +91,7 @@ const ScrollTopButton: React.FC = ({ onClick={handleClick} > diff --git a/src/components/sidebar-menu.tsx b/src/components/sidebar-menu.tsx index 20431476d..67a838a28 100644 --- a/src/components/sidebar-menu.tsx +++ b/src/components/sidebar-menu.tsx @@ -56,7 +56,7 @@ const SidebarLink: React.FC = ({ href, to, icon, text, onClick, co const body = (
- +
{text} @@ -170,7 +170,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { className='absolute right-0 top-0 -mr-11 mt-2 text-gray-600 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300' /> -
+
@@ -348,7 +348,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { @@ -360,7 +360,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {otherAccounts.map(account => renderAccount(account))} - + {intl.formatMessage(messages.addAccount)}
diff --git a/src/components/sidebar-navigation-link.tsx b/src/components/sidebar-navigation-link.tsx index 7cdec9370..336aac5ae 100644 --- a/src/components/sidebar-navigation-link.tsx +++ b/src/components/sidebar-navigation-link.tsx @@ -50,7 +50,7 @@ const SidebarNavigationLink = React.forwardRef((props: ISidebarNavigationLink, r src={(isActive && activeIcon) || icon} count={count} countMax={countMax} - className={clsx('h-5 w-5', { + className={clsx('size-5', { 'text-gray-600 black:text-white dark:text-gray-500 group-hover:text-primary-500 dark:group-hover:text-primary-400': !isActive, 'text-primary-500 dark:text-primary-400': isActive, })} diff --git a/src/components/site-error-boundary.tsx b/src/components/site-error-boundary.tsx index 61db29f1f..513906b2e 100644 --- a/src/components/site-error-boundary.tsx +++ b/src/components/site-error-boundary.tsx @@ -84,7 +84,7 @@ const SiteErrorBoundary: React.FC = ({ children }) => {
-

+

diff --git a/src/components/status-action-button.tsx b/src/components/status-action-button.tsx index aa87502ca..c435227a7 100644 --- a/src/components/status-action-button.tsx +++ b/src/components/status-action-button.tsx @@ -44,8 +44,8 @@ const StatusActionButton = React.forwardRef { if (emoji) { return ( - - + + ); } else { diff --git a/src/components/status-content.tsx b/src/components/status-content.tsx index 980e820c9..8d537aa62 100644 --- a/src/components/status-content.tsx +++ b/src/components/status-content.tsx @@ -27,7 +27,7 @@ interface IReadMoreButton { const ReadMoreButton: React.FC = ({ onClick }) => ( ); diff --git a/src/components/status.tsx b/src/components/status.tsx index cd9e53301..3d9349fd2 100644 --- a/src/components/status.tsx +++ b/src/components/status.tsx @@ -212,7 +212,7 @@ const Status: React.FC = (props) => { return ( } + icon={} text={ = (props) => { return ( } + icon={} text={ = (props) => { return ( } + icon={} text={ } @@ -289,7 +289,7 @@ const Status: React.FC = (props) => { return ( } + icon={} text={ {

= ({ alt, className, src, style, letterb }; /** ClassNames shared between the `` and `` elements. */ - const baseClassName = clsx('block h-full w-full', { + const baseClassName = clsx('block size-full', { 'object-contain': letterboxed, 'object-cover': !letterboxed, }); diff --git a/src/components/ui/accordion/accordion.tsx b/src/components/ui/accordion/accordion.tsx index efaa02a69..ec9e1a4cf 100644 --- a/src/components/ui/accordion/accordion.tsx +++ b/src/components/ui/accordion/accordion.tsx @@ -67,13 +67,13 @@ const Accordion: React.FC = ({ headline, children, menu, expanded = )} diff --git a/src/components/ui/avatar/avatar.tsx b/src/components/ui/avatar/avatar.tsx index 448ab7e52..c6d1af6c8 100644 --- a/src/components/ui/avatar/avatar.tsx +++ b/src/components/ui/avatar/avatar.tsx @@ -36,7 +36,7 @@ const Avatar = (props: IAvatar) => { >
); diff --git a/src/components/ui/button/button.tsx b/src/components/ui/button/button.tsx index 1c9e7d5a1..43c3fd740 100644 --- a/src/components/ui/button/button.tsx +++ b/src/components/ui/button/button.tsx @@ -66,7 +66,7 @@ const Button = React.forwardRef((props, ref): JSX.El return null; } - return ; + return ; }; const handleClick: React.MouseEventHandler = React.useCallback((event) => { diff --git a/src/components/ui/card/card.tsx b/src/components/ui/card/card.tsx index a4bb389a1..242d50f34 100644 --- a/src/components/ui/card/card.tsx +++ b/src/components/ui/card/card.tsx @@ -72,7 +72,7 @@ const CardHeader: React.FC = ({ className, children, backHref, onBa return ( - + {intl.formatMessage(messages.back)} ); diff --git a/src/components/ui/carousel/carousel.tsx b/src/components/ui/carousel/carousel.tsx index 0bece264c..1cd4f2e8a 100644 --- a/src/components/ui/carousel/carousel.tsx +++ b/src/components/ui/carousel/carousel.tsx @@ -69,7 +69,7 @@ const Carousel: React.FC = (props): JSX.Element => { >
@@ -101,7 +101,7 @@ const Carousel: React.FC = (props): JSX.Element => { >
diff --git a/src/components/ui/checkbox/checkbox.tsx b/src/components/ui/checkbox/checkbox.tsx index 3ae46c131..4c20d688c 100644 --- a/src/components/ui/checkbox/checkbox.tsx +++ b/src/components/ui/checkbox/checkbox.tsx @@ -9,7 +9,7 @@ const Checkbox = React.forwardRef((props, ref) => { {...props} ref={ref} type='checkbox' - className='h-4 w-4 rounded border-2 border-gray-300 text-primary-600 focus:ring-primary-500 black:bg-black dark:border-gray-800 dark:bg-gray-900' + className='size-4 rounded border-2 border-gray-300 text-primary-600 focus:ring-primary-500 black:bg-black dark:border-gray-800 dark:bg-gray-900' /> ); }); diff --git a/src/components/ui/emoji-selector/emoji-selector.tsx b/src/components/ui/emoji-selector/emoji-selector.tsx index 114f94d96..9a28bffa1 100644 --- a/src/components/ui/emoji-selector/emoji-selector.tsx +++ b/src/components/ui/emoji-selector/emoji-selector.tsx @@ -32,7 +32,7 @@ const EmojiButton: React.FC = ({ emoji, className, onClick, tabInd return ( ); }; diff --git a/src/components/ui/input/input.tsx b/src/components/ui/input/input.tsx index 9d23b62a2..8b855ab3d 100644 --- a/src/components/ui/input/input.tsx +++ b/src/components/ui/input/input.tsx @@ -73,7 +73,7 @@ const Input = React.forwardRef( > {icon ? (
-
) : null} @@ -124,7 +124,7 @@ const Input = React.forwardRef( >
diff --git a/src/components/ui/language-dropdown/language-dropdown.tsx b/src/components/ui/language-dropdown/language-dropdown.tsx index ba272675f..b6eac2f15 100644 --- a/src/components/ui/language-dropdown/language-dropdown.tsx +++ b/src/components/ui/language-dropdown/language-dropdown.tsx @@ -47,11 +47,11 @@ const LanguageDropdown: React.FC = ({ language, setLanguage } return ( {language ? ( - ) : ( - + )} ); diff --git a/src/components/ui/modal/modal.tsx b/src/components/ui/modal/modal.tsx index 045909030..82b9e6482 100644 --- a/src/components/ui/modal/modal.tsx +++ b/src/components/ui/modal/modal.tsx @@ -118,7 +118,7 @@ const Modal = React.forwardRef(({ src={require('@tabler/icons/outline/arrow-left.svg')} title={intl.formatMessage(messages.back)} onClick={onBack} - className='text-gray-500 hover:text-gray-700 rtl:rotate-180 dark:text-gray-300 dark:hover:text-gray-200' + className='text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200 rtl:rotate-180' /> )} @@ -131,7 +131,7 @@ const Modal = React.forwardRef(({ src={closeIcon} title={intl.formatMessage(messages.close)} onClick={onClose} - className='text-gray-500 hover:text-gray-700 rtl:rotate-180 dark:text-gray-300 dark:hover:text-gray-200' + className='text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200 rtl:rotate-180' /> )}
diff --git a/src/components/ui/radio-button/radio-button.tsx b/src/components/ui/radio-button/radio-button.tsx index df5d77391..c03ca5d52 100644 --- a/src/components/ui/radio-button/radio-button.tsx +++ b/src/components/ui/radio-button/radio-button.tsx @@ -25,7 +25,7 @@ const RadioButton: React.FC = ({ name, value, checked, onChange, l value={value} checked={checked} onChange={onChange} - className='h-4 w-4 border-gray-300 text-primary-600 focus:ring-primary-500' + className='size-4 border-gray-300 text-primary-600 focus:ring-primary-500' />