diff --git a/app/soapbox/api/hooks/groups/useUpdateGroup.ts b/app/soapbox/api/hooks/groups/useUpdateGroup.ts index bb3a37dc2b..b4ec0aa541 100644 --- a/app/soapbox/api/hooks/groups/useUpdateGroup.ts +++ b/app/soapbox/api/hooks/groups/useUpdateGroup.ts @@ -6,8 +6,8 @@ import { groupSchema } from 'soapbox/schemas'; interface UpdateGroupParams { display_name?: string note?: string - avatar?: File - header?: File + avatar?: File | '' + header?: File | '' group_visibility?: string discoverable?: boolean tags?: string[] @@ -30,4 +30,4 @@ function useUpdateGroup(groupId: string) { }; } -export { useUpdateGroup }; \ No newline at end of file +export { useUpdateGroup }; diff --git a/app/soapbox/components/sidebar-menu.tsx b/app/soapbox/components/sidebar-menu.tsx index f77e9f5ed6..11786f4adb 100644 --- a/app/soapbox/components/sidebar-menu.tsx +++ b/app/soapbox/components/sidebar-menu.tsx @@ -28,6 +28,7 @@ const messages = defineMessages({ domainBlocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' }, mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' }, + followedTags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' }, soapboxConfig: { id: 'navigation_bar.soapbox_config', defaultMessage: 'Soapbox config' }, accountMigration: { id: 'navigation_bar.account_migration', defaultMessage: 'Move account' }, accountAliases: { id: 'navigation_bar.account_aliases', defaultMessage: 'Account aliases' }, @@ -305,6 +306,15 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { /> )} + {features.followedHashtagsList && ( + + )} + {account.admin && ( = ({ )); }; - const renderFeedSuggestions = (): React.ReactNode => { - return ; + const renderFeedSuggestions = (statusId: string): React.ReactNode => { + return ( + + ); }; const renderStatuses = (): React.ReactNode[] => { @@ -201,7 +208,7 @@ const StatusList: React.FC = ({ } } else if (statusId.startsWith('末suggestions-')) { if (soapboxConfig.feedInjection) { - acc.push(renderFeedSuggestions()); + acc.push(renderFeedSuggestions(statusId)); } } else if (statusId.startsWith('末pending-')) { acc.push(renderPendingStatus(statusId)); diff --git a/app/soapbox/components/still-image.tsx b/app/soapbox/components/still-image.tsx index cdebaf359e..4a3caf01eb 100644 --- a/app/soapbox/components/still-image.tsx +++ b/app/soapbox/components/still-image.tsx @@ -67,7 +67,7 @@ const StillImage: React.FC = ({ alt, className, src, style, letterb )} diff --git a/app/soapbox/components/ui/card/card.tsx b/app/soapbox/components/ui/card/card.tsx index 4b8d9799d5..a57fc9a1aa 100644 --- a/app/soapbox/components/ui/card/card.tsx +++ b/app/soapbox/components/ui/card/card.tsx @@ -27,6 +27,7 @@ interface ICard { className?: string /** Elements inside the card. */ children: React.ReactNode + tabIndex?: number } /** An opaque backdrop to hold a collection of related elements. */ diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index aa935624d2..ec63d966da 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -11,7 +11,6 @@ import { CompatRouter } from 'react-router-dom-v5-compat'; // @ts-ignore: it doesn't have types import { ScrollContext } from 'react-router-scroll-4'; - import { loadInstance } from 'soapbox/actions/instance'; import { fetchMe } from 'soapbox/actions/me'; import { loadSoapboxConfig, getSoapboxConfig } from 'soapbox/actions/soapbox'; diff --git a/app/soapbox/features/chats/components/chat-message-list.tsx b/app/soapbox/features/chats/components/chat-message-list.tsx index b06c34664f..69ad7690bc 100644 --- a/app/soapbox/features/chats/components/chat-message-list.tsx +++ b/app/soapbox/features/chats/components/chat-message-list.tsx @@ -109,9 +109,13 @@ const ChatMessageList: React.FC = ({ chat }) => { return []; } + const currentYear = new Date().getFullYear(); + return chatMessages.reduce((acc: any, curr: any, idx: number) => { const lastMessage = formattedChatMessages[idx - 1]; + const messageDate = new Date(curr.created_at); + if (lastMessage) { switch (timeChange(lastMessage, curr)) { case 'today': @@ -123,7 +127,14 @@ const ChatMessageList: React.FC = ({ chat }) => { case 'date': acc.push({ type: 'divider', - text: intl.formatDate(new Date(curr.created_at), { weekday: 'short', hour: 'numeric', minute: '2-digit', month: 'short', day: 'numeric' }), + text: intl.formatDate(messageDate, { + weekday: 'short', + hour: 'numeric', + minute: '2-digit', + month: 'short', + day: 'numeric', + year: messageDate.getFullYear() !== currentYear ? '2-digit' : undefined, + }), }); break; } diff --git a/app/soapbox/features/group/components/group-avatar-picker.tsx b/app/soapbox/features/edit-profile/components/avatar-picker.tsx similarity index 61% rename from app/soapbox/features/group/components/group-avatar-picker.tsx rename to app/soapbox/features/edit-profile/components/avatar-picker.tsx index b13dfe80e5..09a6b0d29f 100644 --- a/app/soapbox/features/group/components/group-avatar-picker.tsx +++ b/app/soapbox/features/edit-profile/components/avatar-picker.tsx @@ -1,19 +1,25 @@ import clsx from 'clsx'; import React from 'react'; +import { FormattedMessage } from 'react-intl'; -import Icon from 'soapbox/components/icon'; -import { Avatar, HStack } from 'soapbox/components/ui'; +import { Avatar, Icon, HStack } from 'soapbox/components/ui'; interface IMediaInput { + className?: string src: string | undefined accept: string onChange: React.ChangeEventHandler disabled?: boolean } -const AvatarPicker = React.forwardRef(({ src, onChange, accept, disabled }, ref) => { +const AvatarPicker = React.forwardRef(({ className, src, onChange, accept, disabled }, ref) => { return ( -