Porównaj commity

...

470 Commity

Autor SHA1 Wiadomość Data
miklobit 7dc1cca40c Merge remote-tracking branch 'upstream/develop' into develop 2023-03-31 22:02:56 +02:00
Chewbacca b277143e3a Merge branch 'chunk' into 'develop'
Change discover chunk to groups

See merge request soapbox-pub/soapbox!2392
2023-03-31 12:01:37 +00:00
Chewbacca eeafb3073e Change discover chunk to groups 2023-03-31 08:00:21 -04:00
Chewbacca ccd97e1405 Merge branch 'group-dark-mode' into 'develop'
Improve Dark mode support for Groups + Tests

See merge request soapbox-pub/soapbox!2390
2023-03-31 11:44:28 +00:00
Chewbacca a994d1c33e i18n 2023-03-30 20:46:18 -04:00
Chewbacca 681eacf827 Improve dark mode support of Groups + bug fixes 2023-03-30 15:19:14 -04:00
Chewbacca 4b3b601659 Add tests for GroupOptionsButton 2023-03-30 12:57:42 -04:00
Chewbacca 697791fc5d Add tests for GroupRelationship 2023-03-30 12:57:23 -04:00
Alex Gleason a976b542e1 Merge branch 'edit-group-page' into 'develop'
Edit group page

See merge request soapbox-pub/soapbox!2389
2023-03-30 13:57:57 +00:00
Chewbacca e32ea32f15 Merge branch 'group-name-validation' into 'develop'
Group name validation

See merge request soapbox-pub/soapbox!2388
2023-03-30 13:28:03 +00:00
Chewbacca ff3c0c5cd7 i18n 2023-03-30 09:25:15 -04:00
Chewbacca 01458c3003 Merge branch 'reply-popover' into 'develop'
Add popover when trying to reply to Group status

See merge request soapbox-pub/soapbox!2386
2023-03-30 13:23:47 +00:00
Alex Gleason 453420796b
yarn i18n 2023-03-29 20:49:04 -05:00
Alex Gleason e47b9300f0
EditGroup: add "cannot change" hint 2023-03-29 20:45:40 -05:00
Alex Gleason ddf433a5c9
FormGroup: move hintText above input 2023-03-29 20:42:57 -05:00
Alex Gleason 79a33d0f1d
Input: improve disabled style 2023-03-29 20:37:22 -05:00
Alex Gleason 9e60d90812
We do a little refactoring 2023-03-29 20:30:05 -05:00
Alex Gleason f3727440ff
Move form hooks into their own files 2023-03-29 20:14:41 -05:00
Alex Gleason eb055339d8
react-hook-form SUX 2023-03-29 20:00:04 -05:00
Alex Gleason 9c78a37844
Merge remote-tracking branch 'origin/develop' into edit-group-page 2023-03-29 19:31:01 -05:00
Alex Gleason 8e6dfe6395 Merge branch 'textarea-counter' into 'develop'
Textarea: add a character counter

See merge request soapbox-pub/soapbox!2373
2023-03-30 00:30:39 +00:00
Alex Gleason 7ec51778f8 Apply 1 suggestion(s) to 1 file(s) 2023-03-30 00:30:27 +00:00
Alex Gleason eb6c82a867
Make EditGroup page work, pretty much 2023-03-29 19:18:20 -05:00
Alex Gleason bfd40fa373
Boilerplate Edit Group page by copying code from the modal 2023-03-29 14:51:29 -05:00
Chewbacca 455030ef5b Add validation support to features 2023-03-29 15:44:00 -04:00
Chewbacca 4886548889 Add validation support to Group names 2023-03-29 15:42:20 -04:00
Chewbacca 85e5780645 Deprecate old Icon component 2023-03-29 15:42:05 -04:00
Chewbacca 20960d7238 Improve UI of List component 2023-03-29 15:41:49 -04:00
Alex Gleason 319d47b36f Merge branch 'pending-memberships-dot' into 'develop'
Groups: add dot to group with pending membership requests

See merge request soapbox-pub/soapbox!2387
2023-03-29 19:13:54 +00:00
Alex Gleason 609a25fd8d
Groups: add dot to group with pending membership requests 2023-03-29 12:21:43 -05:00
marcin mikołajczak 55c0f8d6a1 Merge branch 'friendica' into 'develop'
Friendica dislikes

See merge request soapbox-pub/soapbox!2381
2023-03-28 22:13:24 +00:00
Chewbacca 1e69812078 Add popover when trying to reply to Group status 2023-03-28 15:39:41 -04:00
Chewbacca 89ab02224f Merge branch 'group-improvements' into 'develop'
Group improvements

See merge request soapbox-pub/soapbox!2385
2023-03-28 17:21:10 +00:00
Chewbacca af9439f1d3 Use entity store for Group Search 2023-03-28 12:57:44 -04:00
Chewbacca a916056367 Re-use GroupActionButton component 2023-03-28 11:53:13 -04:00
Chewbacca 9fe2d4f92c Remove unused query 2023-03-28 11:53:13 -04:00
Chewbacca ca0987dec2 Update variables to use proper naming 2023-03-28 11:53:13 -04:00
Chewbacca 6458ebbb11 Ensure button text stays centered 2023-03-28 11:53:13 -04:00
Chewbacca 966fcc617a Merge branch 'fix-loading-state' into 'develop'
Fix loading animation for Carousel

See merge request soapbox-pub/soapbox!2383
2023-03-28 15:52:56 +00:00
Chewbacca e12450ee5d Merge branch 'group-improvements' into 'develop'
Remove mock data for Group Discovery

See merge request soapbox-pub/soapbox!2384
2023-03-28 14:33:49 +00:00
Chewbacca 29c913859e Remove mock data for Group Discovery 2023-03-28 10:32:56 -04:00
Chewbacca be4a7e45e9 Fix loading animation for Carousel 2023-03-28 10:30:34 -04:00
Chewbacca 1abcc95a0a Merge branch 'search-my-groups' into 'develop'
Add ability to search my Groups

See merge request soapbox-pub/soapbox!2377
2023-03-28 14:02:25 +00:00
Chewbacca e6252070a6 Fix test 2023-03-28 09:46:55 -04:00
Alex Gleason f2744cdf98 Merge branch 'pending-timer' into 'develop'
AuthorizeRejectButtons: add a countdown timer, remove rejectUserModal

See merge request soapbox-pub/soapbox!2382
2023-03-28 13:35:38 +00:00
Chewbacca 3a2b4c6efb Add ability to search my Groups 2023-03-28 09:09:09 -04:00
Alex Gleason 232e387a50
yarn i18n 2023-03-27 17:24:24 -05:00
Alex Gleason d39e2cc7e0
UnapprovedAccount: use countdown, remove rejectUserModal 2023-03-27 17:14:22 -05:00
Alex Gleason 0522f333c3
Make follow requests use AuthorizeRejectButtons countdown 2023-03-27 17:13:44 -05:00
Alex Gleason 22474e3ca9
MembershipRequest: add 3s countdown on authorize/reject actions 2023-03-27 17:09:10 -05:00
Alex Gleason f216b52b36
AuthorizeRejectButtons: skip animations if countdown is undefined 2023-03-27 17:08:24 -05:00
Alex Gleason 09ed0bccab
AuthorizeRejectButtons: refactor ActionEmblem into a separate component 2023-03-27 17:03:19 -05:00
Alex Gleason 63394bb1b4
AuthorizeRejectButtons: refactor button into a separate component 2023-03-27 16:59:55 -05:00
Alex Gleason d08a2e215b
AuthorizeRejectButtons: add a loading animation 2023-03-27 16:45:41 -05:00
Alex Gleason 3b8f43f02d
AuthorizeRejectButtons: fix onReject never being called 2023-03-27 15:36:55 -05:00
Alex Gleason 9367b16200
AuthorizeRejectButtons: swap out icon during action countdown 2023-03-27 15:34:02 -05:00
Alex Gleason 6f705a827e
AuthorizeRejectButtons: add countdown functionality 2023-03-27 15:31:13 -05:00
Chewbacca ff5eb736fc Merge branch 'report-group' into 'develop'
Add ability to report a Group

See merge request soapbox-pub/soapbox!2375
2023-03-27 18:06:35 +00:00
marcin mikołajczak f6cee79c0e lint
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-26 21:58:46 +02:00
marcin mikołajczak bf8c454c23 Update en.json
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 23:18:38 +01:00
marcin mikołajczak 12f3b4fbc3 Support Friendica dislikes, quotes
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 23:16:40 +01:00
marcin mikołajczak 4bee42f86d Update changelog
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 12:15:56 +01:00
marcin mikołajczak 96a8bcdf82 Friendica dislikes
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 12:14:53 +01:00
marcin mikołajczak a45be78b97 Merge branch 'friendica' into 'develop'
Update features.ts for Friendica

See merge request soapbox-pub/soapbox!2380
2023-03-25 10:59:06 +00:00
marcin mikołajczak 4990e1eaa7 Check version for Friendica features
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 10:02:21 +01:00
marcin mikołajczak 52172c923f Actually fix version parsing for Friendica
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 09:43:27 +01:00
marcin mikołajczak 01359ca592 Update features.ts for Friendica
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-25 09:01:58 +01:00
Alex Gleason 7c1182bfb3 Merge branch 'entity-request' into 'develop'
EntityStore: refactor all hooks to use callbacks

See merge request soapbox-pub/soapbox!2379
2023-03-24 14:44:47 +00:00
Alex Gleason 818b10efc3
Remove stray whitespace 2023-03-23 19:24:20 -05:00
Alex Gleason a530ec0202
EntityStore: switch all hooks to use a callback function 2023-03-23 19:22:26 -05:00
Alex Gleason 9d12173b87
Add useLoading hook 2023-03-23 18:44:44 -05:00
Alex Gleason aa7e2f6965
Refactor hooks with useEntityRequest 2023-03-23 16:22:15 -05:00
Alex Gleason 45c12e9b65
Make EntityCallbacks a generic function 2023-03-23 16:09:04 -05:00
Alex Gleason 7248331742
Add useEntityRequest hook 2023-03-23 16:04:42 -05:00
Alex Gleason ac9718e6ed
Return isLoading from useCreateEntity and useDeleteEntity 2023-03-23 15:30:45 -05:00
Alex Gleason 1b569b6c82
useEntity: accept an EntityRequest object 2023-03-23 15:15:04 -05:00
Alex Gleason b4c3248791
useEntityActions: fix isLoading 2023-03-23 15:09:00 -05:00
Alex Gleason 1c5a6d8b41
useDeleteEntity: refactor with EntityRequest 2023-03-23 15:05:34 -05:00
Alex Gleason 50f65bc7c9
useCreateEntity: pass an EntityRequest, refactor 2023-03-23 14:52:38 -05:00
Chewbacca 30ef70440f Add ability to report a Group 2023-03-23 15:17:44 -04:00
Alex Gleason ad3f8acbe5
EntityStore: allow passing an EntityRequest object to useEntities 2023-03-23 14:14:53 -05:00
Alex Gleason 948d66bcab Merge branch 'group-requests' into 'develop'
Groups: improve pending memberships, standardize "authorize/reject" buttons throughout the UI

See merge request soapbox-pub/soapbox!2370
2023-03-23 17:05:14 +00:00
Alex Gleason 4783a41b78
useDeleteEntity: support onSuccess callback 2023-03-23 10:45:49 -05:00
Alex Gleason 1949651b9a
Merge remote-tracking branch 'origin/develop' into group-requests 2023-03-23 10:23:06 -05:00
Alex Gleason 75b0262f9a
Move pendingCount logic to useEntities 2023-03-22 21:28:48 -05:00
Alex Gleason 2674c060ad
GroupMembers: showLoading if pending members are being fetched 2023-03-22 20:26:53 -05:00
Alex Gleason 6929975aaa
useIncrementEntity: fix optimistic counter 2023-03-22 19:58:40 -05:00
Alex Gleason 402daec9c3
Add useIncrementEntity hook 2023-03-22 19:45:34 -05:00
Alex Gleason c5b1f23bda
GroupMembers: use X-Total-Count if available 2023-03-22 19:22:12 -05:00
Alex Gleason c4d0dd568e
EntityStore: let totalCount be undefined, don't try to set it from the local count 2023-03-22 19:11:11 -05:00
Alex Gleason f016ac1e6d
GroupMembershipRequests: invalidate query upon authorize/reject 2023-03-22 18:48:24 -05:00
Alex Gleason cb8363d179
EntityStore: make fetching the first page override the old list 2023-03-22 18:47:10 -05:00
Alex Gleason e2510489c5
EntityStore: support query invalidation 2023-03-22 18:17:28 -05:00
Alex Gleason a256665aad
EntityStore: add support for X-Total-Count from the API 2023-03-22 17:39:58 -05:00
Alex Gleason 1eed61c386
GroupMembershipRequests: don't clear dismissed entries until new content is fetched 2023-03-22 16:42:08 -05:00
Alex Gleason b47cdb368f
useGroupMembershipRequests: use useDismissEntity hooks 2023-03-22 16:31:49 -05:00
Alex Gleason 61fb434a54
Improve API of parseEntitiesPath 2023-03-22 16:12:05 -05:00
Alex Gleason 8f67d2c76f
EntityStore: consolidate types, fix type of "path" 2023-03-22 16:06:10 -05:00
Alex Gleason d2fd9e0387
Export new entity hooks 2023-03-22 15:32:56 -05:00
Alex Gleason b127025167
Move useCreateEntity into its own hook as well, because why not 2023-03-22 15:31:58 -05:00
Alex Gleason b76559f24a
Add useDismissEntity hook, update useDeleteEntity to match 2023-03-22 14:40:18 -05:00
Alex Gleason 3d72e6305f
EntityStory: add dismissEntities action for deleting ids from a list 2023-03-22 14:34:10 -05:00
Alex Gleason 4049de50aa
Add separate useDeleteEntity hook accepting a callback 2023-03-22 14:08:08 -05:00
Alex Gleason ee1b1b4397
GroupMembers: fix pending row borders and dark mode 2023-03-22 13:47:18 -05:00
Alex Gleason 1954848c65
Tabs: vertically center the counter 2023-03-22 13:23:45 -05:00
Alex Gleason 71c7c4adc7 Merge branch 'group-widgets' into 'develop'
Add MyGroupsPanel, improve layout on various group pages

See merge request soapbox-pub/soapbox!2374
2023-03-22 16:03:02 +00:00
Alex Gleason cc2fbc0208 Merge branch 'redirect-group-posts' into 'develop'
Redirect group statuses to a custom path

See merge request soapbox-pub/soapbox!2371
2023-03-22 16:02:58 +00:00
Chewbacca f7a964e6ee Merge branch 'delete-group' into 'develop'
Add hook to delete Group

See merge request soapbox-pub/soapbox!2369
2023-03-22 15:58:27 +00:00
Chewbacca 32ca5f09ee I18n 2023-03-22 11:23:35 -04:00
Chewbacca ad98bf45cc Add hook to delete Group 2023-03-22 11:20:03 -04:00
Alex Gleason 65070f6519
Add MyGroupsPanel, improve layout on various group pages 2023-03-21 16:34:15 -05:00
Alex Gleason ec72ac0db8
yarn i18n 2023-03-21 16:09:40 -05:00
Alex Gleason be32a0c1a0
Textarea: add a character counter 2023-03-21 15:39:08 -05:00
Alex Gleason 69d667d6c6
"Authorized" --> "Approved" 2023-03-21 11:56:48 -05:00
Alex Gleason be7a462fc4 Merge branch 'edit-group-fixes' into 'develop'
Edit group fixes

See merge request soapbox-pub/soapbox!2372
2023-03-21 03:16:08 +00:00
Alex Gleason f61e0d889a
"Blocked members" --> "Banned members" 2023-03-20 21:56:15 -05:00
Alex Gleason cc3585f319
Manage group: add headers 2023-03-20 21:52:44 -05:00
Alex Gleason f369a7c765
Use "danger" text for deleting account and group 2023-03-20 21:42:54 -05:00
Alex Gleason a8be701ea0
Fix PendingGroupsRow test 2023-03-20 21:31:07 -05:00
Alex Gleason 2196d9e3e5
yarn i18n 2023-03-20 21:23:10 -05:00
Alex Gleason fb8d543f7c
Redirect group statuses to a custom path 2023-03-20 20:57:49 -05:00
Alex Gleason b87af6a71c
AuthorizeRejectButtons: fix styles, make less fragile 2023-03-20 20:11:21 -05:00
Alex Gleason 3a12b316d9
GroupPage: add pending members counter 2023-03-20 20:02:58 -05:00
Alex Gleason 9ca384dcd7
Card: fix back button not having a rounded border 2023-03-20 19:37:46 -05:00
Alex Gleason 4f5866d43f
CHANGELOG: authorize/reject buttons 2023-03-20 19:33:29 -05:00
Alex Gleason 5774516ea0
Reorganize GroupMembershipRequests a little 2023-03-20 19:32:24 -05:00
Alex Gleason d4e9fddd02
Update usage of AuthorizeRejectButtons in group membership requests 2023-03-20 19:24:06 -05:00
Alex Gleason 7a06c7f92c
Use AuthorizeReject buttons for follow requests 2023-03-20 19:23:11 -05:00
Alex Gleason 28f5a88848
Use AuthorizeReject buttons for account approval 2023-03-20 19:22:55 -05:00
Alex Gleason 4de8926445
IAuthorizeRejectButtons: simplify component 2023-03-20 19:22:00 -05:00
Alex Gleason f9ab9a45c2
AuthorizeRejectButtons: improve style of result message 2023-03-20 18:49:41 -05:00
Alex Gleason fe64f9f84b
AuthorizeRejectButtons: improve button styles 2023-03-20 18:35:31 -05:00
Alex Gleason 7c7855e7a1
Groups: make authorize/reject use component state, update designs 2023-03-20 17:46:10 -05:00
Alex Gleason 1d9ed41fec
Add AuthorizeRejectButtons component 2023-03-20 17:45:52 -05:00
marcin mikołajczak 282afaa47f Merge branch 'use-groups-condition' into 'develop'
Do not make requests to api/v1/groups if feature not available

See merge request soapbox-pub/soapbox!2363
2023-03-20 21:57:35 +00:00
marcin mikołajczak 7329c0bf25 Do not make requests to api/v1/groups if fffeature not available
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-20 22:42:27 +01:00
Alex Gleason ca9a41f102
Use EntityStore for pending group requests 2023-03-20 16:41:12 -05:00
Chewbacca babaa979f5 Merge branch 'move-mutations-to-entities' into 'develop'
Move Group mutations to entities

See merge request soapbox-pub/soapbox!2368
2023-03-20 21:35:37 +00:00
Alex Gleason 143a9eda44
Use PendingItemsRow for pending members, pass a prop to control its size 2023-03-20 16:26:40 -05:00
Alex Gleason f6b28dd9c3
Abstract PendingItemsRow into its own component 2023-03-20 16:09:19 -05:00
Alex Gleason 3c06ba734b
Display pending counter in group member list 2023-03-20 16:03:41 -05:00
Alex Gleason d08178f5fc
Groups: use entity store for pending requests 2023-03-20 15:54:06 -05:00
Alex Gleason 28a69ad88b
Ensure group_visibility param is passed when creating group 2023-03-20 15:30:13 -05:00
Chewbacca e46a7e8f4a Merge branch 'promote-to-admin' into 'develop'
Move Promote/Demote admin into entity store

See merge request soapbox-pub/soapbox!2359
2023-03-20 20:08:51 +00:00
Chewbacca 8b478c939a Revert change 2023-03-20 16:08:29 -04:00
Alex Gleason 396f6ada1a Merge branch 'emoji-floating-ui' into 'develop'
Emoji floating ui

Closes #1390 and #1398

See merge request soapbox-pub/soapbox!2367
2023-03-20 20:03:41 +00:00
Chewbacca e42e0577f4 Move Group mutations to entities 2023-03-20 15:41:18 -04:00
Chewbacca 4a6433433f Update translations 2023-03-20 15:41:12 -04:00
Chewbacca 4985db7dea Update group roles to owner/admin/user 2023-03-20 15:41:12 -04:00
Chewbacca 89bdc9b4a1 Move Promote/Demote admin into entity store 2023-03-20 15:41:12 -04:00
Alex Gleason ea4f707413
Fix offset of chat reaction wrapper 2023-03-20 13:57:29 -05:00
Alex Gleason bc457b61d1 Merge branch 'edit-group' into 'develop'
Edit group

See merge request soapbox-pub/soapbox!2357
2023-03-20 18:41:52 +00:00
Alex Gleason f8b20858a3
Chats: fix crash in emoji autosuggest 2023-03-19 19:59:46 -05:00
Alex Gleason 67ffe9609f
ChatTextarea: pass ref to child
Fixes https://gitlab.com/soapbox-pub/soapbox/-/issues/1390
2023-03-19 18:03:44 -05:00
Alex Gleason 47561e5c01
Enable custom emoji reacts on custom Pleroma forks 2023-03-19 17:53:14 -05:00
Alex Gleason 5c7c0ea1dd
EmojiSelector: switch to floating-ui 2023-03-19 17:52:45 -05:00
Alex Gleason 2b75dcacd2
EmojiPickerDropdownContainer: switch to floating-ui 2023-03-19 17:24:39 -05:00
Alex Gleason 9dc12f0994 Merge branch 'changelog' into 'develop'
Update CHANGELOG

See merge request soapbox-pub/soapbox!2365
2023-03-19 20:48:02 +00:00
Alex Gleason f7c7b6ce6c
Update CHANGELOG 2023-03-19 15:47:40 -05:00
Alex Gleason da7284212e Merge branch 'group-svg' into 'develop'
Delete proprietary groups image

See merge request soapbox-pub/soapbox!2364
2023-03-19 20:40:34 +00:00
Alex Gleason 813fd7f8ee
Delete proprietary groups image 2023-03-19 15:39:58 -05:00
marcin mikołajczak b62db891fe Merge branch 'mkljczk-develop-patch-27878' into 'develop'
Update CHANGELOG.md

See merge request soapbox-pub/soapbox!2362
2023-03-19 20:15:28 +00:00
marcin mikołajczak 9c80a50b95 Merge branch 'pending-status-gap' into 'develop'
Add missing gap to PendingStatus

See merge request soapbox-pub/soapbox!2361
2023-03-19 19:50:27 +00:00
marcin mikołajczak 8634c5f91e Update CHANGELOG.md 2023-03-19 19:26:17 +00:00
marcin mikołajczak 049554db84 Add missing gap to PendingStatus
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-19 20:23:36 +01:00
marcin mikołajczak 4124b85ede Merge branch 'custom-emoji-reacts' into 'develop'
Support custom emoji reacts

See merge request soapbox-pub/soapbox!2360
2023-03-19 19:03:53 +00:00
marcin mikołajczak 38c99dbc48 Add tests from custom reacts
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-19 19:22:05 +01:00
marcin mikołajczak 09a0a36935 Update tests
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-18 13:27:27 +01:00
marcin mikołajczak 179eb7fc99 Fix preview in reactions modal
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-18 11:55:00 +01:00
marcin mikołajczak 8b81838f2f Support custom emoji reacts
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-18 00:07:18 +01:00
Alex Gleason c0a22205f7
Fix GroupActionButton test 2023-03-17 16:14:23 -05:00
Alex Gleason 3a94736285 Merge branch 'store-optimistic-delete' into 'develop'
EntityStore: optimistic deletion

See merge request soapbox-pub/soapbox!2356
2023-03-17 20:40:55 +00:00
Alex Gleason e6621a802b
Make popular and suggested groups share the Group store 2023-03-16 13:18:36 -05:00
Alex Gleason 181bf23c34
Importer: use EntityStore enums 2023-03-16 13:15:00 -05:00
Alex Gleason c51870af6e
Update some more groups stuff to use entities 2023-03-15 19:26:37 -05:00
Alex Gleason 1518e88904
Retrofit old Group actions to EntityStore 2023-03-15 18:37:50 -05:00
Alex Gleason 5871abd786
Make "Manage Group" use the EntityStore 2023-03-15 17:59:37 -05:00
Alex Gleason 7fffe59fb9
Allow "owner" permissions on group pages 2023-03-15 17:26:07 -05:00
Alex Gleason 1ab9b1d75c
EntityStore: optimistic deletion 2023-03-15 16:52:09 -05:00
Chewbacca 709edaefad Merge branch 'block-group-members' into 'develop'
Use Entity Hooks for Blocking Group members

See merge request soapbox-pub/soapbox!2353
2023-03-15 20:42:40 +00:00
Chewbacca 41ab40485e Merge branch 'renovate/floating-ui-react-0.x' into 'develop'
fix(deps): update dependency @floating-ui/react to ^0.21.0

See merge request soapbox-pub/soapbox!2348
2023-03-15 20:42:27 +00:00
Alex Gleason a83cfe7ddd Merge branch 'entity-actions-delete' into 'develop'
useEntityActions: ensure the delete gets dispatched

See merge request soapbox-pub/soapbox!2354
2023-03-15 20:08:51 +00:00
Chewbacca 0fe48840e1 Merge branch 'popovers' into 'develop'
Add Popovers component

See merge request soapbox-pub/soapbox!2352
2023-03-15 20:06:50 +00:00
Alex Gleason 74ebd560e6
Revert useEntity array changes, do that in the schema parser 2023-03-15 14:19:13 -05:00
Alex Gleason 602a670b2e
useEntityActions: ensure the delete gets dispatched 2023-03-15 14:04:29 -05:00
Alex Gleason 79aa8e210f Merge branch 'weblate-soapbox-pub-soapbox' into 'develop'
Translations update from Hosted Weblate

See merge request soapbox-pub/soapbox!2350
2023-03-15 19:02:36 +00:00
Chewbacca 6b30671875 Add Account entity and improve Block/Ban support for Groups 2023-03-15 14:55:43 -04:00
Chewbacca a99a7b2af5 Improve focus design for Danger buttons 2023-03-15 14:55:43 -04:00
Chewbacca 9dde71716f Improve DropdownMenu API 2023-03-15 14:55:43 -04:00
Chewbacca 20ccd26a6e Update Entity Store with bug fixes 2023-03-15 14:55:43 -04:00
Chewbacca 283935e837 Add popover component 2023-03-15 14:55:26 -04:00
gallegonovato bbda49a31c
Translated using Weblate (Spanish)
Currently translated at 100.0% (1520 of 1520 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/es/
2023-03-15 19:55:03 +01:00
Poesty Li 471f275dcb
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1520 of 1520 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-15 19:55:03 +01:00
Hosted Weblate c5a548fa83
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/
2023-03-15 19:55:03 +01:00
Poesty Li e28e12cd60
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1520 of 1520 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-15 19:55:03 +01:00
gallegonovato c9bd4291bb
Translated using Weblate (Spanish)
Currently translated at 100.0% (1520 of 1520 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/es/
2023-03-15 19:55:03 +01:00
Chewbacca af69c7564e Merge branch 'group-avatar-ring' into 'develop'
Add GroupAvatar component

See merge request soapbox-pub/soapbox!2349
2023-03-15 18:54:47 +00:00
Alex Gleason 822ab987a1 Merge branch 'create-group-hook' into 'develop'
Add useEntityActions hooks

See merge request soapbox-pub/soapbox!2351
2023-03-15 18:54:28 +00:00
Alex Gleason 463dcd2c1e
Merge remote-tracking branch 'origin/develop' into create-group-hook 2023-03-14 14:56:46 -05:00
Chewbacca c6c12fa60f Merge branch 'group-composer' into 'develop'
Update Group Members to use Entity Store

See merge request soapbox-pub/soapbox!2342
2023-03-14 19:31:52 +00:00
Alex Gleason ac76af41b2
Add preliminary useEntityActions hook 2023-03-14 14:24:11 -05:00
Chewbacca c8a4d63fc8 Add GroupAvatar component 2023-03-14 15:17:05 -04:00
Chewbacca 7070630eaf useVersion -> useBackend 2023-03-14 15:16:01 -04:00
Chewbacca 821b90c372 Add pages for Popular / Suggested Groups 2023-03-14 15:16:01 -04:00
Chewbacca 1b542c3ed7 Use Entities enum 2023-03-14 15:16:01 -04:00
Chewbacca f4d2f42c01 Use new schema arg 2023-03-14 15:16:01 -04:00
Chewbacca 7be8218f0c Convert popular/suggested Groups to use Entities 2023-03-14 15:16:01 -04:00
Alex Gleason 50dadeb1b8 useEntities: support multiple list keys 2023-03-14 15:16:01 -04:00
Chewbacca 99b7a1bdd7 Fix i18n 2023-03-14 15:16:01 -04:00
Chewbacca 1d53f48904 Fix parser 2023-03-14 15:16:01 -04:00
Chewbacca 9d1c2df1a2 Use ZOD for group-members 2023-03-14 15:16:00 -04:00
Chewbacca 08f97a133e Update blankslate for Group Timeline 2023-03-14 15:15:26 -04:00
Chewbacca 8a36561ec8 Use entities with Group Members 2023-03-14 15:15:26 -04:00
Alex Gleason 11d06e6b6e useEntities: support multiple list keys 2023-03-14 15:15:26 -04:00
Alex Gleason 8f8807eb76
EntityStore: allow deleting entities 2023-03-14 14:14:48 -05:00
Soapbox Bot 3b1f1cf789 Update dependency @floating-ui/react to ^0.21.0 2023-03-14 18:09:10 +00:00
Chewbacca 7e74e215cc Merge branch 'fix-export' into 'develop'
Fix exporting of types

See merge request soapbox-pub/soapbox!2347
2023-03-14 17:50:06 +00:00
Alex Gleason fafd27d79a Merge branch 'renovate/fork-ts-checker-webpack-plugin-8.x' into 'develop'
Update dependency fork-ts-checker-webpack-plugin to v8

See merge request soapbox-pub/soapbox!2335
2023-03-14 17:33:32 +00:00
Chewbacca 3ca168dc8c Fix exporting of types 2023-03-14 13:10:00 -04:00
Alex Gleason 6ac57910bf Merge branch 'groupschema-tests' into 'develop'
Add group factory functions for tests, add a groupSchema test

See merge request soapbox-pub/soapbox!2344
2023-03-14 14:16:05 +00:00
Chewbacca e173418041 Merge branch 'update-group-comps' into 'develop'
Update Group component with Join buttons

See merge request soapbox-pub/soapbox!2330
2023-03-14 14:13:46 +00:00
Chewbacca 39d61eabda Merge branch 'entity-store-refactoring' into 'develop'
Entity store refactoring (improve performance, etc)

See merge request soapbox-pub/soapbox!2346
2023-03-14 14:12:14 +00:00
Alex Gleason 9df2bb4a86
EntityStore: add tests for reducer, improve types, ensure error gets added to state 2023-03-13 18:42:46 -05:00
Alex Gleason b93a299009
useEntities(): refactor into smaller performant selectors and hooks 2023-03-13 17:53:54 -05:00
Alex Gleason 8547aeb517
Add useGetState hook 2023-03-13 17:45:35 -05:00
marcin mikołajczak 8c6ce74c46 Merge branch 'fix-locale-parser' into 'develop'
Fix locale parser

Closes #1393

See merge request soapbox-pub/soapbox!2343
2023-03-13 22:27:22 +00:00
Alex Gleason a19b1e83a9
EntityStore: parse entities after fetch, not during render (performance) 2023-03-13 16:39:23 -05:00
Alex Gleason e9ae8d2c45
Fix filteredArray logic 2023-03-13 16:37:40 -05:00
Alex Gleason d0ceac9987
Pass zodSchema directly to entity hooks for safeParse validation 2023-03-13 16:23:11 -05:00
Alex Gleason d12078a687
Use group factory functions in tests instead of normalizers 2023-03-13 14:55:59 -05:00
marcin mikołajczak 61ece4d271 Merge remote-tracking branch 'takver/fix-locale-parser' into fix-locale-parser
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-13 20:44:09 +01:00
Chewbacca bced3d6632 Merge branch 'pending-groups' into 'develop'
Add support for pending Group Requests

See merge request soapbox-pub/soapbox!2327
2023-03-13 19:20:16 +00:00
Chewbacca 879ac883aa Merge branch 'my-groups-blankslate' into 'develop'
Update blankslate to allow Group Creation

See merge request soapbox-pub/soapbox!2326
2023-03-13 19:10:14 +00:00
Soapbox Bot fadceaac45 fix(deps): update dependency fork-ts-checker-webpack-plugin to v8 2023-03-13 19:08:19 +00:00
Alex Gleason d747e323c6
Add basic groupSchema test 2023-03-13 14:03:50 -05:00
Alex Gleason c3728dbddd Merge branch 'weblate-soapbox-pub-soapbox' into 'develop'
Translations update from Hosted Weblate

See merge request soapbox-pub/soapbox!2336
2023-03-13 18:29:09 +00:00
Alex Gleason 1922e889f7 Merge branch 'create-group' into 'develop'
Create group

See merge request soapbox-pub/soapbox!2325
2023-03-13 18:28:43 +00:00
Chewbacca 58527b0656 Update Group component with Join buttons 2023-03-13 14:27:35 -04:00
Chewbacca 737c43d847 Fix i18n 2023-03-13 14:27:21 -04:00
Chewbacca f21f72461a Add support for pending Group Requests 2023-03-13 14:27:21 -04:00
Chewbacca 83532aedba Update blankslate to allow Group Creation 2023-03-13 14:27:21 -04:00
Chewbacca cced90a780 Update blankslate to allow Group Creation 2023-03-13 14:26:42 -04:00
Poesty Li 466cf91b31
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1508 of 1508 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-13 19:08:29 +01:00
Hosted Weblate c3dd9515bf
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/
2023-03-13 19:08:29 +01:00
Poesty Li bd7710677f
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1502 of 1502 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-13 19:08:28 +01:00
gallegonovato 8baecde992
Translated using Weblate (Spanish)
Currently translated at 100.0% (1502 of 1502 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/es/
2023-03-13 19:08:28 +01:00
Hosted Weblate 43a204db50
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/
2023-03-13 19:08:28 +01:00
Alex Gleason a40222c2de Merge branch 'groups-zod' into 'develop'
Groups zod

See merge request soapbox-pub/soapbox!2338
2023-03-13 18:08:16 +00:00
Alex Gleason 607e6b1808
groupsSchema: refine --> transform 2023-03-13 12:05:56 -05:00
Chewbacca a9b79f72b4 Revert "Fix useGroupsPath test"
This reverts commit 487604b15a.
2023-03-13 13:02:41 -04:00
Chewbacca a0c67c9b6f Fix Zod parsing error 2023-03-13 13:02:37 -04:00
Alex Gleason 487604b15a
Fix useGroupsPath test 2023-03-13 11:54:22 -05:00
Alex Gleason 5278c8eb0f
Merge remote-tracking branch 'origin/develop' into groups-zod 2023-03-13 11:05:21 -05:00
Chewbacca 55bacbbf05 Merge branch 'group-actions' into 'develop'
Group actions

See merge request soapbox-pub/soapbox!2324
2023-03-13 16:01:34 +00:00
Chewbacca a71aaca719 Fix translations 2023-03-13 11:36:08 -04:00
Chewbacca bd4c99b697 Fix tests 2023-03-13 11:36:08 -04:00
Chewbacca 7ad2696f85 Move Join / Leave / Cancel group/request to mutations 2023-03-13 11:36:08 -04:00
Chewbacca 287fda6d6c Improve error handling for Groups Discover page 2023-03-13 11:36:08 -04:00
Chewbacca e7b3af5260 Merge branch 'fix-tests' into 'develop'
Fix mock in tests

See merge request soapbox-pub/soapbox!2341
2023-03-13 15:35:40 +00:00
Chewbacca 82da9ceeeb Fix mock in tests 2023-03-13 10:07:23 -04:00
marcin mikołajczak 5148d913a7 Merge branch 'follow-requests-styles' into 'develop'
Fix: Long handles don't get truncated in Follow Requests menu

Closes #1389

See merge request soapbox-pub/soapbox!2340
2023-03-13 11:10:27 +00:00
marcin mikołajczak ea6be269bb Fix: Long handles don't get truncated in Follow Requests menu
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-13 00:00:07 +01:00
Alex Gleason ef10e2a699 Merge branch 'test-fixes' into 'develop'
Upgrade testing-library deps for sanity, fix DurationSelector time logic, comment out 2 failing tests

See merge request soapbox-pub/soapbox!2339
2023-03-10 23:00:11 +00:00
Alex Gleason ccec7f43e5
DurationSelector: actually, don't even do weird date stuff at all, LOL 2023-03-10 15:07:25 -06:00
Alex Gleason bd49417210
Also, fix the variable names in DurationSelector 2023-03-10 15:04:44 -06:00
Alex Gleason 2b137c12cf
Comment out failing tests ¯\_(ツ)_/¯ 2023-03-10 15:00:53 -06:00
Alex Gleason de89a438cc
Make DurationSelector test work locally 2023-03-10 15:00:29 -06:00
Alex Gleason 4031e4624c
Upgrade testing-library deps for sanity 2023-03-10 15:00:21 -06:00
Alex Gleason 1af67c3a25
members_count will never be null 2023-03-10 13:46:20 -06:00
Alex Gleason 6a2c64ae45
groupSchema: catch emojis 2023-03-10 13:41:47 -06:00
Alex Gleason 3d2331d20b
Make useGroups hooks use zod parser, update group types 2023-03-10 13:36:00 -06:00
Alex Gleason 5e8c92ed4d
groupSchema: refine --> transform, fix type of members_count 2023-03-10 13:13:54 -06:00
Alex Gleason 6be8d4d46e
Add groups schemas with zod 2023-03-10 12:42:49 -06:00
Alex Gleason 37f5b35aab
Add zod 2023-03-10 11:35:18 -06:00
Alex Gleason a0c1bd84c9 Merge branch 'group-entities' into 'develop'
EntityStore: Groups

See merge request soapbox-pub/soapbox!2333
2023-03-10 17:22:55 +00:00
Alex Gleason cf541e83b3
Fix useGroupsPath test 2023-03-10 10:56:00 -06:00
marcin mikołajczak b1471be142 Merge branch 'filters-v2' into 'develop'
filters v2

See merge request soapbox-pub/soapbox!2321
2023-03-10 11:03:46 +00:00
marcin mikołajczak 51524118d4 Merge branch 'gallery-load-more' into 'develop'
Fix load more button height on account gallery page

See merge request soapbox-pub/soapbox!2318
2023-03-10 10:52:00 +00:00
Alex Gleason c55154daaf Merge branch 'renovate/testing-library-react-14.x' into 'develop'
Update dependency @testing-library/react to v14

See merge request soapbox-pub/soapbox!2332
2023-03-10 01:46:02 +00:00
Alex Gleason 00c00b31fc Merge branch 'compareDate' into 'develop'
Sort conversations by last status date rather than id

See merge request soapbox-pub/soapbox!2319
2023-03-10 01:45:18 +00:00
Alex Gleason 074c3429cd Merge branch 'develop-patch-51d8' into 'develop'
Dictate Pleroma Chat and Quote Post compatibility by advertised features in the api

See merge request soapbox-pub/soapbox!2334
2023-03-10 01:41:46 +00:00
rurai10 29b75a29f0 Update file features.ts 2023-03-10 00:15:45 +00:00
Alex Gleason be9d922047
Actually, do put relationships in their own list. And fix parsers not doing the right thing. 2023-03-09 15:35:50 -06:00
Alex Gleason 14a84e557c
Update useGroups queries with EntityStore improvements 2023-03-09 15:05:54 -06:00
Alex Gleason fa2884c11b
EntityStore: fetch with useEntity automatically, accept refetch opt 2023-03-09 15:05:27 -06:00
marcin mikołajczak 1d64f934d9 Merge remote-tracking branch 'soapbox/develop' into filters-v2 2023-03-09 21:49:57 +01:00
Alex Gleason ad583c89f8
EntityStore: allow passing an undefined endpoint (to skip fetch), prevent race conditions in isFetching 2023-03-09 14:44:54 -06:00
marcin mikołajczak 94d248fb79 Update README.md
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-09 21:39:31 +01:00
Alex Gleason a3b1f541bc
EntityStore: support staleTime option (automatically fetch) 2023-03-09 14:20:04 -06:00
Alex Gleason d883f2f5bd
Group hooks: use new parser opt 2023-03-09 12:36:20 -06:00
Alex Gleason 250b009635
EntityStore: allow passing a parser function to parse the entities 2023-03-09 12:32:50 -06:00
Alex Gleason 9964491da5
First draft of GroupRelationship entity hooks 2023-03-09 11:47:24 -06:00
Alex Gleason 8923e7b5d0
Combine group hooks into one useGroups file 2023-03-09 11:24:53 -06:00
Alex Gleason 4c6d13e4ef
Use EntityStore for Groups 2023-03-09 11:21:27 -06:00
Soapbox Bot 31351700e0 Update dependency @testing-library/react to v14 2023-03-09 17:09:36 +00:00
Alex Gleason f2983b96fb Merge branch 'weblate-soapbox-pub-soapbox' into 'develop'
Translations update from Hosted Weblate

See merge request soapbox-pub/soapbox!2329
2023-03-09 17:08:09 +00:00
Alex Gleason c492af7042
Merge remote-tracking branch 'origin/develop' into entity-store 2023-03-09 10:43:58 -06:00
Tassoman ae1287ae82
Translated using Weblate (Italian)
Currently translated at 99.8% (1486 of 1488 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/it/
2023-03-09 17:37:54 +01:00
Alex Gleason 68144e4f82 Merge branch 'renovate/eslint-plugin-jsdoc-40.x' into 'develop'
Update dependency eslint-plugin-jsdoc to v40

See merge request soapbox-pub/soapbox!2323
2023-03-09 16:37:48 +00:00
Alex Gleason bed26727c1
yarn i18n 2023-03-09 10:16:04 -06:00
oakes 332be25784 Sort conversations by last status date rather than id 2023-03-09 10:49:59 -05:00
Alex Gleason a8b0dc93f2 Merge branch 'nostr' into 'develop'
Truncate Nostr pubkeys in reply mentions

See merge request soapbox-pub/soapbox!2328
2023-03-09 02:16:05 +00:00
Alex Gleason d1531b832d
Truncate Nostr pubkeys in reply mentions 2023-03-08 19:56:24 -06:00
Alex Gleason c75ce58792
Fix instance test 2023-03-08 14:50:15 -06:00
Alex Gleason 01343bbe0a
Add copy and share links to group confirmation step 2023-03-08 14:46:24 -06:00
Alex Gleason 2a9f05a765
Create Group: add info items to confirmation step 2023-03-08 14:10:09 -06:00
Alex Gleason d7f5e210d8
Groups: scaffold the confirmation step 2023-03-08 13:43:16 -06:00
Alex Gleason 925509a985
Fix groups modal bailing too soon 2023-03-08 12:20:20 -06:00
Alex Gleason 63df638630
Create Group: enforce max limit on description and name 2023-03-08 12:00:28 -06:00
Alex Gleason 08014a678d Merge branch 'weblate-soapbox-pub-soapbox' into 'develop'
Translations update from Hosted Weblate

See merge request soapbox-pub/soapbox!2293
2023-03-08 04:33:30 +00:00
gallegonovato b9ac2084c2
Translated using Weblate (Spanish)
Currently translated at 100.0% (1488 of 1488 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/es/
2023-03-08 00:38:28 +01:00
marcin mikołajczak d969c91c76 Update filter preview
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-08 00:02:17 +01:00
Poesty Li 334f93f2b1
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1488 of 1488 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:15 +01:00
Poesty Li 1d94d2ec9f
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1488 of 1488 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:15 +01:00
Poesty Li 57da9102cf
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1488 of 1488 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:15 +01:00
Hosted Weblate f9523d7afd
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/
2023-03-06 19:46:15 +01:00
Poesty Li 050f4130bb
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1479 of 1479 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:15 +01:00
Isabell De Inschnitzel 3ef34b1695
Translated using Weblate (German)
Currently translated at 97.3% (1440 of 1479 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/de/
2023-03-06 19:46:15 +01:00
Poesty Li aca7bb63a5
Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (1476 of 1479 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:14 +01:00
Hosted Weblate 41a1923ca5
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/
2023-03-06 19:46:14 +01:00
marcin mikołajczak d2ca2da10a
Translated using Weblate (Polish)
Currently translated at 92.3% (1357 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/
2023-03-06 19:46:14 +01:00
Tassoman e7e3ef86a3
Translated using Weblate (Italian)
Currently translated at 100.0% (1470 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/it/
2023-03-06 19:46:14 +01:00
Simen f2eaccf0f2
Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (1470 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/nb_NO/
2023-03-06 19:46:14 +01:00
Simen e87bb3d0ae
Translated using Weblate (Norwegian Bokmål)
Currently translated at 79.5% (1169 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/nb_NO/
2023-03-06 19:46:14 +01:00
ruine 4e9e85a60b
Translated using Weblate (Japanese)
Currently translated at 82.7% (1217 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ja/
2023-03-06 19:46:14 +01:00
ruine 905c1a47ac
Translated using Weblate (Japanese)
Currently translated at 82.7% (1217 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ja/
2023-03-06 19:46:14 +01:00
marcin mikołajczak 4e779742fc
Translated using Weblate (Polish)
Currently translated at 92.3% (1357 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/pl/
2023-03-06 19:46:14 +01:00
Tassoman 3b3a7653b1
Translated using Weblate (Italian)
Currently translated at 100.0% (1470 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/it/
2023-03-06 19:46:14 +01:00
Oukiki Saleh 1e6be8fa0f
Translated using Weblate (Arabic)
Currently translated at 99.3% (1460 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
Oukiki Saleh d6d7398576
Translated using Weblate (Arabic)
Currently translated at 99.1% (1458 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
Oukiki Saleh edf3b093af
Translated using Weblate (Arabic)
Currently translated at 93.3% (1372 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
gallegonovato 95f4aee356
Translated using Weblate (Spanish)
Currently translated at 100.0% (1470 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/es/
2023-03-06 19:46:14 +01:00
Mr.Narsus f8e05013fd
Translated using Weblate (Arabic)
Currently translated at 91.9% (1351 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
Oukiki Saleh 08b59ea58f
Translated using Weblate (Arabic)
Currently translated at 91.9% (1351 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
Mr.Narsus 483aa96b33
Translated using Weblate (Arabic)
Currently translated at 89.3% (1313 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
Oukiki Saleh fce046df8f
Translated using Weblate (Arabic)
Currently translated at 89.3% (1313 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:14 +01:00
Oukiki Saleh 5ab98da220
Translated using Weblate (Arabic)
Currently translated at 89.3% (1313 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:13 +01:00
Mr.Narsus 4e8130667a
Translated using Weblate (Arabic)
Currently translated at 89.3% (1313 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:13 +01:00
Mr.Narsus 725750ca7d
Translated using Weblate (Arabic)
Currently translated at 89.3% (1313 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:13 +01:00
Oukiki Saleh 3f13f8e370
Translated using Weblate (Arabic)
Currently translated at 89.3% (1313 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:13 +01:00
Tassoman 605ea95ee4
Translated using Weblate (Italian)
Currently translated at 98.2% (1445 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/it/
2023-03-06 19:46:13 +01:00
Oukiki Saleh f9541b5c52
Translated using Weblate (Arabic)
Currently translated at 88.2% (1297 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/ar/
2023-03-06 19:46:13 +01:00
Poesty Li 63a42aac67
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1470 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:13 +01:00
Poesty Li fb1c36b1c8
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1470 of 1470 strings)

Translation: Soapbox/Soapbox
Translate-URL: https://hosted.weblate.org/projects/soapbox-pub/soapbox/zh_Hans/
2023-03-06 19:46:13 +01:00
Alex Gleason ca9e59b56b Merge branch 'chat-multi-upload' into 'develop'
Chats: allow uploading multiple attachments at once (if the backend supports it)

See merge request soapbox-pub/soapbox!2313
2023-03-06 18:46:01 +00:00
Alex Gleason 65d1c66aad
Add group icon to create screen 2023-03-06 12:42:13 -06:00
Alex Gleason d16bce0ecc
Merge remote-tracking branch 'origin/develop' into create-group 2023-03-06 12:10:06 -06:00
Chewbacca 4e2213aba8 Merge branch 'my-groups' into 'develop'
Add Trending and Suggested Groups to discovery

See merge request soapbox-pub/soapbox!2312
2023-03-06 16:44:11 +00:00
Chewbacca 721b5dafcd Merge branch 'group-search' into 'my-groups'
Add support for Group search

See merge request soapbox-pub/soapbox!2314
2023-03-06 16:25:07 +00:00
Chewbacca 31653a5a54 Merge branch 'default-group-tabs' into 'group-search'
Use Groups Discovery if user has no groups

See merge request soapbox-pub/soapbox!2317
2023-03-06 16:04:44 +00:00
Chewbacca bdaf6e4cd6 Merge branch 'group-profile-header' into 'default-group-tabs'
Improve Group Header with latest designs

See merge request soapbox-pub/soapbox!2320
2023-03-06 15:45:42 +00:00
Soapbox Bot 266dd3d110 Update dependency eslint-plugin-jsdoc to v40 2023-03-06 05:10:38 +00:00
Alex Gleason a8c4be01ec Merge branch 'renovate/floating-ui-react-0.x' into 'develop'
Update dependency @floating-ui/react to ^0.20.0

See merge request soapbox-pub/soapbox!2322
2023-03-06 04:38:17 +00:00
marcin mikołajczak 1d4d9c2732 Filters expiration, restyle filters list, fix keywords deletion
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-05 19:49:40 +01:00
Soapbox Bot 3c336cbeb4 Update dependency @floating-ui/react to ^0.20.0 2023-03-05 11:05:00 +00:00
marcin mikołajczak b54a466bfd Merge branch 'update-emoji-mart-2' into 'develop'
Update emoji mart

See merge request soapbox-pub/soapbox!2309
2023-03-05 10:05:08 +00:00
marcin mikołajczak af314ee55d Allow editing filters
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-04 21:22:59 +01:00
marcin mikołajczak ebe4f9373b Remove console.log
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-04 12:44:04 +01:00
marcin mikołajczak 4c92f581c4 Allow creating v2 filters
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-04 12:43:27 +01:00
marcin mikołajczak 4200fa2df4 filters v2
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-03 22:40:39 +01:00
marcin mikołajczak c9f2cc0ae2 Hide emoji-mart preview footer
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-02 23:38:17 +01:00
marcin mikołajczak 1f6328c9c6 Fix emoji picker button color
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-02 23:35:56 +01:00
Chewbacca 3cc4f8b64b Improve Group Header with latest designs 2023-03-02 14:42:45 -05:00
Alex Gleason 55c8887a08
Small design tweaks for create group modal 2023-03-02 12:17:25 -06:00
Alex Gleason d3d363e12f
Allow all permissions if unset 2023-03-02 10:28:31 -06:00
marcin mikołajczak 2ce98055d8 Fix load more button height on account gallery page
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-01 21:02:04 +01:00
marcin mikołajczak eb93cb39fd Fix emoji selector on touchscreen
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-03-01 20:27:16 +01:00
Chewbacca 8fd3b99887 Use Groups Discovery if user has no groups 2023-03-01 14:16:09 -05:00
Chewbacca 01dfbad7bc Add i18n keys to en.json 2023-03-01 11:18:35 -05:00
Chewbacca 0b7a2ac19b Add support for i18n in Group Search 2023-03-01 10:40:07 -05:00
Chewbacca d6d7807807 Add tests for RecentSearches 2023-03-01 09:43:30 -05:00
Alex Gleason aad7df89a5 Merge branch 'pagination' into 'develop'
Fix conversation list pagination

See merge request soapbox-pub/soapbox!2316
2023-02-28 20:42:26 +00:00
oakes f1a14efc58 Remove unnecessary equality test 2023-02-28 15:30:01 -05:00
oakes 1b00de14a6 Fix conversation list pagination 2023-02-28 15:24:04 -05:00
Chewbacca 5acc231cda Add tests for Search component 2023-02-28 15:03:03 -05:00
marcin mikołajczak 277045c7a1 Remove custom emojis from reaction picker
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-28 20:52:15 +01:00
marcin mikołajczak d6732955de Merge remote-tracking branch 'soapbox/develop' into update-emoji-mart-2 2023-02-28 20:48:21 +01:00
marcin mikołajczak 9aef41eab1 Cleanup
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-28 19:13:34 +01:00
marcin mikołajczak e6d6ac6d44 Update en.json
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-28 18:59:32 +01:00
Alex Gleason f450c42048 Merge branch 'i18n-fix' into 'develop'
Add `yarn i18n` command to fix translation files

See merge request soapbox-pub/soapbox!2315
2023-02-28 17:13:56 +00:00
marcin mikołajczak dfa5d3ec8e Restore icon picker
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-28 18:04:24 +01:00
Alex Gleason 18bcd1c084
Add `yarn i18n` command to fix translation files 2023-02-28 10:13:53 -06:00
Alex Gleason a6c5d468f4
Enable groups for v.build === UNRELEASED 2023-02-28 10:05:23 -06:00
Chewbacca e7897228c6 Add support for Group search 2023-02-28 10:26:27 -05:00
Alex Gleason 83dab22371
Chats: allow uploading multiple attachments at once (if the backend supports it) 2023-02-27 09:59:00 -06:00
Chewbacca 0414c36a1e Add Trending and Suggested Groups to discovery 2023-02-27 08:26:59 -05:00
marcin mikołajczak 01a4e7370f Types, update styles
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-26 20:34:57 +01:00
marcin mikołajczak 2bbbcd625e WIP
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-26 19:29:37 +01:00
Alex Gleason b7c1d7d44a Merge branch 'media-rounded' into 'develop'
Improve rounded courners in MediaGallery and Chats

See merge request soapbox-pub/soapbox!2310
2023-02-24 16:06:40 +00:00
Alex Gleason 1b020b2a9b
Improve rounded courners in MediaGallery and Chats 2023-02-23 16:05:24 -06:00
marcin mikołajczak 528acb8ac5 Merge remote-tracking branch 'soapbox/develop' into update-emoji-mart
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-23 17:42:31 +01:00
marcin mikołajczak 5a90bb4456 Merge branch 'mkljczk-develop-patch-61732' into 'develop'
Compose: Only send group_id when not null

Closes rebased#184

See merge request soapbox-pub/soapbox!2307
2023-02-22 19:09:23 +00:00
marcin mikołajczak 28d84dedff Compose: Only send group_id when not null 2023-02-22 17:35:48 +00:00
Alex Gleason 6a3618da9a Merge branch 'docker-release-only' into 'develop'
GitLab CI: only run Docker job when a tag is pushed

See merge request soapbox-pub/soapbox!2299
2023-02-21 17:10:07 +00:00
Alex Gleason 02cf175e1f Merge branch 'empty-p' into 'develop'
Replace `<p></p>` with empty string in chats and statuses

See merge request soapbox-pub/soapbox!2306
2023-02-21 16:38:14 +00:00
Alex Gleason dc8952ad18
Replace `<p></p>` with empty string in chats and statuses 2023-02-21 09:00:16 -06:00
Alex Gleason 6413bed23f Merge branch 'renovate/tabler-icons-2.x' into 'develop'
Update dependency @tabler/icons to v2

See merge request soapbox-pub/soapbox!2218
2023-02-20 18:05:26 +00:00
Alex Gleason 93f873fce9
Tabler: ballon.svg --> balloon.svg 2023-02-20 11:37:06 -06:00
marcin mikołajczak eaa060c4bd Merge branch 'audio-styles' into 'develop'
Fix: audio player track position opacity missing

Closes #1381

See merge request soapbox-pub/soapbox!2302
2023-02-19 21:01:28 +00:00
marcin mikołajczak 9d6c698d31 Fix: audio player track position opacity missing
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-19 20:23:20 +01:00
miklobit eb188b0dfa Add custom logo 2023-02-18 15:06:29 +01:00
Alex Gleason d7c9c035a2 Merge branch 'alexgleason-develop-patch-82538' into 'develop'
Remove groups from changelog

See merge request soapbox-pub/soapbox!2301
2023-02-17 12:58:50 +00:00
Alex Gleason c6d89fae38 Remove groups from changelog 2023-02-17 12:58:13 +00:00
Alex Gleason 52b24bb013 Merge branch 'alexgleason-develop-patch-02881' into 'develop'
Update CHANGELOG.md

See merge request soapbox-pub/soapbox!2300
2023-02-16 04:37:42 +00:00
Alex Gleason c9285c7abe Update CHANGELOG.md 2023-02-16 04:37:11 +00:00
Alex Gleason 09baa262f9
GitLab CI: only run Docker job when a tag is pushed 2023-02-15 19:57:40 -06:00
Alex Gleason 10c24f01d9 Merge branch 'fix-react-icons' into 'develop'
Fix Emoji Icon Positioning

Closes #1363

See merge request soapbox-pub/soapbox!2297
2023-02-16 01:52:51 +00:00
marcin mikołajczak b3585bb348 Merge branch 'eslint-rules' into 'develop'
Change ESLint rules, lint

See merge request soapbox-pub/soapbox!2298
2023-02-16 00:06:57 +00:00
marcin mikołajczak 81de0014d3 Change ESLint rules, lint
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-16 00:12:02 +01:00
Alex Gleason 2e27886230 Alex's suggestion (brap) 2023-02-15 21:34:26 +00:00
matty 4b99ab7d35 fixes the stuff 2023-02-15 16:14:03 -05:00
Soapbox Bot a6b96c88aa Update dependency @tabler/icons to v2 2023-02-15 19:09:14 +00:00
Alex Gleason 27500193d8
EntityStore: incorporate Notifications, go back to using POJOs instead of Maps 2022-12-04 18:54:54 -06:00
Alex Gleason f7bfc40b70
EntityStore: proper pagination support 2022-12-04 17:53:56 -06:00
Alex Gleason 52059f6f37
EntityStore: add request/success/fail actions 2022-12-04 17:26:28 -06:00
Alex Gleason 3b067c6fab
Scaffold entity store library 2022-12-04 17:05:01 -06:00
Alex Gleason 8534cabc0a
Fix ComposeForm collapsing when clicking within emoji picker 2022-07-13 20:41:39 -05:00
Alex Gleason a8ebbc15c8
EmojiPickerDropdown: shrink emoji size, cleanup 2022-07-13 20:37:28 -05:00
Alex Gleason 26b5ca8b6e
Fix linter errors 2022-07-11 15:19:37 -05:00
Alex Gleason 00802b01e9
EmojiPicker: fix asset paths 2022-07-11 15:09:41 -05:00
ewwwwwwww 3879dad039 scroll fix 2022-07-10 04:42:22 -07:00
ewwwwwwww a1f0f75f60 abstracted dropdown so it can be reused 2022-07-10 02:06:37 -07:00
ewwwwwwww b8a335a166 add comments and fix index 2022-07-09 16:32:34 -07:00
ewwwwwwww 63ee482982 oops 2022-07-09 15:37:13 -07:00
ewwwwwwww 3725db9789 oops 2022-07-09 15:36:24 -07:00
ewwwwwwww 540b28364b oops 2022-07-09 15:35:50 -07:00
ewwwwwwww 317672e6ec initial changes for fixing image locations 2022-07-09 15:31:14 -07:00
Alex Gleason b7b0ad06dc
Merge remote-tracking branch 'origin/develop' into update-emoji-mart 2022-07-09 15:21:17 -05:00
ewwwwwwww 34d77df8d7 fix lint 2022-07-09 12:16:42 -07:00
ewwwwwwww d5ca6b58fb i18n support 2022-07-09 11:58:09 -07:00
ewwwwwwww 403db1d46e mobile fixes 2022-07-09 10:52:08 -07:00
ewwwwwwww 9770209f00 lint fixes 2022-07-09 10:02:21 -07:00
ewwwwwwww 2f579839d8 rebased 2022-07-09 09:03:22 -07:00
ewwwwwwww 1249b24ba4 fix all tests 2022-07-09 08:33:14 -07:00
ewwwwwwww f3c350aeef fix some texts 2022-07-09 08:33:14 -07:00
ewwwwwwww 8ef60cdf0b add angry note about twemoji breaking spec 2022-07-09 08:33:14 -07:00
ewwwwwwww 13e76b8022 unqualified fixes 2022-07-09 08:33:14 -07:00
ewwwwwwww b1f5902397 added tests 2022-07-09 08:33:14 -07:00
ewwwwwwww a6e56b131c unicode fixes 2022-07-09 08:33:14 -07:00
ewwwwwwww 4a73412142 small fix 2022-07-09 08:33:14 -07:00
ewwwwwwww 16f06cd554 small fix 2022-07-09 08:33:14 -07:00
ewwwwwwww 1962c6544e emoji-picker fixes 2022-07-09 08:33:14 -07:00
ewwwwwwww 84267d3ffe fix emoji-picker key input 2022-07-09 08:33:14 -07:00
ewwwwwwww 41eebfdbda remove dead code 2022-07-09 08:33:14 -07:00
ewwwwwwww 891ce09443 small fixes 2022-07-09 08:33:14 -07:00
ewwwwwwww 0de246fcae remove old todo 2022-07-09 08:33:14 -07:00
ewwwwwwww c183ab0f06 fix some tests 2022-07-09 08:33:14 -07:00
ewwwwwwww f10001fbfd fix some tests 2022-07-09 08:33:13 -07:00
ewwwwwwww 9d0a3b7a69 remove cheerio and add custom html parser 2022-07-09 08:31:31 -07:00
ewwwwwwww a2fab1285d fix types 2022-07-09 08:31:31 -07:00
ewwwwwwww bd9a33201a convert type to union 2022-07-09 08:31:31 -07:00
ewwwwwwww 8d8cf53ac4 remove console log 2022-07-09 08:31:31 -07:00
ewwwwwwww f08d43ecb3 small fixes 2022-07-09 08:31:31 -07:00
ewwwwwwww e2d6a5d41d remove useless file 2022-07-09 08:31:31 -07:00
ewwwwwwww 485095e502 fixed types 2022-07-09 08:31:31 -07:00
ewwwwwwww bfa8331f96 new emoji search 2022-07-09 08:31:31 -07:00
ewwwwwwww 36d6275107 type fixes 2022-07-09 08:31:31 -07:00
ewwwwwwww d98371bf6a migrate emoji types 2022-07-09 08:31:27 -07:00
ewwwwwwww 6ded0afc1e remove files 2022-07-09 08:30:44 -07:00
ewwwwwwww ad523574e2 small fixes 2022-07-09 08:30:44 -07:00
ewwwwwwww d86b7ba333 new emojifier 2022-07-09 08:30:44 -07:00
ewwwwwwww 88f5739769 new emojifier 2022-07-09 08:30:44 -07:00
ewwwwwwww a8e7e10f61 new emojifier 2022-07-09 08:30:44 -07:00
ewwwwwwww 89bba0e2e3 lint fixes 2022-07-09 08:30:44 -07:00
ewwwwwwww f8bd30a5f7 remove consolelog 2022-07-09 08:30:44 -07:00
ewwwwwwww eeb30b5492 migrated emoji picker to typescript 2022-07-09 08:30:44 -07:00
ewwwwwwww 4b7876f1a6 enabled async component 2022-07-09 08:30:44 -07:00
ewwwwwwww 170d3f748e more emoji fixes 2022-07-09 08:30:44 -07:00
ewwwwwwww 2727fb8f20 lint fixes 2022-07-09 08:30:44 -07:00
Shevek 6a3e66bc7e properly fallback on locale 2021-11-08 21:24:07 -05:00
602 zmienionych plików z 14732 dodań i 6140 usunięć

Wyświetl plik

@ -56,6 +56,7 @@ module.exports = {
},
polyfills: [
'es:all', // core-js
'fetch', // not polyfilled, but ignore it
'IntersectionObserver', // npm:intersection-observer
'Promise', // core-js
'ResizeObserver', // npm:resize-observer-polyfill
@ -260,12 +261,29 @@ module.exports = {
},
],
'@typescript-eslint/no-duplicate-imports': 'error',
'@typescript-eslint/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'none',
},
singleline: {
delimiter: 'comma',
},
},
],
'promise/catch-or-return': 'error',
'react-hooks/rules-of-hooks': 'error',
'tailwindcss/classnames-order': 'error',
'tailwindcss/classnames-order': [
'error',
{
classRegex: '^(base|container|icon|item|list|outer|wrapper)?[c|C]lass(Name)?$',
config: 'tailwind.config.cjs',
},
],
'tailwindcss/migration-from-tailwind-2': 'error',
},
overrides: [

Wyświetl plik

@ -157,11 +157,11 @@ docker:
# https://medium.com/devops-with-valentine/how-to-build-a-docker-image-and-push-it-to-the-gitlab-container-registry-from-a-gitlab-ci-pipeline-acac0d1f26df
script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
- docker build -t $CI_REGISTRY_IMAGE .
- docker push $CI_REGISTRY_IMAGE
only:
variables:
- $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
rules:
- if: $CI_COMMIT_TAG
interruptible: false
release:
stage: release

Wyświetl plik

@ -7,10 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Posts: Support posts filtering on recent Mastodon versions
- Reactions: Support custom emoji reactions
- Compatbility: Support Mastodon v2 timeline filters.
- Posts: Support dislikes on Friendica.
- UI: added a character counter to some textareas.
### Changed
- Posts: truncate Nostr pubkeys in reply mentions.
- Posts: upgraded emoji picker component.
- UI: unified design of "approve" and "reject" buttons in follow requests and waitlist.
### Fixed
- Posts: fixed emojis being cut off in reactions modal.
- Posts: fix audio player progress bar visibility.
- Posts: added missing gap in pending status.
- Compatibility: fixed quote posting compatibility with custom Pleroma forks.
- Profile: fix "load more" button height on account gallery page.
- 18n: fixed Chinese language being detected from the browser.
- Conversations: fixed pagination (Mastodon).
- Compatibility: fix version parsing for Friendica.
## [3.2.0] - 2023-02-15
@ -20,12 +36,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Posts: bot badge on statuses from bot accounts.
- Compatibility: improved browser support for older browsers.
- Events: allow to repost events in event menu.
- Groups: Initial support for groups.
- Profile: Add RSS link to user profiles.
- Reactions: adds support for reacting to chat messages.
- Groups: initial support for groups.
- Profile: add RSS link to user profiles.
- Posts: fix posts filtering.
- Chats: reset chat message field height after sending a message.
- Admin: allow to manage announcements.
@ -46,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- index.html: remove `referrer` meta tag so it doesn't conflict with backend's `Referrer-Policy` header.
- Modals: fix media modal automatically switching to video.
- Navigation: profile dropdown erratic behavior.
- Posts: fix posts filtering.
### Removed
- Admin: single user mode. Now the homepage can be redirected to any URL.

Wyświetl plik

@ -75,7 +75,7 @@ One disadvantage of this approach is that it does not help the software spread.
© Alex Gleason & other Soapbox contributors
© Eugen Rochko & other Mastodon contributors
© Trump Media & Technology Group
© Gab AI, Inc.
© Gab AI, Inc.
Soapbox is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by

Wyświetl plik

@ -2,4 +2,4 @@
- verified.svg - Created by Alex Gleason. CC0
Fediverse logo: https://en.wikipedia.org/wiki/Fediverse#/media/File:Fediverse_logo_proposal.svg
Fediverse logo: https://en.wikipedia.org/wiki/Fediverse#/media/File:Fediverse_logo_proposal.svg

Wyświetl plik

@ -1 +1,107 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95 95" width="100" height="100"><path d="M94.909 19.374C94.909 8.674 86.235 0 75.534 0c-10.647 0-19.28 8.591-19.365 19.217l-15.631 2.09c-1.961-6.007-7.598-10.35-14.258-10.35-8.284 0-15.002 6.716-15.002 15.002 0 6.642 4.321 12.267 10.303 14.24l-2.205 16.056c-10.66.049-19.285 8.7-19.285 19.37C.091 86.325 8.765 95 19.466 95c10.677 0 19.332-8.638 19.37-19.304l18.093-2.501c1.979 5.972 7.598 10.285 14.234 10.285 8.284 0 15.002-6.716 15.002-15.002 0-6.891-4.652-12.682-10.983-14.441l1.365-15.339c10.229-.53 18.363-8.966 18.363-19.324zM56.194 67.8l-18.116 2.505a19.39 19.39 0 0 0-13.312-13.3l2.205-16.077a14.98 14.98 0 0 0 14.27-14.222l15.655-2.094c1.894 6.757 7.351 12.009 14.225 13.612l-1.365 15.322c-7.4.688-13.224 6.753-13.562 14.254z" fill="#ffffff"/></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="svg2"
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
sodipodi:docname="soapbox-logo-white.svg"
xml:space="preserve"
version="1.1"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
viewBox="0 0 100 100"
width="100"
height="100"
inkscape:export-filename="/home/miklobit/Downloads/citizen4/logo/citizen4-logo-250px.png"
inkscape:export-xdpi="63.5"
inkscape:export-ydpi="63.5"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><sodipodi:namedview
id="namedview12"
bordercolor="#666666"
inkscape:pageshadow="2"
guidetolerance="10"
pagecolor="#ffffff"
gridtolerance="10"
inkscape:zoom="5.0135101"
objecttolerance="10"
borderopacity="1"
inkscape:current-layer="g1133"
inkscape:cx="54.253406"
inkscape:cy="42.086282"
inkscape:window-width="1920"
showgrid="false"
inkscape:pageopacity="0"
inkscape:window-height="1016"
inkscape:document-rotation="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-x="0"
inkscape:window-y="36"
inkscape:window-maximized="1"
units="mm"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px" />
<defs
id="defs4">
<style
id="style6"
type="text/css">
.fil0 {fill:black}
</style>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath932"><g
id="g936"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(40.327178,0,0,40.327178,-206.26309,-5.404074)">
<path
id="path934"
sodipodi:nodetypes="ccccc"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
d="M 4.25,1.3382 0.4955,2.4662 C 0.58759,5.2588 1.2884,8.6655 4.25,9.6618 7.2442,8.694 7.8774,5.2291 8.0045,2.4662 Z" />
</g></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath932-3"><g
id="g936-6"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(40.327178,0,0,40.327178,-206.26309,-5.404074)"><path
id="path934-7"
sodipodi:nodetypes="ccccc"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
d="M 4.25,1.3382 0.4955,2.4662 C 0.58759,5.2588 1.2884,8.6655 4.25,9.6618 7.2442,8.694 7.8774,5.2291 8.0045,2.4662 Z" /></g></clipPath>
</defs>
<metadata
id="metadata7"><rdf:RDF><cc:Work><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" /><dc:date>2023-02-18T14:20:55</dc:date><dc:source>https://soc.citizen4.eu</dc:source><dc:subject><rdf:Bag><rdf:li>citizen4</rdf:li><rdf:li>logo</rdf:li><rdf:li>shield</rdf:li></rdf:Bag></dc:subject><dc:creator><cc:Agent><dc:title>miklo</dc:title></cc:Agent></dc:creator><dc:description>Citizen4 logo</dc:description></cc:Work><cc:License
rdf:about="http://creativecommons.org/licenses/by-nc-sa/4.0/"><cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" /><cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" /><cc:prohibits
rdf:resource="http://creativecommons.org/ns#CommercialUse" /><cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /><cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" /></cc:License></rdf:RDF></metadata><g
inkscape:groupmode="layer"
id="g1133"
inkscape:label="citizen4"
style="display:inline;fill:#ffffff"
transform="translate(9.1709534,9.343974)"><g
id="g1149"
transform="matrix(0.28130772,0,0,0.28130772,-1.9206898,-6.7154381)"
style="fill:#ffffff"><path
id="path1127"
style="fill:#ffffff;fill-opacity:1;stroke-width:2.298"
d="m 233.61288,175.15307 h -30.0693 v -8.40148 h -35.71547 v -22.85127 h 35.71317 v -8.40148 h 30.0716 c 1.31445,0 2.42898,0.4596 3.34818,1.3765 0.9169,0.9215 1.3788,2.03832 1.3788,3.34818 v 30.20487 c 0,1.22484 -0.4596,2.32098 -1.3788,3.28154 -0.9192,0.95827 -2.03602,1.44314 -3.34818,1.44314 z m 18.90793,-30.07388 c 6.91237,0 10.37315,3.41253 10.37315,10.24447 0,6.83195 -3.45618,10.24217 -10.37315,10.24217 -6.82735,0 -10.24218,-3.41482 -10.24218,-10.24217 0,-6.82734 3.41483,-10.24447 10.24218,-10.24447 z M 70.322893,175.15307 h 30.069297 v -8.40148 h 35.71546 v -22.85127 h -35.71317 v -8.40148 H 70.322893 c -1.31446,0 -2.42898,0.4596 -3.34818,1.3765 -0.9169,0.9215 -1.3788,2.03832 -1.3788,3.34818 v 30.20487 c 0,1.22484 0.4596,2.32098 1.3788,3.28154 0.9192,0.95827 2.03602,1.44314 3.34818,1.44314 z m -18.90793,-30.07388 c -6.91237,0 -10.37315,3.41253 -10.37315,10.24447 0,6.83195 3.45618,10.24217 10.37315,10.24217 6.82735,0 10.24218,-3.41482 10.24218,-10.24217 0,-6.82734 -3.41483,-10.24447 -10.24218,-10.24447 z M 171.79501,73.680969 v 30.069301 h -8.40148 v 35.71546 h -22.85128 v -35.71317 h -8.40147 V 73.680969 c 0,-1.31445 0.45959,-2.42898 1.37649,-3.34818 0.9215,-0.9169 2.03832,-1.3788 3.34819,-1.3788 h 30.20487 c 1.22483,0 2.32097,0.4596 3.28153,1.3788 0.95827,0.9192 1.44315,2.03602 1.44315,3.34818 z m -30.07388,-18.90793 c 0,-6.91237 3.41252,-10.37315 10.24446,-10.37315 6.83195,0 10.24218,3.45618 10.24218,10.37315 0,6.82735 -3.41482,10.24218 -10.24218,10.24218 -6.82734,0 -10.24446,-3.41483 -10.24446,-10.24218 z m 30.07388,182.197911 v -30.06929 h -8.40148 v -35.71547 h -22.85128 v 35.71317 h -8.40147 v 30.07159 c 0,1.31446 0.45959,2.42898 1.37649,3.34818 0.9215,0.9169 2.03832,1.3788 3.34819,1.3788 h 30.20487 c 1.22483,0 2.32097,-0.4596 3.28153,-1.3788 0.95827,-0.9192 1.44315,-2.03602 1.44315,-3.34818 z m -30.07388,18.90793 c 0,6.91237 3.41252,10.37315 10.24446,10.37315 6.83195,0 10.24218,-3.45618 10.24218,-10.37315 0,-6.82735 -3.41482,-10.24218 -10.24218,-10.24218 -6.82734,0 -10.24446,3.41483 -10.24446,10.24218 z M 151.92079,0.52207567 0.51240486,46.01113 C 4.2261345,158.6288 32.487823,296.01139 151.92079,336.18936 272.66842,297.16072 298.20359,157.43109 303.32917,46.01113 Z" /></g></g></svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 812 B

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 6.7 KiB

Wyświetl plik

@ -1 +1,127 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95 95" width="100" height="100"><path d="M94.909 19.374C94.909 8.674 86.235 0 75.534 0c-10.647 0-19.28 8.591-19.365 19.217l-15.631 2.09c-1.961-6.007-7.598-10.35-14.258-10.35-8.284 0-15.002 6.716-15.002 15.002 0 6.642 4.321 12.267 10.303 14.24l-2.205 16.056c-10.66.049-19.285 8.7-19.285 19.37C.091 86.325 8.765 95 19.466 95c10.677 0 19.332-8.638 19.37-19.304l18.093-2.501c1.979 5.972 7.598 10.285 14.234 10.285 8.284 0 15.002-6.716 15.002-15.002 0-6.891-4.652-12.682-10.983-14.441l1.365-15.339c10.229-.53 18.363-8.966 18.363-19.324zM56.194 67.8l-18.116 2.505a19.39 19.39 0 0 0-13.312-13.3l2.205-16.077a14.98 14.98 0 0 0 14.27-14.222l15.655-2.094c1.894 6.757 7.351 12.009 14.225 13.612l-1.365 15.322c-7.4.688-13.224 6.753-13.562 14.254z" fill="#0482d8"/></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="svg2"
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
sodipodi:docname="soapbox-logo.svg"
xml:space="preserve"
version="1.1"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
viewBox="0 0 100 100"
width="100"
height="100"
inkscape:export-filename="/home/miklobit/Downloads/citizen4/logo/citizen4-logo-250px.png"
inkscape:export-xdpi="63.5"
inkscape:export-ydpi="63.5"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><sodipodi:namedview
id="namedview12"
bordercolor="#666666"
inkscape:pageshadow="2"
guidetolerance="10"
pagecolor="#ffffff"
gridtolerance="10"
inkscape:zoom="5.0135101"
objecttolerance="10"
borderopacity="1"
inkscape:current-layer="svg2"
inkscape:cx="54.253406"
inkscape:cy="42.086282"
inkscape:window-width="1920"
showgrid="false"
inkscape:pageopacity="0"
inkscape:window-height="1016"
inkscape:document-rotation="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-x="0"
inkscape:window-y="36"
inkscape:window-maximized="1"
units="mm"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px" />
<defs
id="defs4">
<style
id="style6"
type="text/css">
.fil0 {fill:black}
</style>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath932"><g
id="g936"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(40.327178,0,0,40.327178,-206.26309,-5.404074)">
<path
id="path934"
sodipodi:nodetypes="ccccc"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
d="M 4.25,1.3382 0.4955,2.4662 C 0.58759,5.2588 1.2884,8.6655 4.25,9.6618 7.2442,8.694 7.8774,5.2291 8.0045,2.4662 Z" />
</g></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath932-3"><g
id="g936-6"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
transform="matrix(40.327178,0,0,40.327178,-206.26309,-5.404074)"><path
id="path934-7"
sodipodi:nodetypes="ccccc"
style="fill:#ffffff;stroke:#000000;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none"
d="M 4.25,1.3382 0.4955,2.4662 C 0.58759,5.2588 1.2884,8.6655 4.25,9.6618 7.2442,8.694 7.8774,5.2291 8.0045,2.4662 Z" /></g></clipPath>
</defs>
<metadata
id="metadata7"><rdf:RDF><cc:Work><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" /><dc:date>2023-02-18T14:20:55</dc:date><dc:source>https://soc.citizen4.eu</dc:source><dc:subject><rdf:Bag><rdf:li>citizen4</rdf:li><rdf:li>logo</rdf:li><rdf:li>shield</rdf:li></rdf:Bag></dc:subject><dc:creator><cc:Agent><dc:title>miklo</dc:title></cc:Agent></dc:creator><dc:description>Citizen4 logo</dc:description></cc:Work><cc:License
rdf:about="http://creativecommons.org/licenses/by-nc-sa/4.0/"><cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" /><cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" /><cc:prohibits
rdf:resource="http://creativecommons.org/ns#CommercialUse" /><cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /><cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" /></cc:License></rdf:RDF></metadata><g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="shield"
style="display:inline"
transform="translate(9.1709534,9.343974)"><g
id="g912"
style="clip-rule:evenodd;fill:#003399;fill-opacity:1;fill-rule:evenodd;stroke:#888888;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
transform="matrix(11.344346,0,0,11.344346,-7.3976698,-21.749578)"><path
id="path910"
sodipodi:nodetypes="ccccc"
style="fill:#003399;fill-opacity:1;stroke:#888888;stroke-width:0.468608;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 4.25,1.3382 0.4955,2.4662 C 0.58759,5.2588 1.2884,8.6655 4.25,9.6618 7.2442,8.694 7.8774,5.2291 8.0045,2.4662 Z" /></g></g><g
inkscape:groupmode="layer"
id="g1133"
inkscape:label="citizen2"
style="display:inline"
transform="translate(9.1709534,9.343974)"><g
id="g1149"
transform="matrix(0.28130772,0,0,0.28130772,-1.9206898,-6.7154381)"><path
id="path1119"
style="fill:#ffcc00;fill-opacity:1;stroke-width:2.298"
d="m 171.79501,236.97095 v -30.06929 h -8.40148 v -35.71547 h -22.85128 v 35.71317 h -8.40147 v 30.07159 c 0,1.31446 0.45959,2.42898 1.37649,3.34818 0.9215,0.9169 2.03832,1.3788 3.34819,1.3788 h 30.20487 c 1.22483,0 2.32097,-0.4596 3.28153,-1.3788 0.95827,-0.9192 1.44315,-2.03602 1.44315,-3.34818 z m -30.07388,18.90793 c 0,6.91237 3.41252,10.37315 10.24446,10.37315 6.83195,0 10.24218,-3.45618 10.24218,-10.37315 0,-6.82735 -3.41482,-10.24218 -10.24218,-10.24218 -6.82734,0 -10.24446,3.41483 -10.24446,10.24218 z" /><path
id="path1121"
style="fill:#ffcc00;fill-opacity:1;stroke-width:2.298"
d="m 171.79501,73.680969 v 30.069301 h -8.40148 v 35.71546 h -22.85128 v -35.71317 h -8.40147 V 73.680969 c 0,-1.31445 0.45959,-2.42898 1.37649,-3.34818 0.9215,-0.9169 2.03832,-1.3788 3.34819,-1.3788 h 30.20487 c 1.22483,0 2.32097,0.4596 3.28153,1.3788 0.95827,0.9192 1.44315,2.03602 1.44315,3.34818 z m -30.07388,-18.90793 c 0,-6.91237 3.41252,-10.37315 10.24446,-10.37315 6.83195,0 10.24218,3.45618 10.24218,10.37315 0,6.82735 -3.41482,10.24218 -10.24218,10.24218 -6.82734,0 -10.24446,-3.41483 -10.24446,-10.24218 z" /><path
id="path1125"
style="fill:#ffcc00;fill-opacity:1;stroke-width:2.298"
d="m 70.322893,175.15307 h 30.069297 v -8.40148 h 35.71546 v -22.85127 h -35.71317 v -8.40148 H 70.322893 c -1.31446,0 -2.42898,0.4596 -3.34818,1.3765 -0.9169,0.9215 -1.3788,2.03832 -1.3788,3.34818 v 30.20487 c 0,1.22484 0.4596,2.32098 1.3788,3.28154 0.9192,0.95827 2.03602,1.44314 3.34818,1.44314 z m -18.90793,-30.07388 c -6.91237,0 -10.37315,3.41253 -10.37315,10.24447 0,6.83195 3.45618,10.24217 10.37315,10.24217 6.82735,0 10.24218,-3.41482 10.24218,-10.24217 0,-6.82734 -3.41483,-10.24447 -10.24218,-10.24447 z" /><path
id="path1127"
style="fill:#ffcc00;fill-opacity:1;stroke-width:2.298"
d="m 233.61288,175.15307 h -30.0693 v -8.40148 h -35.71547 v -22.85127 h 35.71317 v -8.40148 h 30.0716 c 1.31445,0 2.42898,0.4596 3.34818,1.3765 0.9169,0.9215 1.3788,2.03832 1.3788,3.34818 v 30.20487 c 0,1.22484 -0.4596,2.32098 -1.3788,3.28154 -0.9192,0.95827 -2.03602,1.44314 -3.34818,1.44314 z m 18.90793,-30.07388 c 6.91237,0 10.37315,3.41253 10.37315,10.24447 0,6.83195 -3.45618,10.24217 -10.37315,10.24217 -6.82735,0 -10.24218,-3.41482 -10.24218,-10.24217 0,-6.82734 3.41483,-10.24447 10.24218,-10.24447 z" /></g></g></svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 812 B

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 7.6 KiB

Wyświetl plik

@ -0,0 +1,16 @@
{
"note": "patriots 900000001",
"discoverable": true,
"id": "109989480368015378",
"domain": null,
"avatar": "https://media.covfefe.social/groups/avatars/109/989/480/368/015/378/original/50b0d899bc5aae13.jpg",
"avatar_static": "https://media.covfefe.social/groups/avatars/109/989/480/368/015/378/original/50b0d899bc5aae13.jpg",
"header": "https://media.covfefe.social/groups/headers/109/989/480/368/015/378/original/c5063b59f919cd4a.png",
"header_static": "https://media.covfefe.social/groups/headers/109/989/480/368/015/378/original/c5063b59f919cd4a.png",
"group_visibility": "everyone",
"created_at": "2023-03-08T00:00:00.000Z",
"display_name": "PATRIOT PATRIOTS",
"membership_required": true,
"members_count": 1,
"tags": []
}

Wyświetl plik

@ -228,7 +228,7 @@ const fetchAccountFail = (id: string | null, error: AxiosError) => ({
});
type FollowAccountOpts = {
reblogs?: boolean,
reblogs?: boolean
notify?: boolean
};

Wyświetl plik

@ -4,7 +4,8 @@ import throttle from 'lodash/throttle';
import { defineMessages, IntlShape } from 'react-intl';
import api from 'soapbox/api';
import { search as emojiSearch } from 'soapbox/features/emoji/emoji-mart-search-light';
import { isNativeEmoji } from 'soapbox/features/emoji';
import emojiSearch from 'soapbox/features/emoji/search';
import { tagHistory } from 'soapbox/settings';
import toast from 'soapbox/toast';
import { isLoggedIn } from 'soapbox/utils/auth';
@ -19,8 +20,8 @@ import { openModal, closeModal } from './modals';
import { getSettings } from './settings';
import { createStatus } from './statuses';
import type { Emoji } from 'soapbox/components/autosuggest-emoji';
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
import type { Emoji } from 'soapbox/features/emoji';
import type { AppDispatch, RootState } from 'soapbox/store';
import type { Account, APIEntity, Status, Tag } from 'soapbox/types/entities';
import type { History } from 'soapbox/types/history';
@ -277,7 +278,7 @@ const submitCompose = (composeId: string, routerHistory?: History, force = false
const idempotencyKey = compose.idempotencyKey;
const params = {
const params: Record<string, any> = {
status,
in_reply_to_id: compose.in_reply_to,
quote_id: compose.quote,
@ -289,9 +290,10 @@ const submitCompose = (composeId: string, routerHistory?: History, force = false
poll: compose.poll,
scheduled_at: compose.schedule,
to,
group_id: compose.privacy === 'group' ? compose.group_id : null,
};
if (compose.privacy === 'group') params.group_id = compose.group_id;
dispatch(createStatus(params, idempotencyKey, statusId)).then(function(data) {
if (!statusId && data.visibility === 'direct' && getState().conversations.mounted <= 0 && routerHistory) {
routerHistory.push('/messages');
@ -515,7 +517,9 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, composeId,
}, 200, { leading: true, trailing: true });
const fetchComposeSuggestionsEmojis = (dispatch: AppDispatch, getState: () => RootState, composeId: string, token: string) => {
const results = emojiSearch(token.replace(':', ''), { maxResults: 5 } as any);
const state = getState();
const results = emojiSearch(token.replace(':', ''), { maxResults: 5 }, state.custom_emojis);
dispatch(readyComposeSuggestionsEmojis(composeId, token, results));
};
@ -560,7 +564,7 @@ const selectComposeSuggestion = (composeId: string, position: number, token: str
let completion, startPosition;
if (typeof suggestion === 'object' && suggestion.id) {
completion = suggestion.native || suggestion.colons;
completion = isNativeEmoji(suggestion) ? suggestion.native : suggestion.colons;
startPosition = position - 1;
dispatch(useEmoji(suggestion));

Wyświetl plik

@ -25,7 +25,7 @@ const EMOJI_REACTS_FETCH_FAIL = 'EMOJI_REACTS_FETCH_FAIL';
const noOp = () => () => new Promise(f => f(undefined));
const simpleEmojiReact = (status: Status, emoji: string) =>
const simpleEmojiReact = (status: Status, emoji: string, custom?: string) =>
(dispatch: AppDispatch) => {
const emojiReacts: ImmutableList<ImmutableMap<string, any>> = status.pleroma.get('emoji_reactions') || ImmutableList();
@ -43,7 +43,7 @@ const simpleEmojiReact = (status: Status, emoji: string) =>
if (emoji === '👍') {
dispatch(favourite(status));
} else {
dispatch(emojiReact(status, emoji));
dispatch(emojiReact(status, emoji, custom));
}
}).catch(err => {
console.error(err);
@ -70,11 +70,11 @@ const fetchEmojiReacts = (id: string, emoji: string) =>
});
};
const emojiReact = (status: Status, emoji: string) =>
const emojiReact = (status: Status, emoji: string, custom?: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return dispatch(noOp());
dispatch(emojiReactRequest(status, emoji));
dispatch(emojiReactRequest(status, emoji, custom));
return api(getState)
.put(`/api/v1/pleroma/statuses/${status.get('id')}/reactions/${emoji}`)
@ -120,10 +120,11 @@ const fetchEmojiReactsFail = (id: string, error: AxiosError) => ({
error,
});
const emojiReactRequest = (status: Status, emoji: string) => ({
const emojiReactRequest = (status: Status, emoji: string, custom?: string) => ({
type: EMOJI_REACT_REQUEST,
status,
emoji,
custom,
skipLoading: true,
});

Wyświetl plik

@ -1,6 +1,6 @@
import { saveSettings } from './settings';
import type { Emoji } from 'soapbox/components/autosuggest-emoji';
import type { Emoji } from 'soapbox/features/emoji';
import type { AppDispatch } from 'soapbox/store';
const EMOJI_USE = 'EMOJI_USE';

Wyświetl plik

@ -569,7 +569,7 @@ const rejectEventParticipationRequestFail = (id: string, accountId: string, erro
});
const fetchEventIcs = (id: string) =>
(dispatch: any, getState: () => RootState) =>
(dispatch: AppDispatch, getState: () => RootState) =>
api(getState).get(`/api/v1/pleroma/events/${id}/ics`);
const cancelEventCompose = () => ({

Wyświetl plik

@ -34,8 +34,8 @@ type ExportDataActions = {
| typeof EXPORT_BLOCKS_FAIL
| typeof EXPORT_MUTES_REQUEST
| typeof EXPORT_MUTES_SUCCESS
| typeof EXPORT_MUTES_FAIL,
error?: any,
| typeof EXPORT_MUTES_FAIL
error?: any
}
function fileExport(content: string, fileName: string) {

Wyświetl plik

@ -11,25 +11,25 @@ export const FAMILIAR_FOLLOWERS_FETCH_SUCCESS = 'FAMILIAR_FOLLOWERS_FETCH_SUCCES
export const FAMILIAR_FOLLOWERS_FETCH_FAIL = 'FAMILIAR_FOLLOWERS_FETCH_FAIL';
type FamiliarFollowersFetchRequestAction = {
type: typeof FAMILIAR_FOLLOWERS_FETCH_REQUEST,
id: string,
type: typeof FAMILIAR_FOLLOWERS_FETCH_REQUEST
id: string
}
type FamiliarFollowersFetchRequestSuccessAction = {
type: typeof FAMILIAR_FOLLOWERS_FETCH_SUCCESS,
id: string,
accounts: Array<APIEntity>,
type: typeof FAMILIAR_FOLLOWERS_FETCH_SUCCESS
id: string
accounts: Array<APIEntity>
}
type FamiliarFollowersFetchRequestFailAction = {
type: typeof FAMILIAR_FOLLOWERS_FETCH_FAIL,
id: string,
error: any,
type: typeof FAMILIAR_FOLLOWERS_FETCH_FAIL
id: string
error: any
}
type AccountsImportAction = {
type: typeof ACCOUNTS_IMPORT,
accounts: Array<APIEntity>,
type: typeof ACCOUNTS_IMPORT
accounts: Array<APIEntity>
}
export type FamiliarFollowersActions = FamiliarFollowersFetchRequestAction | FamiliarFollowersFetchRequestSuccessAction | FamiliarFollowersFetchRequestFailAction | AccountsImportAction

Wyświetl plik

@ -12,10 +12,18 @@ const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL';
const FILTER_FETCH_REQUEST = 'FILTER_FETCH_REQUEST';
const FILTER_FETCH_SUCCESS = 'FILTER_FETCH_SUCCESS';
const FILTER_FETCH_FAIL = 'FILTER_FETCH_FAIL';
const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
const FILTERS_CREATE_FAIL = 'FILTERS_CREATE_FAIL';
const FILTERS_UPDATE_REQUEST = 'FILTERS_UPDATE_REQUEST';
const FILTERS_UPDATE_SUCCESS = 'FILTERS_UPDATE_SUCCESS';
const FILTERS_UPDATE_FAIL = 'FILTERS_UPDATE_FAIL';
const FILTERS_DELETE_REQUEST = 'FILTERS_DELETE_REQUEST';
const FILTERS_DELETE_SUCCESS = 'FILTERS_DELETE_SUCCESS';
const FILTERS_DELETE_FAIL = 'FILTERS_DELETE_FAIL';
@ -25,22 +33,16 @@ const messages = defineMessages({
removed: { id: 'filters.removed', defaultMessage: 'Filter deleted.' },
});
const fetchFilters = () =>
type FilterKeywords = { keyword: string, whole_word: boolean }[];
const fetchFiltersV1 = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return;
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (!features.filters) return;
dispatch({
type: FILTERS_FETCH_REQUEST,
skipLoading: true,
});
api(getState)
return api(getState)
.get('/api/v1/filters')
.then(({ data }) => dispatch({
type: FILTERS_FETCH_SUCCESS,
@ -55,15 +57,105 @@ const fetchFilters = () =>
}));
};
const createFilter = (phrase: string, expires_at: string, context: Array<string>, whole_word: boolean, irreversible: boolean) =>
const fetchFiltersV2 = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({
type: FILTERS_FETCH_REQUEST,
skipLoading: true,
});
return api(getState)
.get('/api/v2/filters')
.then(({ data }) => dispatch({
type: FILTERS_FETCH_SUCCESS,
filters: data,
skipLoading: true,
}))
.catch(err => dispatch({
type: FILTERS_FETCH_FAIL,
err,
skipLoading: true,
skipAlert: true,
}));
};
const fetchFilters = (fromFiltersPage = false) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return;
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (features.filtersV2 && fromFiltersPage) return dispatch(fetchFiltersV2());
if (features.filters) return dispatch(fetchFiltersV1());
};
const fetchFilterV1 = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({
type: FILTER_FETCH_REQUEST,
skipLoading: true,
});
return api(getState)
.get(`/api/v1/filters/${id}`)
.then(({ data }) => dispatch({
type: FILTER_FETCH_SUCCESS,
filter: data,
skipLoading: true,
}))
.catch(err => dispatch({
type: FILTER_FETCH_FAIL,
err,
skipLoading: true,
skipAlert: true,
}));
};
const fetchFilterV2 = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({
type: FILTER_FETCH_REQUEST,
skipLoading: true,
});
return api(getState)
.get(`/api/v2/filters/${id}`)
.then(({ data }) => dispatch({
type: FILTER_FETCH_SUCCESS,
filter: data,
skipLoading: true,
}))
.catch(err => dispatch({
type: FILTER_FETCH_FAIL,
err,
skipLoading: true,
skipAlert: true,
}));
};
const fetchFilter = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (features.filtersV2) return dispatch(fetchFilterV2(id));
if (features.filters) return dispatch(fetchFilterV1(id));
};
const createFilterV1 = (title: string, expires_in: string | null, context: Array<string>, hide: boolean, keywords: FilterKeywords) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FILTERS_CREATE_REQUEST });
return api(getState).post('/api/v1/filters', {
phrase,
phrase: keywords[0].keyword,
context,
irreversible,
whole_word,
expires_at,
irreversible: hide,
whole_word: keywords[0].whole_word,
expires_in,
}).then(response => {
dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data });
toast.success(messages.added);
@ -72,7 +164,80 @@ const createFilter = (phrase: string, expires_at: string, context: Array<string>
});
};
const deleteFilter = (id: string) =>
const createFilterV2 = (title: string, expires_in: string | null, context: Array<string>, hide: boolean, keywords_attributes: FilterKeywords) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FILTERS_CREATE_REQUEST });
return api(getState).post('/api/v2/filters', {
title,
context,
filter_action: hide ? 'hide' : 'warn',
expires_in,
keywords_attributes,
}).then(response => {
dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data });
toast.success(messages.added);
}).catch(error => {
dispatch({ type: FILTERS_CREATE_FAIL, error });
});
};
const createFilter = (title: string, expires_in: string | null, context: Array<string>, hide: boolean, keywords: FilterKeywords) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (features.filtersV2) return dispatch(createFilterV2(title, expires_in, context, hide, keywords));
return dispatch(createFilterV1(title, expires_in, context, hide, keywords));
};
const updateFilterV1 = (id: string, title: string, expires_in: string | null, context: Array<string>, hide: boolean, keywords: FilterKeywords) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FILTERS_UPDATE_REQUEST });
return api(getState).patch(`/api/v1/filters/${id}`, {
phrase: keywords[0].keyword,
context,
irreversible: hide,
whole_word: keywords[0].whole_word,
expires_in,
}).then(response => {
dispatch({ type: FILTERS_UPDATE_SUCCESS, filter: response.data });
toast.success(messages.added);
}).catch(error => {
dispatch({ type: FILTERS_UPDATE_FAIL, error });
});
};
const updateFilterV2 = (id: string, title: string, expires_in: string | null, context: Array<string>, hide: boolean, keywords_attributes: FilterKeywords) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FILTERS_UPDATE_REQUEST });
return api(getState).patch(`/api/v2/filters/${id}`, {
title,
context,
filter_action: hide ? 'hide' : 'warn',
expires_in,
keywords_attributes,
}).then(response => {
dispatch({ type: FILTERS_UPDATE_SUCCESS, filter: response.data });
toast.success(messages.added);
}).catch(error => {
dispatch({ type: FILTERS_UPDATE_FAIL, error });
});
};
const updateFilter = (id: string, title: string, expires_in: string | null, context: Array<string>, hide: boolean, keywords: FilterKeywords) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (features.filtersV2) return dispatch(updateFilterV2(id, title, expires_in, context, hide, keywords));
return dispatch(updateFilterV1(id, title, expires_in, context, hide, keywords));
};
const deleteFilterV1 = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FILTERS_DELETE_REQUEST });
return api(getState).delete(`/api/v1/filters/${id}`).then(response => {
@ -83,17 +248,47 @@ const deleteFilter = (id: string) =>
});
};
const deleteFilterV2 = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FILTERS_DELETE_REQUEST });
return api(getState).delete(`/api/v2/filters/${id}`).then(response => {
dispatch({ type: FILTERS_DELETE_SUCCESS, filter: response.data });
toast.success(messages.removed);
}).catch(error => {
dispatch({ type: FILTERS_DELETE_FAIL, error });
});
};
const deleteFilter = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (features.filtersV2) return dispatch(deleteFilterV2(id));
return dispatch(deleteFilterV1(id));
};
export {
FILTERS_FETCH_REQUEST,
FILTERS_FETCH_SUCCESS,
FILTERS_FETCH_FAIL,
FILTER_FETCH_REQUEST,
FILTER_FETCH_SUCCESS,
FILTER_FETCH_FAIL,
FILTERS_CREATE_REQUEST,
FILTERS_CREATE_SUCCESS,
FILTERS_CREATE_FAIL,
FILTERS_UPDATE_REQUEST,
FILTERS_UPDATE_SUCCESS,
FILTERS_UPDATE_FAIL,
FILTERS_DELETE_REQUEST,
FILTERS_DELETE_SUCCESS,
FILTERS_DELETE_FAIL,
fetchFilters,
fetchFilter,
createFilter,
updateFilter,
deleteFilter,
};
};

Wyświetl plik

@ -1,5 +1,6 @@
import { defineMessages } from 'react-intl';
import { deleteEntities } from 'soapbox/entity-store/actions';
import toast from 'soapbox/toast';
import api, { getLinks } from '../api';
@ -40,14 +41,6 @@ const GROUP_RELATIONSHIPS_FETCH_REQUEST = 'GROUP_RELATIONSHIPS_FETCH_REQUEST';
const GROUP_RELATIONSHIPS_FETCH_SUCCESS = 'GROUP_RELATIONSHIPS_FETCH_SUCCESS';
const GROUP_RELATIONSHIPS_FETCH_FAIL = 'GROUP_RELATIONSHIPS_FETCH_FAIL';
const GROUP_JOIN_REQUEST = 'GROUP_JOIN_REQUEST';
const GROUP_JOIN_SUCCESS = 'GROUP_JOIN_SUCCESS';
const GROUP_JOIN_FAIL = 'GROUP_JOIN_FAIL';
const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST';
const GROUP_LEAVE_SUCCESS = 'GROUP_LEAVE_SUCCESS';
const GROUP_LEAVE_FAIL = 'GROUP_LEAVE_FAIL';
const GROUP_DELETE_STATUS_REQUEST = 'GROUP_DELETE_STATUS_REQUEST';
const GROUP_DELETE_STATUS_SUCCESS = 'GROUP_DELETE_STATUS_SUCCESS';
const GROUP_DELETE_STATUS_FAIL = 'GROUP_DELETE_STATUS_FAIL';
@ -148,7 +141,8 @@ const createGroup = (params: Record<string, any>, shouldReset?: boolean) =>
if (shouldReset) {
dispatch(resetGroupEditor());
}
dispatch(closeModal('MANAGE_GROUP'));
return data;
}).catch(err => dispatch(createGroupFail(err)));
};
@ -198,7 +192,7 @@ const updateGroupFail = (error: AxiosError) => ({
});
const deleteGroup = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => {
dispatch(deleteGroupRequest(id));
dispatch(deleteEntities([id], 'Group'));
return api(getState).delete(`/api/v1/groups/${id}`)
.then(() => dispatch(deleteGroupSuccess(id)))
@ -312,70 +306,6 @@ const fetchGroupRelationshipsFail = (error: AxiosError) => ({
skipNotFound: true,
});
const joinGroup = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const locked = (getState().groups.items.get(id) as any).locked || false;
dispatch(joinGroupRequest(id, locked));
return api(getState).post(`/api/v1/groups/${id}/join`).then(response => {
dispatch(joinGroupSuccess(response.data));
toast.success(locked ? messages.joinRequestSuccess : messages.joinSuccess);
}).catch(error => {
dispatch(joinGroupFail(error, locked));
});
};
const leaveGroup = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch(leaveGroupRequest(id));
return api(getState).post(`/api/v1/groups/${id}/leave`).then(response => {
dispatch(leaveGroupSuccess(response.data));
toast.success(messages.leaveSuccess);
}).catch(error => {
dispatch(leaveGroupFail(error));
});
};
const joinGroupRequest = (id: string, locked: boolean) => ({
type: GROUP_JOIN_REQUEST,
id,
locked,
skipLoading: true,
});
const joinGroupSuccess = (relationship: APIEntity) => ({
type: GROUP_JOIN_SUCCESS,
relationship,
skipLoading: true,
});
const joinGroupFail = (error: AxiosError, locked: boolean) => ({
type: GROUP_JOIN_FAIL,
error,
locked,
skipLoading: true,
});
const leaveGroupRequest = (id: string) => ({
type: GROUP_LEAVE_REQUEST,
id,
skipLoading: true,
});
const leaveGroupSuccess = (relationship: APIEntity) => ({
type: GROUP_LEAVE_SUCCESS,
relationship,
skipLoading: true,
});
const leaveGroupFail = (error: AxiosError) => ({
type: GROUP_LEAVE_FAIL,
error,
skipLoading: true,
});
const groupDeleteStatus = (groupId: string, statusId: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch(groupDeleteStatusRequest(groupId, statusId));
@ -859,9 +789,11 @@ const submitGroupEditor = (shouldReset?: boolean) => (dispatch: AppDispatch, get
const note = getState().group_editor.note;
const avatar = getState().group_editor.avatar;
const header = getState().group_editor.header;
const visibility = getState().group_editor.locked ? 'members_only' : 'everyone'; // Truth Social
const params: Record<string, any> = {
display_name: displayName,
group_visibility: visibility,
note,
};
@ -869,9 +801,9 @@ const submitGroupEditor = (shouldReset?: boolean) => (dispatch: AppDispatch, get
if (header) params.header = header;
if (groupId === null) {
dispatch(createGroup(params, shouldReset));
return dispatch(createGroup(params, shouldReset));
} else {
dispatch(updateGroup(groupId, params, shouldReset));
return dispatch(updateGroup(groupId, params, shouldReset));
}
};
@ -895,12 +827,6 @@ export {
GROUP_RELATIONSHIPS_FETCH_REQUEST,
GROUP_RELATIONSHIPS_FETCH_SUCCESS,
GROUP_RELATIONSHIPS_FETCH_FAIL,
GROUP_JOIN_REQUEST,
GROUP_JOIN_SUCCESS,
GROUP_JOIN_FAIL,
GROUP_LEAVE_REQUEST,
GROUP_LEAVE_SUCCESS,
GROUP_LEAVE_FAIL,
GROUP_DELETE_STATUS_REQUEST,
GROUP_DELETE_STATUS_SUCCESS,
GROUP_DELETE_STATUS_FAIL,
@ -973,14 +899,6 @@ export {
fetchGroupRelationshipsRequest,
fetchGroupRelationshipsSuccess,
fetchGroupRelationshipsFail,
joinGroup,
leaveGroup,
joinGroupRequest,
joinGroupSuccess,
joinGroupFail,
leaveGroupRequest,
leaveGroupSuccess,
leaveGroupFail,
groupDeleteStatus,
groupDeleteStatusRequest,
groupDeleteStatusSuccess,

Wyświetl plik

@ -27,8 +27,8 @@ type ImportDataActions = {
| typeof IMPORT_BLOCKS_FAIL
| typeof IMPORT_MUTES_REQUEST
| typeof IMPORT_MUTES_SUCCESS
| typeof IMPORT_MUTES_FAIL,
error?: any,
| typeof IMPORT_MUTES_FAIL
error?: any
config?: string
}

Wyświetl plik

@ -1,3 +1,8 @@
import { importEntities } from 'soapbox/entity-store/actions';
import { Entities } from 'soapbox/entity-store/entities';
import { Group, groupSchema } from 'soapbox/schemas';
import { filteredArray } from 'soapbox/schemas/utils';
import { getSettings } from '../settings';
import type { AppDispatch, RootState } from 'soapbox/store';
@ -18,11 +23,11 @@ const importAccount = (account: APIEntity) =>
const importAccounts = (accounts: APIEntity[]) =>
({ type: ACCOUNTS_IMPORT, accounts });
const importGroup = (group: APIEntity) =>
({ type: GROUP_IMPORT, group });
const importGroup = (group: Group) =>
importEntities([group], Entities.GROUPS);
const importGroups = (groups: APIEntity[]) =>
({ type: GROUPS_IMPORT, groups });
const importGroups = (groups: Group[]) =>
importEntities(groups, Entities.GROUPS);
const importStatus = (status: APIEntity, idempotencyKey?: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
@ -69,17 +74,8 @@ const importFetchedGroup = (group: APIEntity) =>
importFetchedGroups([group]);
const importFetchedGroups = (groups: APIEntity[]) => {
const normalGroups: APIEntity[] = [];
const processGroup = (group: APIEntity) => {
if (!group.id) return;
normalGroups.push(group);
};
groups.forEach(processGroup);
return importGroups(normalGroups);
const entities = filteredArray(groupSchema).catch([]).parse(groups);
return importGroups(entities);
};
const importFetchedStatus = (status: APIEntity, idempotencyKey?: string) =>

Wyświetl plik

@ -20,6 +20,10 @@ const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST';
const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS';
const FAVOURITE_FAIL = 'FAVOURITE_FAIL';
const DISLIKE_REQUEST = 'DISLIKE_REQUEST';
const DISLIKE_SUCCESS = 'DISLIKE_SUCCESS';
const DISLIKE_FAIL = 'DISLIKE_FAIL';
const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST';
const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS';
const UNREBLOG_FAIL = 'UNREBLOG_FAIL';
@ -28,6 +32,10 @@ const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST';
const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS';
const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL';
const UNDISLIKE_REQUEST = 'UNDISLIKE_REQUEST';
const UNDISLIKE_SUCCESS = 'UNDISLIKE_SUCCESS';
const UNDISLIKE_FAIL = 'UNDISLIKE_FAIL';
const REBLOGS_FETCH_REQUEST = 'REBLOGS_FETCH_REQUEST';
const REBLOGS_FETCH_SUCCESS = 'REBLOGS_FETCH_SUCCESS';
const REBLOGS_FETCH_FAIL = 'REBLOGS_FETCH_FAIL';
@ -36,6 +44,10 @@ const FAVOURITES_FETCH_REQUEST = 'FAVOURITES_FETCH_REQUEST';
const FAVOURITES_FETCH_SUCCESS = 'FAVOURITES_FETCH_SUCCESS';
const FAVOURITES_FETCH_FAIL = 'FAVOURITES_FETCH_FAIL';
const DISLIKES_FETCH_REQUEST = 'DISLIKES_FETCH_REQUEST';
const DISLIKES_FETCH_SUCCESS = 'DISLIKES_FETCH_SUCCESS';
const DISLIKES_FETCH_FAIL = 'DISLIKES_FETCH_FAIL';
const REACTIONS_FETCH_REQUEST = 'REACTIONS_FETCH_REQUEST';
const REACTIONS_FETCH_SUCCESS = 'REACTIONS_FETCH_SUCCESS';
const REACTIONS_FETCH_FAIL = 'REACTIONS_FETCH_FAIL';
@ -96,7 +108,7 @@ const unreblog = (status: StatusEntity) =>
};
const toggleReblog = (status: StatusEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
(dispatch: AppDispatch) => {
if (status.reblogged) {
dispatch(unreblog(status));
} else {
@ -169,7 +181,7 @@ const unfavourite = (status: StatusEntity) =>
};
const toggleFavourite = (status: StatusEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
(dispatch: AppDispatch) => {
if (status.favourited) {
dispatch(unfavourite(status));
} else {
@ -215,6 +227,79 @@ const unfavouriteFail = (status: StatusEntity, error: AxiosError) => ({
skipLoading: true,
});
const dislike = (status: StatusEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return;
dispatch(dislikeRequest(status));
api(getState).post(`/api/friendica/statuses/${status.get('id')}/dislike`).then(function() {
dispatch(dislikeSuccess(status));
}).catch(function(error) {
dispatch(dislikeFail(status, error));
});
};
const undislike = (status: StatusEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return;
dispatch(undislikeRequest(status));
api(getState).post(`/api/friendica/statuses/${status.get('id')}/undislike`).then(() => {
dispatch(undislikeSuccess(status));
}).catch(error => {
dispatch(undislikeFail(status, error));
});
};
const toggleDislike = (status: StatusEntity) =>
(dispatch: AppDispatch) => {
if (status.disliked) {
dispatch(undislike(status));
} else {
dispatch(dislike(status));
}
};
const dislikeRequest = (status: StatusEntity) => ({
type: DISLIKE_REQUEST,
status: status,
skipLoading: true,
});
const dislikeSuccess = (status: StatusEntity) => ({
type: DISLIKE_SUCCESS,
status: status,
skipLoading: true,
});
const dislikeFail = (status: StatusEntity, error: AxiosError) => ({
type: DISLIKE_FAIL,
status: status,
error: error,
skipLoading: true,
});
const undislikeRequest = (status: StatusEntity) => ({
type: UNDISLIKE_REQUEST,
status: status,
skipLoading: true,
});
const undislikeSuccess = (status: StatusEntity) => ({
type: UNDISLIKE_SUCCESS,
status: status,
skipLoading: true,
});
const undislikeFail = (status: StatusEntity, error: AxiosError) => ({
type: UNDISLIKE_FAIL,
status: status,
error: error,
skipLoading: true,
});
const bookmark = (status: StatusEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch(bookmarkRequest(status));
@ -351,6 +436,38 @@ const fetchFavouritesFail = (id: string, error: AxiosError) => ({
error,
});
const fetchDislikes = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return;
dispatch(fetchDislikesRequest(id));
api(getState).get(`/api/friendica/statuses/${id}/disliked_by`).then(response => {
dispatch(importFetchedAccounts(response.data));
dispatch(fetchRelationships(response.data.map((item: APIEntity) => item.id)));
dispatch(fetchDislikesSuccess(id, response.data));
}).catch(error => {
dispatch(fetchDislikesFail(id, error));
});
};
const fetchDislikesRequest = (id: string) => ({
type: DISLIKES_FETCH_REQUEST,
id,
});
const fetchDislikesSuccess = (id: string, accounts: APIEntity[]) => ({
type: DISLIKES_FETCH_SUCCESS,
id,
accounts,
});
const fetchDislikesFail = (id: string, error: AxiosError) => ({
type: DISLIKES_FETCH_FAIL,
id,
error,
});
const fetchReactions = (id: string) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch(fetchReactionsRequest(id));
@ -498,18 +615,27 @@ export {
FAVOURITE_REQUEST,
FAVOURITE_SUCCESS,
FAVOURITE_FAIL,
DISLIKE_REQUEST,
DISLIKE_SUCCESS,
DISLIKE_FAIL,
UNREBLOG_REQUEST,
UNREBLOG_SUCCESS,
UNREBLOG_FAIL,
UNFAVOURITE_REQUEST,
UNFAVOURITE_SUCCESS,
UNFAVOURITE_FAIL,
UNDISLIKE_REQUEST,
UNDISLIKE_SUCCESS,
UNDISLIKE_FAIL,
REBLOGS_FETCH_REQUEST,
REBLOGS_FETCH_SUCCESS,
REBLOGS_FETCH_FAIL,
FAVOURITES_FETCH_REQUEST,
FAVOURITES_FETCH_SUCCESS,
FAVOURITES_FETCH_FAIL,
DISLIKES_FETCH_REQUEST,
DISLIKES_FETCH_SUCCESS,
DISLIKES_FETCH_FAIL,
REACTIONS_FETCH_REQUEST,
REACTIONS_FETCH_SUCCESS,
REACTIONS_FETCH_FAIL,
@ -546,6 +672,15 @@ export {
unfavouriteRequest,
unfavouriteSuccess,
unfavouriteFail,
dislike,
undislike,
toggleDislike,
dislikeRequest,
dislikeSuccess,
dislikeFail,
undislikeRequest,
undislikeSuccess,
undislikeFail,
bookmark,
unbookmark,
toggleBookmark,
@ -563,6 +698,10 @@ export {
fetchFavouritesRequest,
fetchFavouritesSuccess,
fetchFavouritesFail,
fetchDislikes,
fetchDislikesRequest,
fetchDislikesSuccess,
fetchDislikesFail,
fetchReactions,
fetchReactionsRequest,
fetchReactionsSuccess,

Wyświetl plik

@ -112,27 +112,6 @@ const deleteUserModal = (intl: IntlShape, accountId: string, afterConfirm = () =
}));
};
const rejectUserModal = (intl: IntlShape, accountId: string, afterConfirm = () => {}) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const acct = state.accounts.get(accountId)!.acct;
const name = state.accounts.get(accountId)!.username;
dispatch(openModal('CONFIRM', {
icon: require('@tabler/icons/user-off.svg'),
heading: intl.formatMessage(messages.rejectUserHeading, { acct }),
message: intl.formatMessage(messages.rejectUserPrompt, { acct }),
confirm: intl.formatMessage(messages.rejectUserConfirm, { name }),
onConfirm: () => {
dispatch(deleteUsers([accountId]))
.then(() => {
afterConfirm();
})
.catch(() => {});
},
}));
};
const toggleStatusSensitivityModal = (intl: IntlShape, statusId: string, sensitive: boolean, afterConfirm = () => {}) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
@ -178,7 +157,6 @@ const deleteStatusModal = (intl: IntlShape, statusId: string, afterConfirm = ()
export {
deactivateUserModal,
deleteUserModal,
rejectUserModal,
toggleStatusSensitivityModal,
deleteStatusModal,
};

Wyświetl plik

@ -37,8 +37,8 @@ const subscribe = (registration: ServiceWorkerRegistration, getState: () => Root
});
const unsubscribe = ({ registration, subscription }: {
registration: ServiceWorkerRegistration,
subscription: PushSubscription | null,
registration: ServiceWorkerRegistration
subscription: PushSubscription | null
}) =>
subscription ? subscription.unsubscribe().then(() => registration) : new Promise<ServiceWorkerRegistration>(r => r(registration));
@ -82,8 +82,8 @@ const register = () =>
.then(getPushSubscription)
// @ts-ignore
.then(({ registration, subscription }: {
registration: ServiceWorkerRegistration,
subscription: PushSubscription | null,
registration: ServiceWorkerRegistration
subscription: PushSubscription | null
}) => {
if (subscription !== null) {
// We have a subscription, check if it is still valid

Wyświetl plik

@ -4,7 +4,7 @@ import { openModal } from './modals';
import type { AxiosError } from 'axios';
import type { AppDispatch, RootState } from 'soapbox/store';
import type { Account, ChatMessage, Status } from 'soapbox/types/entities';
import type { Account, ChatMessage, Group, Status } from 'soapbox/types/entities';
const REPORT_INIT = 'REPORT_INIT';
const REPORT_CANCEL = 'REPORT_CANCEL';
@ -20,19 +20,29 @@ const REPORT_BLOCK_CHANGE = 'REPORT_BLOCK_CHANGE';
const REPORT_RULE_CHANGE = 'REPORT_RULE_CHANGE';
type ReportedEntity = {
status?: Status,
chatMessage?: ChatMessage
enum ReportableEntities {
ACCOUNT = 'ACCOUNT',
CHAT_MESSAGE = 'CHAT_MESSAGE',
GROUP = 'GROUP',
STATUS = 'STATUS'
}
const initReport = (account: Account, entities?: ReportedEntity) => (dispatch: AppDispatch) => {
const { status, chatMessage } = entities || {};
type ReportedEntity = {
status?: Status
chatMessage?: ChatMessage
group?: Group
}
const initReport = (entityType: ReportableEntities, account: Account, entities?: ReportedEntity) => (dispatch: AppDispatch) => {
const { status, chatMessage, group } = entities || {};
dispatch({
type: REPORT_INIT,
entityType,
account,
status,
chatMessage,
group,
});
return dispatch(openModal('REPORT'));
@ -56,7 +66,8 @@ const submitReport = () =>
return api(getState).post('/api/v1/reports', {
account_id: reports.getIn(['new', 'account_id']),
status_ids: reports.getIn(['new', 'status_ids']),
message_ids: [reports.getIn(['new', 'chat_message', 'id'])],
message_ids: [reports.getIn(['new', 'chat_message', 'id'])].filter(Boolean),
group_id: reports.getIn(['new', 'group', 'id']),
rule_ids: reports.getIn(['new', 'rule_ids']),
comment: reports.getIn(['new', 'comment']),
forward: reports.getIn(['new', 'forward']),
@ -97,6 +108,7 @@ const changeReportRule = (ruleId: string) => ({
});
export {
ReportableEntities,
REPORT_INIT,
REPORT_CANCEL,
REPORT_SUBMIT_REQUEST,

Wyświetl plik

@ -1,9 +1,10 @@
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet } from 'immutable';
import { defineMessages } from 'react-intl';
import { defineMessage } from 'react-intl';
import { createSelector } from 'reselect';
import { v4 as uuid } from 'uuid';
import { patchMe } from 'soapbox/actions/me';
import messages from 'soapbox/locales/messages';
import toast from 'soapbox/toast';
import { isLoggedIn } from 'soapbox/utils/auth';
@ -18,12 +19,10 @@ const FE_NAME = 'soapbox_fe';
/** Options when changing/saving settings. */
type SettingOpts = {
/** Whether to display an alert when settings are saved. */
showAlert?: boolean,
showAlert?: boolean
}
const messages = defineMessages({
saveSuccess: { id: 'settings.save.success', defaultMessage: 'Your preferences have been saved!' },
});
const saveSuccessMessage = defineMessage({ id: 'settings.save.success', defaultMessage: 'Your preferences have been saved!' });
const defaultSettings = ImmutableMap({
onboarded: false,
@ -40,7 +39,7 @@ const defaultSettings = ImmutableMap({
defaultPrivacy: 'public',
defaultContentType: 'text/plain',
themeMode: 'system',
locale: navigator.language.split(/[-_]/)[0] || 'en',
locale: navigator.language || 'en',
showExplanationBox: true,
explanationBox: true,
autoloadTimelines: true,
@ -221,7 +220,7 @@ const saveSettingsImmediate = (opts?: SettingOpts) =>
dispatch({ type: SETTING_SAVE });
if (opts?.showAlert) {
toast.success(messages.saveSuccess);
toast.success(saveSuccessMessage);
}
}).catch(error => {
toast.showAlertForError(error);
@ -231,6 +230,12 @@ const saveSettingsImmediate = (opts?: SettingOpts) =>
const saveSettings = (opts?: SettingOpts) =>
(dispatch: AppDispatch) => dispatch(saveSettingsImmediate(opts));
const getLocale = (state: RootState, fallback = 'en') => {
const localeWithVariant = (getSettings(state).get('locale') as string).replace('_', '-');
const locale = localeWithVariant.split('-')[0];
return Object.keys(messages).includes(localeWithVariant) ? localeWithVariant : Object.keys(messages).includes(locale) ? locale : fallback;
};
export {
SETTING_CHANGE,
SETTING_SAVE,
@ -242,4 +247,5 @@ export {
changeSetting,
saveSettingsImmediate,
saveSettings,
getLocale,
};

Wyświetl plik

@ -48,6 +48,8 @@ const STATUS_TRANSLATE_SUCCESS = 'STATUS_TRANSLATE_SUCCESS';
const STATUS_TRANSLATE_FAIL = 'STATUS_TRANSLATE_FAIL';
const STATUS_TRANSLATE_UNDO = 'STATUS_TRANSLATE_UNDO';
const STATUS_UNFILTER = 'STATUS_UNFILTER';
const statusExists = (getState: () => RootState, statusId: string) => {
return (getState().statuses.get(statusId) || null) !== null;
};
@ -335,6 +337,11 @@ const undoStatusTranslation = (id: string) => ({
id,
});
const unfilterStatus = (id: string) => ({
type: STATUS_UNFILTER,
id,
});
export {
STATUS_CREATE_REQUEST,
STATUS_CREATE_SUCCESS,
@ -363,6 +370,7 @@ export {
STATUS_TRANSLATE_SUCCESS,
STATUS_TRANSLATE_FAIL,
STATUS_TRANSLATE_UNDO,
STATUS_UNFILTER,
createStatus,
editStatus,
fetchStatus,
@ -381,4 +389,5 @@ export {
toggleStatusHidden,
translateStatus,
undoStatusTranslation,
unfilterStatus,
};

Wyświetl plik

@ -1,4 +1,4 @@
import { getSettings } from 'soapbox/actions/settings';
import { getLocale, getSettings } from 'soapbox/actions/settings';
import messages from 'soapbox/locales/messages';
import { ChatKeys, IChat, isLastMessage } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client';
@ -34,13 +34,6 @@ import type { APIEntity, Chat } from 'soapbox/types/entities';
const STREAMING_CHAT_UPDATE = 'STREAMING_CHAT_UPDATE';
const STREAMING_FOLLOW_RELATIONSHIPS_UPDATE = 'STREAMING_FOLLOW_RELATIONSHIPS_UPDATE';
const validLocale = (locale: string) => Object.keys(messages).includes(locale);
const getLocale = (state: RootState) => {
const locale = getSettings(state).get('locale') as string;
return validLocale(locale) ? locale : 'en';
};
const updateFollowRelationships = (relationships: APIEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const me = getState().me;
@ -81,7 +74,7 @@ const updateChatQuery = (chat: IChat) => {
};
interface StreamOpts {
statContext?: IStatContext,
statContext?: IStatContext
}
const connectTimelineStream = (

Wyświetl plik

@ -31,14 +31,14 @@ const AGE: Challenge = 'age';
export type Challenge = 'age' | 'sms' | 'email'
type Challenges = {
email?: 0 | 1,
sms?: 0 | 1,
age?: 0 | 1,
email?: 0 | 1
sms?: 0 | 1
age?: 0 | 1
}
type Verification = {
token?: string,
challenges?: Challenges,
token?: string
challenges?: Challenges
challengeTypes?: Array<'age' | 'sms' | 'email'>
};

Wyświetl plik

@ -23,7 +23,12 @@ export const getLinks = (response: AxiosResponse): LinkHeader => {
export const getNextLink = (response: AxiosResponse) => {
const nextLink = new LinkHeader(response.headers?.link);
return nextLink.refs.find((ref) => ref.uri)?.uri;
return nextLink.refs.find(link => link.rel === 'next')?.uri;
};
export const getPrevLink = (response: AxiosResponse) => {
const prevLink = new LinkHeader(response.headers?.link);
return prevLink.refs.find(link => link.rel === 'prev')?.uri;
};
export const baseClient = (...params: any[]) => {

Wyświetl plik

@ -29,6 +29,10 @@ export const getNextLink = (response: AxiosResponse): string | undefined => {
return getLinks(response).refs.find(link => link.rel === 'next')?.uri;
};
export const getPrevLink = (response: AxiosResponse): string | undefined => {
return getLinks(response).refs.find(link => link.rel === 'prev')?.uri;
};
const getToken = (state: RootState, authType: string) => {
return authType === 'app' ? getAppToken(state) : getAccessToken(state);
};

Wyświetl plik

@ -1,7 +1,7 @@
import React from 'react';
interface IInlineSVG {
loader?: JSX.Element,
loader?: JSX.Element
}
const InlineSVG: React.FC<IInlineSVG> = ({ loader }): JSX.Element => {

Wyświetl plik

@ -12,9 +12,9 @@ const messages = defineMessages({
interface IAccountSearch {
/** Callback when a searched account is chosen. */
onSelected: (accountId: string) => void,
onSelected: (accountId: string) => void
/** Override the default placeholder of the input. */
placeholder?: string,
placeholder?: string
}
/** Input to search for accounts. */

Wyświetl plik

@ -14,11 +14,12 @@ import RelativeTimestamp from './relative-timestamp';
import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui';
import type { StatusApprovalStatus } from 'soapbox/normalizers/status';
import type { Account as AccountSchema } from 'soapbox/schemas';
import type { Account as AccountEntity } from 'soapbox/types/entities';
interface IInstanceFavicon {
account: AccountEntity,
disabled?: boolean,
account: AccountEntity | AccountSchema
disabled?: boolean
}
const messages = defineMessages({
@ -53,7 +54,7 @@ const InstanceFavicon: React.FC<IInstanceFavicon> = ({ account, disabled }) => {
};
interface IProfilePopper {
condition: boolean,
condition: boolean
wrapper: (children: React.ReactNode) => React.ReactNode
children: React.ReactNode
}
@ -67,30 +68,31 @@ const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children
};
export interface IAccount {
account: AccountEntity,
action?: React.ReactElement,
actionAlignment?: 'center' | 'top',
actionIcon?: string,
actionTitle?: string,
account: AccountEntity | AccountSchema
action?: React.ReactElement
actionAlignment?: 'center' | 'top'
actionIcon?: string
actionTitle?: string
/** Override other actions for specificity like mute/unmute. */
actionType?: 'muting' | 'blocking' | 'follow_request',
avatarSize?: number,
hidden?: boolean,
hideActions?: boolean,
id?: string,
onActionClick?: (account: any) => void,
showProfileHoverCard?: boolean,
timestamp?: string,
timestampUrl?: string,
futureTimestamp?: boolean,
withAccountNote?: boolean,
withDate?: boolean,
withLinkToProfile?: boolean,
withRelationship?: boolean,
showEdit?: boolean,
approvalStatus?: StatusApprovalStatus,
emoji?: string,
note?: string,
actionType?: 'muting' | 'blocking' | 'follow_request'
avatarSize?: number
hidden?: boolean
hideActions?: boolean
id?: string
onActionClick?: (account: any) => void
showProfileHoverCard?: boolean
timestamp?: string
timestampUrl?: string
futureTimestamp?: boolean
withAccountNote?: boolean
withDate?: boolean
withLinkToProfile?: boolean
withRelationship?: boolean
showEdit?: boolean
approvalStatus?: StatusApprovalStatus
emoji?: string
emojiUrl?: string
note?: string
}
const Account = ({
@ -115,6 +117,7 @@ const Account = ({
showEdit = false,
approvalStatus,
emoji,
emojiUrl,
note,
}: IAccount) => {
const overflowRef = useRef<HTMLDivElement>(null);
@ -143,7 +146,7 @@ const Account = ({
title={actionTitle}
onClick={handleAction}
className='bg-transparent text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500'
iconClassName='w-4 h-4'
iconClassName='h-4 w-4'
/>
);
}
@ -190,8 +193,9 @@ const Account = ({
<Avatar src={account.avatar} size={avatarSize} />
{emoji && (
<Emoji
className='absolute -bottom-1.5 -right-1.5 h-5 w-5'
className='absolute bottom-0 -right-1.5 h-5 w-5'
emoji={emoji}
src={emojiUrl}
/>
)}
</LinkEl>

Wyświetl plik

@ -15,8 +15,8 @@ const obfuscatedCount = (count: number) => {
};
interface IAnimatedNumber {
value: number;
obfuscate?: boolean;
value: number
obfuscate?: boolean
}
const AnimatedNumber: React.FC<IAnimatedNumber> = ({ value, obfuscate }) => {

Wyświetl plik

@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom';
import type { Announcement as AnnouncementEntity, Mention as MentionEntity } from 'soapbox/types/entities';
interface IAnnouncementContent {
announcement: AnnouncementEntity;
announcement: AnnouncementEntity
}
const AnnouncementContent: React.FC<IAnnouncementContent> = ({ announcement }) => {

Wyświetl plik

@ -11,10 +11,10 @@ import type { Map as ImmutableMap } from 'immutable';
import type { Announcement as AnnouncementEntity } from 'soapbox/types/entities';
interface IAnnouncement {
announcement: AnnouncementEntity;
addReaction: (id: string, name: string) => void;
removeReaction: (id: string, name: string) => void;
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>;
announcement: AnnouncementEntity
addReaction: (id: string, name: string) => void
removeReaction: (id: string, name: string) => void
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>
}
const Announcement: React.FC<IAnnouncement> = ({ announcement, addReaction, removeReaction, emojiMap }) => {

Wyświetl plik

@ -1,15 +1,15 @@
import React from 'react';
import unicodeMapping from 'soapbox/features/emoji/emoji-unicode-mapping-light';
import unicodeMapping from 'soapbox/features/emoji/mapping';
import { useSettings } from 'soapbox/hooks';
import { joinPublicPath } from 'soapbox/utils/static';
import type { Map as ImmutableMap } from 'immutable';
interface IEmoji {
emoji: string;
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>;
hovered: boolean;
emoji: string
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>
hovered: boolean
}
const Emoji: React.FC<IEmoji> = ({ emoji, emojiMap, hovered }) => {

Wyświetl plik

@ -2,7 +2,7 @@ import clsx from 'clsx';
import React, { useState } from 'react';
import AnimatedNumber from 'soapbox/components/animated-number';
import unicodeMapping from 'soapbox/features/emoji/emoji-unicode-mapping-light';
import unicodeMapping from 'soapbox/features/emoji/mapping';
import Emoji from './emoji';
@ -10,12 +10,12 @@ import type { Map as ImmutableMap } from 'immutable';
import type { AnnouncementReaction } from 'soapbox/types/entities';
interface IReaction {
announcementId: string;
reaction: AnnouncementReaction;
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>;
addReaction: (id: string, name: string) => void;
removeReaction: (id: string, name: string) => void;
style: React.CSSProperties;
announcementId: string
reaction: AnnouncementReaction
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>
addReaction: (id: string, name: string) => void
removeReaction: (id: string, name: string) => void
style: React.CSSProperties
}
const Reaction: React.FC<IReaction> = ({ announcementId, reaction, addReaction, removeReaction, emojiMap, style }) => {

Wyświetl plik

@ -2,29 +2,28 @@ import clsx from 'clsx';
import React from 'react';
import { TransitionMotion, spring } from 'react-motion';
import { Icon } from 'soapbox/components/ui';
import EmojiPickerDropdown from 'soapbox/features/compose/components/emoji-picker/emoji-picker-dropdown';
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
import { useSettings } from 'soapbox/hooks';
import Reaction from './reaction';
import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
import type { Emoji } from 'soapbox/components/autosuggest-emoji';
import type { Emoji, NativeEmoji } from 'soapbox/features/emoji';
import type { AnnouncementReaction } from 'soapbox/types/entities';
interface IReactionsBar {
announcementId: string;
reactions: ImmutableList<AnnouncementReaction>;
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>;
addReaction: (id: string, name: string) => void;
removeReaction: (id: string, name: string) => void;
announcementId: string
reactions: ImmutableList<AnnouncementReaction>
emojiMap: ImmutableMap<string, ImmutableMap<string, string>>
addReaction: (id: string, name: string) => void
removeReaction: (id: string, name: string) => void
}
const ReactionsBar: React.FC<IReactionsBar> = ({ announcementId, reactions, addReaction, removeReaction, emojiMap }) => {
const reduceMotion = useSettings().get('reduceMotion');
const handleEmojiPick = (data: Emoji) => {
addReaction(announcementId, data.native.replace(/:/g, ''));
addReaction(announcementId, (data as NativeEmoji).native.replace(/:/g, ''));
};
const willEnter = () => ({ scale: reduceMotion ? 1 : 0 });
@ -55,7 +54,7 @@ const ReactionsBar: React.FC<IReactionsBar> = ({ announcementId, reactions, addR
/>
))}
{visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={handleEmojiPick} button={<Icon className='h-4 w-4 text-gray-400 hover:text-gray-600 dark:hover:text-white' src={require('@tabler/icons/plus.svg')} />} />}
{visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={handleEmojiPick} />}
</div>
)}
</TransitionMotion>

Wyświetl plik

@ -0,0 +1,139 @@
import clsx from 'clsx';
import React, { useEffect, useRef, useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { HStack, IconButton, Text } from 'soapbox/components/ui';
interface IAuthorizeRejectButtons {
onAuthorize(): Promise<unknown> | unknown
onReject(): Promise<unknown> | unknown
countdown?: number
}
/** Buttons to approve or reject a pending item, usually an account. */
const AuthorizeRejectButtons: React.FC<IAuthorizeRejectButtons> = ({ onAuthorize, onReject, countdown }) => {
const [state, setState] = useState<'authorizing' | 'rejecting' | 'authorized' | 'rejected' | 'pending'>('pending');
const timeout = useRef<NodeJS.Timeout>();
function handleAction(
present: 'authorizing' | 'rejecting',
past: 'authorized' | 'rejected',
action: () => Promise<unknown> | unknown,
): void {
if (state === present) {
if (timeout.current) {
clearTimeout(timeout.current);
}
setState('pending');
} else {
const doAction = async () => {
try {
await action();
setState(past);
} catch (e) {
console.error(e);
}
};
if (typeof countdown === 'number') {
setState(present);
timeout.current = setTimeout(doAction, countdown);
} else {
doAction();
}
}
}
const handleAuthorize = async () => handleAction('authorizing', 'authorized', onAuthorize);
const handleReject = async () => handleAction('rejecting', 'rejected', onReject);
useEffect(() => {
return () => {
if (timeout.current) {
clearTimeout(timeout.current);
}
};
}, []);
switch (state) {
case 'authorized':
return (
<ActionEmblem text={<FormattedMessage id='authorize.success' defaultMessage='Approved' />} />
);
case 'rejected':
return (
<ActionEmblem text={<FormattedMessage id='reject.success' defaultMessage='Rejected' />} />
);
default:
return (
<HStack space={3} alignItems='center'>
<AuthorizeRejectButton
theme='danger'
icon={require('@tabler/icons/x.svg')}
action={handleReject}
isLoading={state === 'rejecting'}
disabled={state === 'authorizing'}
/>
<AuthorizeRejectButton
theme='primary'
icon={require('@tabler/icons/check.svg')}
action={handleAuthorize}
isLoading={state === 'authorizing'}
disabled={state === 'rejecting'}
/>
</HStack>
);
}
};
interface IActionEmblem {
text: React.ReactNode
}
const ActionEmblem: React.FC<IActionEmblem> = ({ text }) => {
return (
<div className='rounded-full bg-gray-100 px-4 py-2 dark:bg-gray-800'>
<Text theme='muted' size='sm'>
{text}
</Text>
</div>
);
};
interface IAuthorizeRejectButton {
theme: 'primary' | 'danger'
icon: string
action(): void
isLoading?: boolean
disabled?: boolean
}
const AuthorizeRejectButton: React.FC<IAuthorizeRejectButton> = ({ theme, icon, action, isLoading, disabled }) => {
return (
<div className='relative'>
<IconButton
src={isLoading ? require('@tabler/icons/player-stop-filled.svg') : icon}
onClick={action}
theme='seamless'
className={clsx('h-10 w-10 items-center justify-center border-2', {
'border-primary-500/10 hover:border-primary-500': theme === 'primary',
'border-danger-600/10 hover:border-danger-600': theme === 'danger',
})}
iconClassName={clsx('h-6 w-6', {
'text-primary-500': theme === 'primary',
'text-danger-600': theme === 'danger',
})}
disabled={disabled}
/>
{(isLoading) && (
<div
className={clsx('pointer-events-none absolute inset-0 h-10 w-10 animate-spin rounded-full border-2 border-transparent', {
'border-t-primary-500': theme === 'primary',
'border-t-danger-600': theme === 'danger',
})}
/>
)}
</div>
);
};
export { AuthorizeRejectButtons };

Wyświetl plik

@ -12,16 +12,16 @@ import type { InputThemes } from 'soapbox/components/ui/input/input';
const noOp = () => { };
interface IAutosuggestAccountInput {
onChange: React.ChangeEventHandler<HTMLInputElement>,
onSelected: (accountId: string) => void,
autoFocus?: boolean,
value: string,
limit?: number,
className?: string,
autoSelect?: boolean,
menu?: Menu,
onKeyDown?: React.KeyboardEventHandler,
theme?: InputThemes,
onChange: React.ChangeEventHandler<HTMLInputElement>
onSelected: (accountId: string) => void
autoFocus?: boolean
value: string
limit?: number
className?: string
autoSelect?: boolean
menu?: Menu
onKeyDown?: React.KeyboardEventHandler
theme?: InputThemes
}
const AutosuggestAccountInput: React.FC<IAutosuggestAccountInput> = ({

Wyświetl plik

@ -1,38 +1,30 @@
import React from 'react';
import unicodeMapping from 'soapbox/features/emoji/emoji-unicode-mapping-light';
import { isCustomEmoji } from 'soapbox/features/emoji';
import unicodeMapping from 'soapbox/features/emoji/mapping';
import { joinPublicPath } from 'soapbox/utils/static';
export type Emoji = {
id: string,
custom: boolean,
imageUrl: string,
native: string,
colons: string,
}
type UnicodeMapping = {
filename: string,
}
import type { Emoji } from 'soapbox/features/emoji';
interface IAutosuggestEmoji {
emoji: Emoji,
emoji: Emoji
}
const AutosuggestEmoji: React.FC<IAutosuggestEmoji> = ({ emoji }) => {
let url;
let url, alt;
if (emoji.custom) {
if (isCustomEmoji(emoji)) {
url = emoji.imageUrl;
alt = emoji.colons;
} else {
// @ts-ignore
const mapping: UnicodeMapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')];
const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')];
if (!mapping) {
return null;
}
url = joinPublicPath(`packs/emoji/${mapping.filename}.svg`);
url = joinPublicPath(`packs/emoji/${mapping.unified}.svg`);
alt = emoji.native;
}
return (
@ -40,7 +32,7 @@ const AutosuggestEmoji: React.FC<IAutosuggestEmoji> = ({ emoji }) => {
<img
className='emojione'
src={url}
alt={emoji.native || emoji.colons}
alt={alt}
/>
{emoji.colons}

Wyświetl plik

@ -3,7 +3,7 @@ import { List as ImmutableList } from 'immutable';
import React from 'react';
import ImmutablePureComponent from 'react-immutable-pure-component';
import AutosuggestEmoji, { Emoji } from 'soapbox/components/autosuggest-emoji';
import AutosuggestEmoji from 'soapbox/components/autosuggest-emoji';
import Icon from 'soapbox/components/icon';
import { Input, Portal } from 'soapbox/components/ui';
import AutosuggestAccount from 'soapbox/features/compose/components/autosuggest-account';
@ -12,27 +12,28 @@ import { textAtCursorMatchesToken } from 'soapbox/utils/suggestions';
import type { Menu, MenuItem } from 'soapbox/components/dropdown-menu';
import type { InputThemes } from 'soapbox/components/ui/input/input';
import type { Emoji } from 'soapbox/features/emoji';
export type AutoSuggestion = string | Emoji;
export interface IAutosuggestInput extends Pick<React.HTMLAttributes<HTMLInputElement>, 'onChange' | 'onKeyUp' | 'onKeyDown'> {
value: string,
suggestions: ImmutableList<any>,
disabled?: boolean,
placeholder?: string,
onSuggestionSelected: (tokenStart: number, lastToken: string | null, suggestion: AutoSuggestion) => void,
onSuggestionsClearRequested: () => void,
onSuggestionsFetchRequested: (token: string) => void,
autoFocus: boolean,
autoSelect: boolean,
className?: string,
id?: string,
searchTokens: string[],
maxLength?: number,
menu?: Menu,
renderSuggestion?: React.FC<{ id: string }>,
hidePortal?: boolean,
theme?: InputThemes,
value: string
suggestions: ImmutableList<any>
disabled?: boolean
placeholder?: string
onSuggestionSelected: (tokenStart: number, lastToken: string | null, suggestion: AutoSuggestion) => void
onSuggestionsClearRequested: () => void
onSuggestionsFetchRequested: (token: string) => void
autoFocus: boolean
autoSelect: boolean
className?: string
id?: string
searchTokens: string[]
maxLength?: number
menu?: Menu
renderSuggestion?: React.FC<{ id: string }>
hidePortal?: boolean
theme?: InputThemes
}
export default class AutosuggestInput extends ImmutablePureComponent<IAutosuggestInput> {

Wyświetl plik

@ -19,7 +19,7 @@ export const ADDRESS_ICONS: Record<string, string> = {
};
interface IAutosuggestLocation {
id: string,
id: string
}
const AutosuggestLocation: React.FC<IAutosuggestLocation> = ({ id }) => {

Wyświetl plik

@ -4,33 +4,33 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import Textarea from 'react-textarea-autosize';
import { Portal } from 'soapbox/components/ui';
import AutosuggestAccount from 'soapbox/features/compose/components/autosuggest-account';
import { isRtl } from 'soapbox/rtl';
import { textAtCursorMatchesToken } from 'soapbox/utils/suggestions';
import AutosuggestAccount from '../features/compose/components/autosuggest-account';
import { isRtl } from '../rtl';
import AutosuggestEmoji, { Emoji } from './autosuggest-emoji';
import AutosuggestEmoji from './autosuggest-emoji';
import type { List as ImmutableList } from 'immutable';
import type { Emoji } from 'soapbox/features/emoji';
interface IAutosuggesteTextarea {
id?: string,
value: string,
suggestions: ImmutableList<string>,
disabled: boolean,
placeholder: string,
onSuggestionSelected: (tokenStart: number, token: string | null, value: string | undefined) => void,
onSuggestionsClearRequested: () => void,
onSuggestionsFetchRequested: (token: string | number) => void,
onChange: React.ChangeEventHandler<HTMLTextAreaElement>,
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>,
onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>,
onPaste: (files: FileList) => void,
autoFocus: boolean,
onFocus: () => void,
onBlur?: () => void,
condensed?: boolean,
children: React.ReactNode,
id?: string
value: string
suggestions: ImmutableList<string>
disabled: boolean
placeholder: string
onSuggestionSelected: (tokenStart: number, token: string | null, value: string | undefined) => void
onSuggestionsClearRequested: () => void
onSuggestionsFetchRequested: (token: string | number) => void
onChange: React.ChangeEventHandler<HTMLTextAreaElement>
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>
onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>
onPaste: (files: FileList) => void
autoFocus: boolean
onFocus: () => void
onBlur?: () => void
condensed?: boolean
children: React.ReactNode
}
class AutosuggestTextarea extends ImmutablePureComponent<IAutosuggesteTextarea> {

Wyświetl plik

@ -2,8 +2,8 @@ import clsx from 'clsx';
import React from 'react';
interface IBadge {
title: React.ReactNode,
slug: string,
title: React.ReactNode
slug: string
}
/** Badge to display on a user's profile. */
const Badge: React.FC<IBadge> = ({ title, slug }) => {

Wyświetl plik

@ -15,9 +15,9 @@ const messages = defineMessages({
});
interface IBirthdayInput {
value?: string,
onChange: (value: string) => void,
required?: boolean,
value?: string
onChange: (value: string) => void
required?: boolean
}
const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required }) => {
@ -56,15 +56,15 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
nextYearButtonDisabled,
date,
}: {
decreaseMonth(): void,
increaseMonth(): void,
prevMonthButtonDisabled: boolean,
nextMonthButtonDisabled: boolean,
decreaseYear(): void,
increaseYear(): void,
prevYearButtonDisabled: boolean,
nextYearButtonDisabled: boolean,
date: Date,
decreaseMonth(): void
increaseMonth(): void
prevMonthButtonDisabled: boolean
nextMonthButtonDisabled: boolean
decreaseYear(): void
increaseYear(): void
prevYearButtonDisabled: boolean
nextYearButtonDisabled: boolean
date: Date
}) => {
return (
<div className='flex flex-col gap-2'>

Wyświetl plik

@ -3,18 +3,18 @@ import React, { useRef, useEffect } from 'react';
interface IBlurhash {
/** Hash to render */
hash: string | null | undefined,
hash: string | null | undefined
/** Width of the blurred region in pixels. Defaults to 32. */
width?: number,
width?: number
/** Height of the blurred region in pixels. Defaults to width. */
height?: number,
height?: number
/**
* Whether dummy mode is enabled. If enabled, nothing is rendered
* and canvas left untouched.
*/
dummy?: boolean,
dummy?: boolean
/** className of the canvas element. */
className?: string,
className?: string
}
/**

Wyświetl plik

@ -5,7 +5,7 @@ import { Button, HStack, Input } from './ui';
interface ICopyableInput {
/** Text to be copied. */
value: string,
value: string
}
/** An input with copy abilities. */

Wyświetl plik

@ -12,7 +12,7 @@ const messages = defineMessages({
});
interface IDomain {
domain: string,
domain: string
}
const Domain: React.FC<IDomain> = ({ domain }) => {

Wyświetl plik

@ -73,7 +73,7 @@ const DropdownMenuItem = ({ index, item, onClick }: IDropdownMenuItem) => {
}
return (
<li className='truncate focus-within:ring-2 focus-within:ring-primary-500'>
<li className='truncate focus-visible:ring-2 focus-visible:ring-primary-500'>
<a
href={item.href || item.to || '#'}
role='button'

Wyświetl plik

@ -271,6 +271,10 @@ const DropdownMenu = (props: IDropdownMenu) => {
};
}, [refs.floating.current]);
if (items.length === 0) {
return null;
}
return (
<>
{children ? (

Wyświetl plik

@ -31,10 +31,10 @@ interface Props extends ReturnType<typeof mapStateToProps> {
}
type State = {
hasError: boolean,
error: any,
componentStack: any,
browser?: Bowser.Parser.Parser,
hasError: boolean
error: any
componentStack: any
browser?: Bowser.Parser.Parser
}
class ErrorBoundary extends React.PureComponent<Props, State> {

Wyświetl plik

@ -3,14 +3,14 @@ import React, { useEffect, useRef } from 'react';
import { isIOS } from 'soapbox/is-mobile';
interface IExtendedVideoPlayer {
src: string,
alt?: string,
width?: number,
height?: number,
time?: number,
controls?: boolean,
muted?: boolean,
onClick?: () => void,
src: string
alt?: string
width?: number
height?: number
time?: number
controls?: boolean
muted?: boolean
onClick?: () => void
}
const ExtendedVideoPlayer: React.FC<IExtendedVideoPlayer> = ({ src, alt, time, controls, muted, onClick }) => {

Wyświetl plik

@ -9,9 +9,9 @@ import clsx from 'clsx';
import React from 'react';
export interface IForkAwesomeIcon extends React.HTMLAttributes<HTMLLIElement> {
id: string,
className?: string,
fixedWidth?: boolean,
id: string
className?: string
fixedWidth?: boolean
}
const ForkAwesomeIcon: React.FC<IForkAwesomeIcon> = ({ id, className, fixedWidth, ...rest }) => {

Wyświetl plik

@ -1,7 +1,12 @@
import React from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import { Avatar, HStack, Icon, Stack, Text } from './ui';
import GroupMemberCount from 'soapbox/features/group/components/group-member-count';
import GroupPrivacy from 'soapbox/features/group/components/group-privacy';
import GroupRelationship from 'soapbox/features/group/components/group-relationship';
import GroupAvatar from './groups/group-avatar';
import { HStack, Stack, Text } from './ui';
import type { Group as GroupEntity } from 'soapbox/types/entities';
@ -17,43 +22,42 @@ const GroupCard: React.FC<IGroupCard> = ({ group }) => {
const intl = useIntl();
return (
<div className='overflow-hidden'>
<Stack className='rounded-lg border border-solid border-gray-300 bg-white dark:border-primary-800 dark:bg-primary-900 sm:rounded-xl'>
<div className='relative -m-[1px] mb-0 h-[120px] rounded-t-lg bg-primary-100 dark:bg-gray-800 sm:rounded-t-xl'>
{group.header && <img className='h-full w-full rounded-t-lg object-cover sm:rounded-t-xl' src={group.header} alt={intl.formatMessage(messages.groupHeader)} />}
<div className='absolute left-1/2 bottom-0 -translate-x-1/2 translate-y-1/2'>
<Avatar className='ring-2 ring-white dark:ring-primary-900' src={group.avatar} size={64} />
</div>
</div>
<Stack className='p-3 pt-9' alignItems='center' space={3}>
<Text size='lg' weight='bold' dangerouslySetInnerHTML={{ __html: group.display_name_html }} />
<HStack className='text-gray-700 dark:text-gray-600' space={3} wrap>
{group.relationship?.role === 'admin' ? (
<HStack space={1} alignItems='center'>
<Icon className='h-4 w-4' src={require('@tabler/icons/users.svg')} />
<span><FormattedMessage id='group.role.admin' defaultMessage='Admin' /></span>
</HStack>
) : group.relationship?.role === 'moderator' && (
<HStack space={1} alignItems='center'>
<Icon className='h-4 w-4' src={require('@tabler/icons/gavel.svg')} />
<span><FormattedMessage id='group.role.moderator' defaultMessage='Moderator' /></span>
</HStack>
)}
{group.locked ? (
<HStack space={1} alignItems='center'>
<Icon className='h-4 w-4' src={require('@tabler/icons/lock.svg')} />
<span><FormattedMessage id='group.privacy.locked' defaultMessage='Private' /></span>
</HStack>
) : (
<HStack space={1} alignItems='center'>
<Icon className='h-4 w-4' src={require('@tabler/icons/world.svg')} />
<span><FormattedMessage id='group.privacy.public' defaultMessage='Public' /></span>
</HStack>
)}
</HStack>
</Stack>
<Stack
className='relative h-[240px] rounded-lg border border-solid border-gray-300 bg-white dark:border-primary-800 dark:bg-primary-900'
data-testid='group-card'
>
{/* Group Cover Image */}
<Stack grow className='relative basis-1/2 rounded-t-lg bg-primary-100 dark:bg-gray-800'>
{group.header && (
<img
className='absolute inset-0 h-full w-full rounded-t-lg object-cover'
src={group.header} alt={intl.formatMessage(messages.groupHeader)}
/>
)}
</Stack>
</div>
{/* Group Avatar */}
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
<GroupAvatar group={group} size={64} withRing />
</div>
{/* Group Info */}
<Stack alignItems='center' justifyContent='end' grow className='basis-1/2 py-4' space={0.5}>
<HStack alignItems='center' space={1.5}>
<Text size='lg' weight='bold' dangerouslySetInnerHTML={{ __html: group.display_name_html }} />
{group.relationship?.pending_requests && (
<div className='h-2 w-2 rounded-full bg-secondary-500' />
)}
</HStack>
<HStack className='text-gray-700 dark:text-gray-600' space={2} wrap>
<GroupRelationship group={group} />
<GroupPrivacy group={group} />
<GroupMemberCount group={group} />
</HStack>
</Stack>
</Stack>
);
};

Wyświetl plik

@ -0,0 +1,37 @@
import clsx from 'clsx';
import React from 'react';
import { GroupRoles } from 'soapbox/schemas/group-member';
import { Avatar } from '../ui';
import type { Group } from 'soapbox/schemas';
interface IGroupAvatar {
group: Group
size: number
withRing?: boolean
}
const GroupAvatar = (props: IGroupAvatar) => {
const { group, size, withRing = false } = props;
const isOwner = group.relationship?.role === GroupRoles.OWNER;
return (
<Avatar
className={
clsx('relative rounded-full', {
'shadow-[0_0_0_2px_theme(colors.primary.600),0_0_0_4px_theme(colors.white)]': isOwner && withRing,
'dark:shadow-[0_0_0_2px_theme(colors.primary.600),0_0_0_4px_theme(colors.gray.800)]': isOwner && withRing,
'shadow-[0_0_0_2px_theme(colors.primary.600)]': isOwner && !withRing,
'shadow-[0_0_0_2px_theme(colors.white)] dark:shadow-[0_0_0_2px_theme(colors.gray.800)]': !isOwner && withRing,
})
}
src={group.avatar}
size={size}
/>
);
};
export default GroupAvatar;

Wyświetl plik

@ -0,0 +1,99 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { Button, Divider, HStack, Popover, Stack, Text } from 'soapbox/components/ui';
import GroupMemberCount from 'soapbox/features/group/components/group-member-count';
import GroupPrivacy from 'soapbox/features/group/components/group-privacy';
import GroupAvatar from '../group-avatar';
import type { Group } from 'soapbox/schemas';
interface IGroupPopoverContainer {
children: React.ReactElement<any, string | React.JSXElementConstructor<any>>
isEnabled: boolean
group: Group
}
const messages = defineMessages({
title: { id: 'group.popover.title', defaultMessage: 'Membership required' },
summary: { id: 'group.popover.summary', defaultMessage: 'You must be a member of the group in order to reply to this status.' },
action: { id: 'group.popover.action', defaultMessage: 'View Group' },
});
const GroupPopover = (props: IGroupPopoverContainer) => {
const { children, group, isEnabled } = props;
const intl = useIntl();
if (!isEnabled) {
return children;
}
return (
<Popover
interaction='click'
referenceElementClassName='cursor-pointer'
content={
<Stack space={4} className='w-80'>
<Stack
className='relative h-60 rounded-lg bg-white dark:border-primary-800 dark:bg-primary-900'
data-testid='group-card'
>
{/* Group Cover Image */}
<Stack grow className='relative basis-1/2 rounded-t-lg bg-primary-100 dark:bg-gray-800'>
{group.header && (
<img
className='absolute inset-0 h-full w-full rounded-t-lg object-cover'
src={group.header}
alt=''
/>
)}
</Stack>
{/* Group Avatar */}
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
<GroupAvatar group={group} size={64} withRing />
</div>
{/* Group Info */}
<Stack alignItems='center' justifyContent='end' grow className='basis-1/2 py-4' space={0.5}>
<Text size='lg' weight='bold' dangerouslySetInnerHTML={{ __html: group.display_name_html }} />
<HStack className='text-gray-700 dark:text-gray-600' space={2} wrap>
<GroupPrivacy group={group} />
<GroupMemberCount group={group} />
</HStack>
</Stack>
</Stack>
<Divider />
<Stack space={0.5} className='px-4'>
<Text weight='semibold'>
{intl.formatMessage(messages.title)}
</Text>
<Text theme='muted'>
{intl.formatMessage(messages.summary)}
</Text>
</Stack>
<div className='px-4 pb-4'>
<Link to={`/groups/${group.id}`}>
<Button type='button' theme='secondary' block>
{intl.formatMessage(messages.action)}
</Button>
</Link>
</div>
</Stack>
}
isFlush
children={
<div className='inline-block'>{children}</div>
}
/>
);
};
export default GroupPopover;

Wyświetl plik

@ -10,7 +10,7 @@ import { HStack, Stack, Text } from './ui';
import type { Tag } from 'soapbox/types/entities';
interface IHashtag {
hashtag: Tag,
hashtag: Tag
}
const Hashtag: React.FC<IHashtag> = ({ hashtag }) => {

Wyświetl plik

@ -15,10 +15,10 @@ const showProfileHoverCard = debounce((dispatch, ref, accountId) => {
}, 600);
interface IHoverRefWrapper {
accountId: string,
inline?: boolean,
className?: string,
children: React.ReactNode,
accountId: string
inline?: boolean
className?: string
children: React.ReactNode
}
/** Makes a profile hover card appear when the wrapped element is hovered. */

Wyświetl plik

@ -14,10 +14,10 @@ const showStatusHoverCard = debounce((dispatch, ref, statusId) => {
}, 300);
interface IHoverStatusWrapper {
statusId: any,
inline: boolean,
className?: string,
children: React.ReactNode,
statusId: any
inline: boolean
className?: string
children: React.ReactNode
}
/** Makes a status hover card appear when the wrapped element is hovered. */

Wyświetl plik

@ -4,10 +4,10 @@ import Icon, { IIcon } from 'soapbox/components/icon';
import { Counter } from 'soapbox/components/ui';
interface IIconWithCounter extends React.HTMLAttributes<HTMLDivElement> {
count: number,
count: number
countMax?: number
icon?: string;
src?: string;
icon?: string
src?: string
}
const IconWithCounter: React.FC<IIconWithCounter> = ({ icon, count, countMax, ...rest }) => {

Wyświetl plik

@ -8,12 +8,15 @@ import React from 'react';
import InlineSVG from 'react-inlinesvg'; // eslint-disable-line no-restricted-imports
export interface IIcon extends React.HTMLAttributes<HTMLDivElement> {
src: string,
id?: string,
alt?: string,
className?: string,
src: string
id?: string
alt?: string
className?: string
}
/**
* @deprecated Use the UI Icon component directly.
*/
const Icon: React.FC<IIcon> = ({ src, alt, className, ...rest }) => {
return (
<div

Wyświetl plik

@ -4,8 +4,7 @@ import { v4 as uuidv4 } from 'uuid';
import { SelectDropdown } from '../features/forms';
import Icon from './icon';
import { HStack, Select } from './ui';
import { Icon, HStack, Select } from './ui';
interface IList {
children: React.ReactNode
@ -16,9 +15,9 @@ const List: React.FC<IList> = ({ children }) => (
);
interface IListItem {
label: React.ReactNode,
hint?: React.ReactNode,
onClick?(): void,
label: React.ReactNode
hint?: React.ReactNode
onClick?(): void
onSelect?(): void
isSelected?: boolean
children?: React.ReactNode
@ -58,13 +57,13 @@ const ListItem: React.FC<IListItem> = ({ label, hint, children, onClick, onSelec
return (
<Comp
className={clsx({
'flex items-center justify-between px-3 py-2 first:rounded-t-lg last:rounded-b-lg bg-gradient-to-r from-gradient-start/10 to-gradient-end/10': true,
'cursor-pointer hover:from-gradient-start/20 hover:to-gradient-end/20 dark:hover:from-gradient-start/5 dark:hover:to-gradient-end/5': typeof onClick !== 'undefined' || typeof onSelect !== 'undefined',
'flex items-center justify-between px-4 py-2 first:rounded-t-lg last:rounded-b-lg bg-gradient-to-r from-gradient-start/20 to-gradient-end/20 dark:from-gradient-start/10 dark:to-gradient-end/10': true,
'cursor-pointer hover:from-gradient-start/30 hover:to-gradient-end/30 dark:hover:from-gradient-start/5 dark:hover:to-gradient-end/5': typeof onClick !== 'undefined' || typeof onSelect !== 'undefined',
})}
{...linkProps}
>
<div className='flex flex-col py-1.5 pr-4 rtl:pl-4 rtl:pr-0'>
<LabelComp className='text-gray-900 dark:text-gray-100' htmlFor={domId}>{label}</LabelComp>
<LabelComp className='font-medium text-gray-900 dark:text-gray-100' htmlFor={domId}>{label}</LabelComp>
{hint ? (
<span className='text-sm text-gray-700 dark:text-gray-600'>{hint}</span>
@ -83,9 +82,26 @@ const ListItem: React.FC<IListItem> = ({ label, hint, children, onClick, onSelec
<div className='flex flex-row items-center text-gray-700 dark:text-gray-600'>
{children}
{isSelected ? (
<Icon src={require('@tabler/icons/check.svg')} className='ml-1 text-primary-500 dark:text-primary-400' />
) : null}
<div
className={
clsx({
'flex h-6 w-6 items-center justify-center rounded-full border-2 border-solid border-primary-500 dark:border-primary-400 transition': true,
'bg-primary-500 dark:bg-primary-400': isSelected,
'bg-transparent': !isSelected,
})
}
>
<Icon
src={require('@tabler/icons/check.svg')}
className={
clsx({
'h-4 w-4 text-white dark:text-white transition-all duration-500': true,
'opacity-0 scale-50': !isSelected,
'opacity-100 scale-100': isSelected,
})
}
/>
</div>
</div>
) : null}

Wyświetl plik

@ -8,9 +8,9 @@ const messages = defineMessages({
});
interface ILoadGap {
disabled?: boolean,
maxId: string,
onClick: (id: string) => void,
disabled?: boolean
maxId: string
onClick: (id: string) => void
}
const LoadGap: React.FC<ILoadGap> = ({ disabled, maxId, onClick }) => {

Wyświetl plik

@ -4,18 +4,19 @@ import { FormattedMessage } from 'react-intl';
import { Button } from 'soapbox/components/ui';
interface ILoadMore {
onClick: React.MouseEventHandler,
disabled?: boolean,
visible?: Boolean,
onClick: React.MouseEventHandler
disabled?: boolean
visible?: boolean
className?: string
}
const LoadMore: React.FC<ILoadMore> = ({ onClick, disabled, visible = true }) => {
const LoadMore: React.FC<ILoadMore> = ({ onClick, disabled, visible = true, className }) => {
if (!visible) {
return null;
}
return (
<Button theme='primary' block disabled={disabled || !visible} onClick={onClick}>
<Button className={className} theme='primary' block disabled={disabled || !visible} onClick={onClick}>
<FormattedMessage id='status.load_more' defaultMessage='Load more' />
</Button>
);

Wyświetl plik

@ -18,7 +18,7 @@ const messages = defineMessages({
});
interface ILocationSearch {
onSelected: (locationId: string) => void,
onSelected: (locationId: string) => void
}
const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {

Wyświetl plik

@ -19,21 +19,21 @@ const ATTACHMENT_LIMIT = 4;
const MAX_FILENAME_LENGTH = 45;
interface Dimensions {
w: Property.Width | number,
h: Property.Height | number,
t?: Property.Top,
r?: Property.Right,
b?: Property.Bottom,
l?: Property.Left,
float?: Property.Float,
pos?: Property.Position,
w: Property.Width | number
h: Property.Height | number
t?: Property.Top
r?: Property.Right
b?: Property.Bottom
l?: Property.Left
float?: Property.Float
pos?: Property.Position
}
interface SizeData {
style: React.CSSProperties,
itemsDimensions: Dimensions[],
size: number,
width: number,
style: React.CSSProperties
itemsDimensions: Dimensions[]
size: number
width: number
}
const withinLimits = (aspectRatio: number) => {
@ -48,16 +48,16 @@ const shouldLetterbox = (attachment: Attachment): boolean => {
};
interface IItem {
attachment: Attachment,
standalone?: boolean,
index: number,
size: number,
onClick: (index: number) => void,
displayWidth?: number,
visible: boolean,
dimensions: Dimensions,
last?: boolean,
total: number,
attachment: Attachment
standalone?: boolean
index: number
size: number
onClick: (index: number) => void
displayWidth?: number
visible: boolean
dimensions: Dimensions
last?: boolean
total: number
}
const Item: React.FC<IItem> = ({
@ -152,7 +152,14 @@ const Item: React.FC<IItem> = ({
);
return (
<div className={clsx('media-gallery__item', { standalone })} key={attachment.id} style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}>
<div
className={clsx('media-gallery__item', {
standalone,
'rounded-md': total > 1,
})}
key={attachment.id}
style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}
>
<a className='media-gallery__item-thumbnail' href={attachment.url} target='_blank' style={{ cursor: 'pointer' }}>
<Blurhash hash={attachment.blurhash} className='media-gallery__preview' />
<span className='media-gallery__item__icons'>{attachmentIcon}</span>
@ -245,7 +252,14 @@ const Item: React.FC<IItem> = ({
}
return (
<div className={clsx('media-gallery__item', `media-gallery__item--${attachment.type}`, { standalone })} key={attachment.id} style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}>
<div
className={clsx('media-gallery__item', `media-gallery__item--${attachment.type}`, {
standalone,
'rounded-md': total > 1,
})}
key={attachment.id}
style={{ position, float, left, top, right, bottom, height, width: `${width}%` }}
>
{last && total > ATTACHMENT_LIMIT && (
<div className='media-gallery__item-overflow'>
+{total - ATTACHMENT_LIMIT + 1}
@ -260,23 +274,25 @@ const Item: React.FC<IItem> = ({
);
};
interface IMediaGallery {
sensitive?: boolean,
media: ImmutableList<Attachment>,
height?: number,
onOpenMedia: (media: ImmutableList<Attachment>, index: number) => void,
defaultWidth?: number,
cacheWidth?: (width: number) => void,
visible?: boolean,
onToggleVisibility?: () => void,
displayMedia?: string,
compact: boolean,
export interface IMediaGallery {
sensitive?: boolean
media: ImmutableList<Attachment>
height?: number
onOpenMedia: (media: ImmutableList<Attachment>, index: number) => void
defaultWidth?: number
cacheWidth?: (width: number) => void
visible?: boolean
onToggleVisibility?: () => void
displayMedia?: string
compact?: boolean
className?: string
}
const MediaGallery: React.FC<IMediaGallery> = (props) => {
const {
media,
defaultWidth = 0,
className,
onOpenMedia,
cacheWidth,
compact,
@ -546,7 +562,11 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
}, [node.current]);
return (
<div className={clsx('media-gallery', { 'media-gallery--compact': compact })} style={sizeData.style} ref={node}>
<div
className={clsx(className, 'media-gallery', { 'media-gallery--compact': compact })}
style={sizeData.style}
ref={node}
>
{children}
</div>
);

Wyświetl plik

@ -39,10 +39,10 @@ export const checkEventComposeContent = (compose?: ReturnType<typeof ReducerComp
};
interface IModalRoot {
onCancel?: () => void,
onClose: (type?: ModalType) => void,
type: ModalType,
children: React.ReactNode,
onCancel?: () => void
onClose: (type?: ModalType) => void
type: ModalType
children: React.ReactNode
}
const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type }) => {

Wyświetl plik

@ -2,8 +2,8 @@ import clsx from 'clsx';
import React from 'react';
interface IOutlineBox extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode,
className?: string,
children: React.ReactNode
className?: string
}
/** Wraps children in a container with an outline. */

Wyświetl plik

@ -0,0 +1,54 @@
import clsx from 'clsx';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import { HStack, Icon, Text } from 'soapbox/components/ui';
interface IPendingItemsRow {
/** Path to navigate the user when clicked. */
to: string
/** Number of pending items. */
count: number
/** Size of the icon. */
size?: 'md' | 'lg'
}
const PendingItemsRow: React.FC<IPendingItemsRow> = ({ to, count, size = 'md' }) => {
return (
<Link to={to} className='group' data-testid='pending-items-row'>
<HStack alignItems='center' justifyContent='between'>
<HStack alignItems='center' space={2}>
<div className={clsx('rounded-full bg-primary-200 text-primary-500 dark:bg-primary-800 dark:text-primary-200', {
'p-3': size === 'lg',
'p-2.5': size === 'md',
})}
>
<Icon
src={require('@tabler/icons/exclamation-circle.svg')}
className={clsx({
'h-5 w-5': size === 'md',
'h-7 w-7': size === 'lg',
})}
/>
</div>
<Text weight='bold' size='md'>
<FormattedMessage
id='groups.pending.count'
defaultMessage='{number, plural, one {# pending request} other {# pending requests}}'
values={{ number: count }}
/>
</Text>
</HStack>
<Icon
src={require('@tabler/icons/chevron-right.svg')}
className='h-5 w-5 text-gray-600 transition-colors group-hover:text-gray-700 dark:text-gray-600 dark:group-hover:text-gray-500'
/>
</HStack>
</Link>
);
};
export { PendingItemsRow };

Wyświetl plik

@ -16,9 +16,9 @@ const messages = defineMessages({
});
interface IPollFooter {
poll: PollEntity,
showResults: boolean,
selected: Selected,
poll: PollEntity
showResults: boolean
selected: Selected
}
const PollFooter: React.FC<IPollFooter> = ({ poll, showResults, selected }): JSX.Element => {

Wyświetl plik

@ -29,7 +29,7 @@ const PollPercentageBar: React.FC<{ percent: number, leading: boolean }> = ({ pe
};
interface IPollOptionText extends IPollOption {
percent: number,
percent: number
}
const PollOptionText: React.FC<IPollOptionText> = ({ poll, option, index, active, onToggle }) => {
@ -95,12 +95,12 @@ const PollOptionText: React.FC<IPollOptionText> = ({ poll, option, index, active
};
interface IPollOption {
poll: PollEntity,
option: PollOptionEntity,
index: number,
showResults?: boolean,
active: boolean,
onToggle: (value: number) => void,
poll: PollEntity
option: PollOptionEntity
index: number
showResults?: boolean
active: boolean
onToggle: (value: number) => void
}
const PollOption: React.FC<IPollOption> = (props): JSX.Element | null => {

Wyświetl plik

@ -13,8 +13,8 @@ import PollOption from './poll-option';
export type Selected = Record<number, boolean>;
interface IPoll {
id: string,
status?: string,
id: string
status?: string
}
const messages = defineMessages({

Wyświetl plik

@ -54,7 +54,7 @@ const handleMouseLeave = (dispatch: AppDispatch): React.MouseEventHandler => {
};
interface IProfileHoverCard {
visible: boolean,
visible: boolean
}
/** Popup profile preview that appears when hovering avatars and display names. */

Wyświetl plik

@ -2,10 +2,10 @@ import clsx from 'clsx';
import React from 'react';
interface IProgressCircle {
progress: number,
radius?: number,
stroke?: number,
title?: string,
progress: number
radius?: number
stroke?: number
title?: string
}
const ProgressCircle: React.FC<IProgressCircle> = ({ progress, radius = 12, stroke = 4, title }) => {

Wyświetl plik

@ -4,10 +4,10 @@ import PTRComponent from 'react-simple-pull-to-refresh';
import { Spinner } from 'soapbox/components/ui';
interface IPullToRefresh {
onRefresh?: () => Promise<any>;
refreshingContent?: JSX.Element | string;
pullingContent?: JSX.Element | string;
children: React.ReactNode;
onRefresh?: () => Promise<any>
refreshingContent?: JSX.Element | string
pullingContent?: JSX.Element | string
children: React.ReactNode
}
/**

Wyświetl plik

@ -3,7 +3,7 @@ import React from 'react';
import PullToRefresh from './pull-to-refresh';
interface IPullable {
children: React.ReactNode,
children: React.ReactNode
}
/**

Wyświetl plik

@ -23,11 +23,11 @@ const messages = defineMessages({
interface IQuotedStatus {
/** The quoted status entity. */
status?: StatusEntity,
status?: StatusEntity
/** Callback when cancelled (during compose). */
onCancel?: Function,
onCancel?: Function
/** Whether the status is shown in the post composer. */
compose?: boolean,
compose?: boolean
}
/** Status embedded in a quote post. */

Wyświetl plik

@ -16,11 +16,11 @@ const RadioGroup = ({ onChange, children }: IRadioGroup) => {
};
interface IRadioItem {
label: React.ReactNode,
hint?: React.ReactNode,
value: string,
checked: boolean,
onChange?: React.ChangeEventHandler,
label: React.ReactNode
hint?: React.ReactNode
value: string
checked: boolean
onChange?: React.ChangeEventHandler
}
const RadioItem: React.FC<IRadioItem> = ({ label, hint, checked = false, onChange, value }) => {

Wyświetl plik

@ -113,14 +113,14 @@ const timeRemainingString = (intl: IntlShape, date: Date, now: number) => {
};
interface RelativeTimestampProps extends IText {
intl: IntlShape,
timestamp: string,
year?: number,
futureDate?: boolean,
intl: IntlShape
timestamp: string
year?: number
futureDate?: boolean
}
interface RelativeTimestampState {
now: number,
now: number
}
/** Displays a timestamp compared to the current time, eg "1m" for one minute ago. */

Wyświetl plik

@ -2,13 +2,13 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
interface ISafeEmbed {
/** Styles for the outer frame element. */
className?: string,
className?: string
/** Space-separate list of restrictions to ALLOW for the iframe. */
sandbox?: string,
sandbox?: string
/** Unique title for the iframe. */
title: string,
title: string
/** HTML body to embed. */
html?: string,
html?: string
}
/** Safely embeds arbitrary HTML content on the page (by putting it in an iframe). */

Wyświetl plik

@ -9,15 +9,15 @@ import { useSettings } from 'soapbox/hooks';
interface IScrollTopButton {
/** Callback when clicked, and also when scrolled to the top. */
onClick: () => void,
onClick: () => void
/** Number of unread items. */
count: number,
count: number
/** Message to display in the button (should contain a `{count}` value). */
message: MessageDescriptor,
message: MessageDescriptor
/** Distance from the top of the screen (scrolling down) before the button appears. */
threshold?: number,
threshold?: number
/** Distance from the top of the screen (scrolling up) before the action is triggered. */
autoloadThreshold?: number,
autoloadThreshold?: number
}
/** Floating new post counter above timelines, clicked to scroll to top. */

Wyświetl plik

@ -10,14 +10,14 @@ import { Card, Spinner } from './ui';
/** Custom Viruoso component context. */
type Context = {
itemClassName?: string,
listClassName?: string,
itemClassName?: string
listClassName?: string
}
/** Scroll position saved in sessionStorage. */
type SavedScrollPosition = {
index: number,
offset: number,
index: number
offset: number
}
/** Custom Virtuoso Item component representing a single scrollable item. */
@ -37,44 +37,46 @@ const List: Components<JSX.Element, Context>['List'] = React.forwardRef((props,
interface IScrollableList extends VirtuosoProps<any, any> {
/** Unique key to preserve the scroll position when navigating back. */
scrollKey?: string,
scrollKey?: string
/** Pagination callback when the end of the list is reached. */
onLoadMore?: () => void,
onLoadMore?: () => void
/** Whether the data is currently being fetched. */
isLoading?: boolean,
isLoading?: boolean
/** Whether to actually display the loading state. */
showLoading?: boolean,
showLoading?: boolean
/** Whether we expect an additional page of data. */
hasMore?: boolean,
hasMore?: boolean
/** Additional element to display at the top of the list. */
prepend?: React.ReactNode,
prepend?: React.ReactNode
/** Whether to display the prepended element. */
alwaysPrepend?: boolean,
alwaysPrepend?: boolean
/** Message to display when the list is loaded but empty. */
emptyMessage?: React.ReactNode,
emptyMessage?: React.ReactNode
/** Should the empty message be displayed in a Card */
emptyMessageCard?: boolean
/** Scrollable content. */
children: Iterable<React.ReactNode>,
children: Iterable<React.ReactNode>
/** Callback when the list is scrolled to the top. */
onScrollToTop?: () => void,
onScrollToTop?: () => void
/** Callback when the list is scrolled. */
onScroll?: () => void,
onScroll?: () => void
/** Placeholder component to render while loading. */
placeholderComponent?: React.ComponentType | React.NamedExoticComponent,
placeholderComponent?: React.ComponentType | React.NamedExoticComponent
/** Number of placeholders to render while loading. */
placeholderCount?: number,
placeholderCount?: number
/**
* Pull to refresh callback.
* @deprecated Put a PTR around the component instead.
*/
onRefresh?: () => Promise<any>,
onRefresh?: () => Promise<any>
/** Extra class names on the Virtuoso element. */
className?: string,
className?: string
/** Class names on each item container. */
itemClassName?: string,
itemClassName?: string
/** `id` attribute on the Virtuoso element. */
id?: string,
id?: string
/** CSS styles on the Virtuoso element. */
style?: React.CSSProperties,
style?: React.CSSProperties
/** Whether to use the window to scroll the content instead of Virtuoso's container. */
useWindowScroll?: boolean
}
@ -87,6 +89,7 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
children,
isLoading,
emptyMessage,
emptyMessageCard = true,
showLoading,
onRefresh,
onScroll,
@ -158,13 +161,17 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
<div className='mt-2'>
{alwaysPrepend && prepend}
<Card variant='rounded' size='lg'>
{isLoading ? (
<Spinner />
) : (
emptyMessage
)}
</Card>
{isLoading ? (
<Spinner />
) : (
<>
{emptyMessageCard ? (
<Card variant='rounded' size='lg'>
{emptyMessage}
</Card>
) : emptyMessage}
</>
)}
</div>
);
};

Wyświetl plik

@ -10,7 +10,7 @@ import { closeSidebar } from 'soapbox/actions/sidebar';
import Account from 'soapbox/components/account';
import { Stack } from 'soapbox/components/ui';
import ProfileStats from 'soapbox/features/ui/components/profile-stats';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useGroupsPath, useFeatures } from 'soapbox/hooks';
import { makeGetAccount, makeGetOtherAccounts } from 'soapbox/selectors';
import { Divider, HStack, Icon, IconButton, Text } from './ui';
@ -43,11 +43,11 @@ const messages = defineMessages({
});
interface ISidebarLink {
href?: string,
to?: string,
icon: string,
text: string | JSX.Element,
onClick: React.EventHandler<React.MouseEvent>,
href?: string
to?: string
icon: string
text: string | JSX.Element
onClick: React.EventHandler<React.MouseEvent>
}
const SidebarLink: React.FC<ISidebarLink> = ({ href, to, icon, text, onClick }) => {
@ -90,6 +90,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
const sidebarOpen = useAppSelector((state) => state.sidebar.sidebarOpen);
const settings = useAppSelector((state) => getSettings(state));
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
const groupsPath = useGroupsPath();
const closeButtonRef = React.useRef(null);
@ -210,7 +211,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
{features.groups && (
<SidebarLink
to='/groups'
to={groupsPath}
icon={require('@tabler/icons/circles.svg')}
text={intl.formatMessage(messages.groups)}
onClick={onClose}
@ -296,7 +297,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
/>
)}
{features.filters && (
{(features.filters || features.filtersV2) && (
<SidebarLink
to='/filters'
icon={require('@tabler/icons/filter.svg')}

Wyświetl plik

@ -6,17 +6,17 @@ import { Icon, Text } from './ui';
interface ISidebarNavigationLink {
/** Notification count, if any. */
count?: number,
count?: number
/** Optional max to cap count (ie: N+) */
countMax?: number
/** URL to an SVG icon. */
icon: string,
icon: string
/** Link label. */
text: React.ReactNode,
text: React.ReactNode
/** Route to an internal page. */
to?: string,
to?: string
/** Callback when the link is clicked. */
onClick?: React.EventHandler<React.MouseEvent>,
onClick?: React.EventHandler<React.MouseEvent>
}
/** Desktop sidebar navigation link. */

Wyświetl plik

@ -4,7 +4,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { Stack } from 'soapbox/components/ui';
import { useStatContext } from 'soapbox/contexts/stat-context';
import ComposeButton from 'soapbox/features/ui/components/compose-button';
import { useAppSelector, useFeatures, useOwnAccount, useSettings } from 'soapbox/hooks';
import { useAppSelector, useGroupsPath, useFeatures, useOwnAccount, useSettings } from 'soapbox/hooks';
import DropdownMenu, { Menu } from './dropdown-menu';
import SidebarNavigationLink from './sidebar-navigation-link';
@ -25,6 +25,8 @@ const SidebarNavigation = () => {
const features = useFeatures();
const settings = useSettings();
const account = useOwnAccount();
const groupsPath = useGroupsPath();
const notificationCount = useAppSelector((state) => state.notifications.unread);
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
@ -135,7 +137,7 @@ const SidebarNavigation = () => {
{features.groups && (
<SidebarNavigationLink
to='/groups'
to={groupsPath}
icon={require('@tabler/icons/circles.svg')}
text={<FormattedMessage id='tabs_bar.groups' defaultMessage='Groups' />}
/>

Wyświetl plik

@ -5,9 +5,9 @@ import { useSoapboxConfig, useSettings, useTheme } from 'soapbox/hooks';
interface ISiteLogo extends React.ComponentProps<'img'> {
/** Extra class names for the <img> element. */
className?: string,
className?: string
/** Override theme setting for <SitePreview /> */
theme?: 'dark' | 'light',
theme?: 'dark' | 'light'
}
/** Display the most appropriate site logo based on the theme and configuration. */

Wyświetl plik

@ -8,11 +8,11 @@ import { launchChat } from 'soapbox/actions/chats';
import { directCompose, mentionCompose, quoteCompose, replyCompose } from 'soapbox/actions/compose';
import { editEvent } from 'soapbox/actions/events';
import { groupBlock, groupDeleteStatus, groupKick } from 'soapbox/actions/groups';
import { toggleBookmark, toggleFavourite, togglePin, toggleReblog } from 'soapbox/actions/interactions';
import { toggleBookmark, toggleDislike, toggleFavourite, togglePin, toggleReblog } from 'soapbox/actions/interactions';
import { openModal } from 'soapbox/actions/modals';
import { deleteStatusModal, toggleStatusSensitivityModal } from 'soapbox/actions/moderation';
import { initMuteModal } from 'soapbox/actions/mutes';
import { initReport } from 'soapbox/actions/reports';
import { initReport, ReportableEntities } from 'soapbox/actions/reports';
import { deleteStatus, editStatus, toggleMuteStatus } from 'soapbox/actions/statuses';
import DropdownMenu from 'soapbox/components/dropdown-menu';
import StatusActionButton from 'soapbox/components/status-action-button';
@ -24,6 +24,8 @@ import { isLocal, isRemote } from 'soapbox/utils/accounts';
import copy from 'soapbox/utils/copy';
import { getReactForStatus, reduceEmoji } from 'soapbox/utils/emoji-reacts';
import GroupPopover from './groups/popover/group-popover';
import type { Menu } from 'soapbox/components/dropdown-menu';
import type { Account, Group, Status } from 'soapbox/types/entities';
@ -45,6 +47,7 @@ const messages = defineMessages({
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Un-repost' },
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be reposted' },
favourite: { id: 'status.favourite', defaultMessage: 'Like' },
disfavourite: { id: 'status.disfavourite', defaultMessage: 'Disike' },
open: { id: 'status.open', defaultMessage: 'Expand this post' },
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
unbookmark: { id: 'status.unbookmark', defaultMessage: 'Remove bookmark' },
@ -97,10 +100,10 @@ const messages = defineMessages({
});
interface IStatusActionBar {
status: Status,
withLabels?: boolean,
expandable?: boolean,
space?: 'expand' | 'compact',
status: Status
withLabels?: boolean
expandable?: boolean
space?: 'expand' | 'compact'
}
const StatusActionBar: React.FC<IStatusActionBar> = ({
@ -161,6 +164,14 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
}
};
const handleDislikeClick: React.EventHandler<React.MouseEvent> = (e) => {
if (me) {
dispatch(toggleDislike(status));
} else {
onOpenUnauthorizedModal('DISLIKE');
}
};
const handleBookmarkClick: React.EventHandler<React.MouseEvent> = (e) => {
dispatch(toggleBookmark(status));
};
@ -254,7 +265,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
secondary: intl.formatMessage(messages.blockAndReport),
onSecondary: () => {
dispatch(blockAccount(account.id));
dispatch(initReport(account, { status }));
dispatch(initReport(ReportableEntities.STATUS, account, { status }));
},
}));
};
@ -271,7 +282,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const handleReport: React.EventHandler<React.MouseEvent> = (e) => {
dispatch(initReport(status.account as Account, { status }));
dispatch(initReport(ReportableEntities.STATUS, status.account as Account, { status }));
};
const handleConversationMuteClick: React.EventHandler<React.MouseEvent> = (e) => {
@ -538,7 +549,8 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
allowedEmoji,
).reduce((acc, cur) => acc + cur.get('count'), 0);
const meEmojiReact = getReactForStatus(status, allowedEmoji) as keyof typeof reactMessages | undefined;
const meEmojiReact = getReactForStatus(status, allowedEmoji);
const meEmojiName = meEmojiReact?.get('name') as keyof typeof reactMessages | undefined;
const reactMessages = {
'👍': messages.reactionLike,
@ -550,7 +562,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
'': messages.favourite,
};
const meEmojiTitle = intl.formatMessage(reactMessages[meEmojiReact || ''] || messages.favourite);
const meEmojiTitle = intl.formatMessage(reactMessages[meEmojiName || ''] || messages.favourite);
const menu = _makeMenu(publicStatus);
let reblogIcon = require('@tabler/icons/repeat.svg');
@ -607,14 +619,19 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
grow={space === 'expand'}
onClick={e => e.stopPropagation()}
>
<StatusActionButton
title={replyTitle}
icon={require('@tabler/icons/message-circle-2.svg')}
onClick={handleReplyClick}
count={replyCount}
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
disabled={replyDisabled}
/>
<GroupPopover
group={status.group as any}
isEnabled={replyDisabled}
>
<StatusActionButton
title={replyTitle}
icon={require('@tabler/icons/message-circle-2.svg')}
onClick={handleReplyClick}
count={replyCount}
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
disabled={replyDisabled}
/>
</GroupPopover>
{(features.quotePosts && me) ? (
<DropdownMenu
@ -635,7 +652,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
icon={require('@tabler/icons/heart.svg')}
filled
color='accent'
active={Boolean(meEmojiReact)}
active={Boolean(meEmojiName)}
count={emojiReactCount}
emoji={meEmojiReact}
text={withLabels ? meEmojiTitle : undefined}
@ -644,16 +661,29 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
) : (
<StatusActionButton
title={intl.formatMessage(messages.favourite)}
icon={require('@tabler/icons/heart.svg')}
icon={features.dislikes ? require('@tabler/icons/thumb-up.svg') : require('@tabler/icons/heart.svg')}
color='accent'
filled
onClick={handleFavouriteClick}
active={Boolean(meEmojiReact)}
active={Boolean(meEmojiName)}
count={favouriteCount}
text={withLabels ? meEmojiTitle : undefined}
/>
)}
{features.dislikes && (
<StatusActionButton
title={intl.formatMessage(messages.disfavourite)}
icon={require('@tabler/icons/thumb-down.svg')}
color='accent'
filled
onClick={handleDislikeClick}
active={status.disliked}
count={status.dislikes_count}
text={withLabels ? intl.formatMessage(messages.disfavourite) : undefined}
/>
)}
{canShare && (
<StatusActionButton
title={intl.formatMessage(messages.share)}

Wyświetl plik

@ -4,6 +4,8 @@ import React from 'react';
import { Text, Icon, Emoji } from 'soapbox/components/ui';
import { shortNumberFormat } from 'soapbox/utils/numbers';
import type { Map as ImmutableMap } from 'immutable';
const COLORS = {
accent: 'accent',
success: 'success',
@ -12,7 +14,7 @@ const COLORS = {
type Color = keyof typeof COLORS;
interface IStatusActionCounter {
count: number,
count: number
}
/** Action button numerical counter, eg "5" likes. */
@ -25,14 +27,14 @@ const StatusActionCounter: React.FC<IStatusActionCounter> = ({ count = 0 }): JSX
};
interface IStatusActionButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {
iconClassName?: string,
icon: string,
count?: number,
active?: boolean,
color?: Color,
filled?: boolean,
emoji?: string,
text?: React.ReactNode,
iconClassName?: string
icon: string
count?: number
active?: boolean
color?: Color
filled?: boolean
emoji?: ImmutableMap<string, any>
text?: React.ReactNode
}
const StatusActionButton = React.forwardRef<HTMLButtonElement, IStatusActionButton>((props, ref): JSX.Element => {
@ -42,7 +44,7 @@ const StatusActionButton = React.forwardRef<HTMLButtonElement, IStatusActionButt
if (emoji) {
return (
<span className='flex h-6 w-6 items-center justify-center'>
<Emoji className='h-full w-full p-0.5' emoji={emoji} />
<Emoji className='h-full w-full p-0.5' emoji={emoji.get('name')} src={emoji.get('url')} />
</span>
);
} else {

Wyświetl plik

@ -20,7 +20,7 @@ const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
const BIG_EMOJI_LIMIT = 10;
interface IReadMoreButton {
onClick: React.MouseEventHandler,
onClick: React.MouseEventHandler
}
/** Button to expand a truncated status (due to too much content) */
@ -32,11 +32,11 @@ const ReadMoreButton: React.FC<IReadMoreButton> = ({ onClick }) => (
);
interface IStatusContent {
status: Status,
onClick?: () => void,
collapsable?: boolean,
translatable?: boolean,
textSize?: Sizes,
status: Status
onClick?: () => void
collapsable?: boolean
translatable?: boolean
textSize?: Sizes
}
/** Renders the text content of a status */

Wyświetl plik

@ -15,7 +15,7 @@ import { showStatusHoverCard } from './hover-status-wrapper';
import { Card, CardBody } from './ui';
interface IStatusHoverCard {
visible: boolean,
visible: boolean
}
/** Popup status preview that appears when hovering reply to */

Wyświetl plik

@ -23,31 +23,31 @@ import type { Ad as AdEntity } from 'soapbox/types/soapbox';
interface IStatusList extends Omit<IScrollableList, 'onLoadMore' | 'children'> {
/** Unique key to preserve the scroll position when navigating back. */
scrollKey: string,
scrollKey: string
/** List of status IDs to display. */
statusIds: ImmutableOrderedSet<string>,
statusIds: ImmutableOrderedSet<string>
/** Last _unfiltered_ status ID (maxId) for pagination. */
lastStatusId?: string,
lastStatusId?: string
/** Pinned statuses to show at the top of the feed. */
featuredStatusIds?: ImmutableOrderedSet<string>,
featuredStatusIds?: ImmutableOrderedSet<string>
/** Pagination callback when the end of the list is reached. */
onLoadMore?: (lastStatusId: string) => void,
onLoadMore?: (lastStatusId: string) => void
/** Whether the data is currently being fetched. */
isLoading: boolean,
isLoading: boolean
/** Whether the server did not return a complete page. */
isPartial?: boolean,
isPartial?: boolean
/** Whether we expect an additional page of data. */
hasMore: boolean,
hasMore: boolean
/** Message to display when the list is loaded but empty. */
emptyMessage: React.ReactNode,
emptyMessage: React.ReactNode
/** ID of the timeline in Redux. */
timelineId?: string,
timelineId?: string
/** Whether to display a gap or border between statuses in the list. */
divideType?: 'space' | 'border',
divideType?: 'space' | 'border'
/** Whether to display ads. */
showAds?: boolean,
showAds?: boolean
/** Whether to show group information. */
showGroup?: boolean,
showGroup?: boolean
}
/** Feed of statuses, built atop ScrollableList. */

Wyświetl plik

@ -15,15 +15,15 @@ import type { Status, Attachment } from 'soapbox/types/entities';
interface IStatusMedia {
/** Status entity to render media for. */
status: Status,
status: Status
/** Whether to display compact media. */
muted?: boolean,
muted?: boolean
/** Callback when compact media is clicked. */
onClick?: () => void,
onClick?: () => void
/** Whether or not the media is concealed behind a NSFW banner. */
showMedia?: boolean,
showMedia?: boolean
/** Callback when visibility is toggled (eg clicked through NSFW). */
onToggleVisibility?: () => void,
onToggleVisibility?: () => void
}
/** Render media attachments for a status. */

Wyświetl plik

@ -8,8 +8,8 @@ import { isUserTouching } from 'soapbox/is-mobile';
import { getReactForStatus } from 'soapbox/utils/emoji-reacts';
interface IStatusReactionWrapper {
statusId: string,
children: JSX.Element,
statusId: string
children: JSX.Element
}
/** Provides emoji reaction functionality to the underlying button component */
@ -60,9 +60,9 @@ const StatusReactionWrapper: React.FC<IStatusReactionWrapper> = ({ statusId, chi
}
};
const handleReact = (emoji: string): void => {
const handleReact = (emoji: string, custom?: string): void => {
if (ownAccount) {
dispatch(simpleEmojiReact(status, emoji));
dispatch(simpleEmojiReact(status, emoji, custom));
} else {
handleUnauthorized();
}
@ -71,7 +71,7 @@ const StatusReactionWrapper: React.FC<IStatusReactionWrapper> = ({ statusId, chi
};
const handleClick: React.EventHandler<React.MouseEvent> = e => {
const meEmojiReact = getReactForStatus(status, soapboxConfig.allowedEmoji) || '👍';
const meEmojiReact = getReactForStatus(status, soapboxConfig.allowedEmoji)?.get('name') || '👍';
if (isUserTouching()) {
if (ownAccount) {
@ -112,6 +112,7 @@ const StatusReactionWrapper: React.FC<IStatusReactionWrapper> = ({ statusId, chi
referenceElement={referenceElement}
onReact={handleReact}
visible={visible}
onClose={() => setVisible(false)}
/>
</Portal>
)}

Wyświetl plik

@ -6,12 +6,13 @@ import { openModal } from 'soapbox/actions/modals';
import HoverRefWrapper from 'soapbox/components/hover-ref-wrapper';
import HoverStatusWrapper from 'soapbox/components/hover-status-wrapper';
import { useAppDispatch } from 'soapbox/hooks';
import { isPubkey } from 'soapbox/utils/nostr';
import type { Account, Status } from 'soapbox/types/entities';
interface IStatusReplyMentions {
status: Status,
hoverable?: boolean,
status: Status
hoverable?: boolean
}
const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable = true }) => {
@ -56,7 +57,7 @@ const StatusReplyMentions: React.FC<IStatusReplyMentions> = ({ status, hoverable
className='reply-mentions__account'
onClick={(e) => e.stopPropagation()}
>
@{account.username}
@{isPubkey(account.username) ? account.username.slice(0, 8) : account.username}
</Link>
);

Wyświetl plik

@ -7,7 +7,7 @@ import { useHistory } from 'react-router-dom';
import { mentionCompose, replyCompose } from 'soapbox/actions/compose';
import { toggleFavourite, toggleReblog } from 'soapbox/actions/interactions';
import { openModal } from 'soapbox/actions/modals';
import { toggleStatusHidden } from 'soapbox/actions/statuses';
import { toggleStatusHidden, unfilterStatus } from 'soapbox/actions/statuses';
import Icon from 'soapbox/components/icon';
import TranslateButton from 'soapbox/components/translate-button';
import AccountContainer from 'soapbox/containers/account-container';
@ -38,22 +38,22 @@ const messages = defineMessages({
});
export interface IStatus {
id?: string,
avatarSize?: number,
status: StatusEntity,
onClick?: () => void,
muted?: boolean,
hidden?: boolean,
unread?: boolean,
onMoveUp?: (statusId: string, featured?: boolean) => void,
onMoveDown?: (statusId: string, featured?: boolean) => void,
focusable?: boolean,
featured?: boolean,
hideActionBar?: boolean,
hoverable?: boolean,
variant?: 'default' | 'rounded',
showGroup?: boolean,
accountAction?: React.ReactElement,
id?: string
avatarSize?: number
status: StatusEntity
onClick?: () => void
muted?: boolean
hidden?: boolean
unread?: boolean
onMoveUp?: (statusId: string, featured?: boolean) => void
onMoveDown?: (statusId: string, featured?: boolean) => void
focusable?: boolean
featured?: boolean
hideActionBar?: boolean
hoverable?: boolean
variant?: 'default' | 'rounded'
showGroup?: boolean
accountAction?: React.ReactElement
}
const Status: React.FC<IStatus> = (props) => {
@ -93,6 +93,8 @@ const Status: React.FC<IStatus> = (props) => {
const statusUrl = `/@${actualStatus.getIn(['account', 'acct'])}/posts/${actualStatus.id}`;
const group = actualStatus.group as GroupEntity | null;
const filtered = (status.filtered.size || actualStatus.filtered.size) > 0;
// Track height changes we know about to compensate scrolling.
useEffect(() => {
didShowCard.current = Boolean(!muted && !hidden && status?.card);
@ -202,6 +204,8 @@ const Status: React.FC<IStatus> = (props) => {
_expandEmojiSelector();
};
const handleUnfilter = () => dispatch(unfilterStatus(status.filtered.size ? status.id : actualStatus.id));
const _expandEmojiSelector = (): void => {
const firstEmoji: HTMLDivElement | null | undefined = node.current?.querySelector('.emoji-react-selector .emoji-react-selector__emoji');
firstEmoji?.focus();
@ -281,7 +285,7 @@ const Status: React.FC<IStatus> = (props) => {
);
}
if (status.filtered || actualStatus.filtered) {
if (filtered && status.showFiltered) {
const minHandlers = muted ? undefined : {
moveUp: handleHotkeyMoveUp,
moveDown: handleHotkeyMoveDown,
@ -291,7 +295,11 @@ const Status: React.FC<IStatus> = (props) => {
<HotKeys handlers={minHandlers}>
<div className={clsx('status__wrapper text-center', { focusable })} tabIndex={focusable ? 0 : undefined} ref={node}>
<Text theme='muted'>
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />: {status.filtered.join(', ')}.
{' '}
<button className='text-primary-600 hover:underline dark:text-accent-blue' onClick={handleUnfilter}>
<FormattedMessage id='status.show_filter_reason' defaultMessage='Show anyway' />
</button>
</Text>
</div>
</HotKeys>

Wyświetl plik

@ -5,17 +5,17 @@ import { useSettings } from 'soapbox/hooks';
interface IStillImage {
/** Image alt text. */
alt?: string,
alt?: string
/** Extra class names for the outer <div> container. */
className?: string,
className?: string
/** URL to the image */
src: string,
src: string
/** Extra CSS styles on the outer <div> element. */
style?: React.CSSProperties,
style?: React.CSSProperties
/** Whether to display the image contained vs filled in its container. */
letterboxed?: boolean,
letterboxed?: boolean
/** Whether to show the file extension in the corner. */
showExt?: boolean,
showExt?: boolean
}
/** Renders images on a canvas, only playing GIFs if autoPlayGif is enabled. */
@ -80,7 +80,7 @@ const StillImage: React.FC<IStillImage> = ({ alt, className, src, style, letterb
interface IExtensionBadge {
/** File extension. */
ext: string,
ext: string
}
/** Badge displaying a file extension. */

Wyświetl plik

@ -6,13 +6,13 @@ import IconWithCounter from 'soapbox/components/icon-with-counter';
import { Icon, Text } from 'soapbox/components/ui';
interface IThumbNavigationLink {
count?: number,
countMax?: number,
src: string,
text: string | React.ReactElement,
to: string,
exact?: boolean,
paths?: Array<string>,
count?: number
countMax?: number
src: string
text: string | React.ReactElement
to: string
exact?: boolean
paths?: Array<string>
}
const ThumbNavigationLink: React.FC<IThumbNavigationLink> = ({ count, countMax, src, text, to, exact, paths }): JSX.Element => {

Wyświetl plik

@ -5,9 +5,9 @@ import { FormattedMessage } from 'react-intl';
import { Text } from 'soapbox/components/ui';
interface ITombstone {
id: string,
onMoveUp: (statusId: string) => void,
onMoveDown: (statusId: string) => void,
id: string
onMoveUp: (statusId: string) => void
onMoveDown: (statusId: string) => void
}
/** Represents a deleted item. */

Wyświetl plik

@ -11,7 +11,7 @@ import { Stack, Button, Text } from './ui';
import type { Account, Status } from 'soapbox/types/entities';
interface ITranslateButton {
status: Status,
status: Status
}
const TranslateButton: React.FC<ITranslateButton> = ({ status }) => {

Some files were not shown because too many files have changed in this diff Show More