Merge branch 'improve-status-info' into 'develop'

Improve StatusInfo for reposting from groups

See merge request soapbox-pub/soapbox!2453
This commit is contained in:
Chewbacca 2023-04-19 14:48:13 +00:00
commit 1074b003b0
4 changed files with 111 additions and 52 deletions

View File

@ -2,7 +2,7 @@ import clsx from 'clsx';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { HotKeys } from 'react-hotkeys'; import { HotKeys } from 'react-hotkeys';
import { useIntl, FormattedMessage, defineMessages } from 'react-intl'; import { useIntl, FormattedMessage, defineMessages } from 'react-intl';
import { useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { mentionCompose, replyCompose } from 'soapbox/actions/compose'; import { mentionCompose, replyCompose } from 'soapbox/actions/compose';
import { toggleFavourite, toggleReblog } from 'soapbox/actions/interactions'; import { toggleFavourite, toggleReblog } from 'soapbox/actions/interactions';
@ -211,11 +211,50 @@ const Status: React.FC<IStatus> = (props) => {
}; };
const renderStatusInfo = () => { const renderStatusInfo = () => {
if (isReblog) { if (isReblog && showGroup && group) {
return (
<StatusInfo
avatarSize={avatarSize}
icon={<Icon src={require('@tabler/icons/repeat.svg')} className='h-4 w-4 text-green-600' />}
text={
<FormattedMessage
id='status.reblogged_by_with_group'
defaultMessage='{name} reposted from {group}'
values={{
name: (
<Link
to={`/@${status.getIn(['account', 'acct'])}`}
className='hover:underline'
>
<bdi className='truncate'>
<strong
className='text-gray-800 dark:text-gray-200'
dangerouslySetInnerHTML={{
__html: String(status.getIn(['account', 'display_name_html'])),
}}
/>
</bdi>
</Link>
),
group: (
<Link to={`/group/${(status.group as GroupEntity).slug}`} className='hover:underline'>
<strong
className='text-gray-800 dark:text-gray-200'
dangerouslySetInnerHTML={{
__html: (status.group as GroupEntity).display_name_html,
}}
/>
</Link>
),
}}
/>
}
/>
);
} else if (isReblog) {
return ( return (
<StatusInfo <StatusInfo
avatarSize={avatarSize} avatarSize={avatarSize}
to={`/@${status.getIn(['account', 'acct'])}`}
icon={<Icon src={require('@tabler/icons/repeat.svg')} className='h-4 w-4 text-green-600' />} icon={<Icon src={require('@tabler/icons/repeat.svg')} className='h-4 w-4 text-green-600' />}
text={ text={
<FormattedMessage <FormattedMessage
@ -223,14 +262,16 @@ const Status: React.FC<IStatus> = (props) => {
defaultMessage='{name} reposted' defaultMessage='{name} reposted'
values={{ values={{
name: ( name: (
<bdi className='truncate pr-1 rtl:pl-1'> <Link to={`/@${status.getIn(['account', 'acct'])}`} className='hover:underline'>
<strong <bdi className='truncate'>
className='text-gray-800 dark:text-gray-200' <strong
dangerouslySetInnerHTML={{ className='text-gray-800 dark:text-gray-200'
__html: String(status.getIn(['account', 'display_name_html'])), dangerouslySetInnerHTML={{
}} __html: String(status.getIn(['account', 'display_name_html'])),
/> }}
</bdi> />
</bdi>
</Link>
), ),
}} }}
/> />
@ -243,9 +284,7 @@ const Status: React.FC<IStatus> = (props) => {
avatarSize={avatarSize} avatarSize={avatarSize}
icon={<Icon src={require('@tabler/icons/pinned.svg')} className='h-4 w-4 text-gray-600 dark:text-gray-400' />} icon={<Icon src={require('@tabler/icons/pinned.svg')} className='h-4 w-4 text-gray-600 dark:text-gray-400' />}
text={ text={
<Text size='xs' theme='muted' weight='medium'> <FormattedMessage id='status.pinned' defaultMessage='Pinned post' />
<FormattedMessage id='status.pinned' defaultMessage='Pinned post' />
</Text>
} }
/> />
); );
@ -253,18 +292,23 @@ const Status: React.FC<IStatus> = (props) => {
return ( return (
<StatusInfo <StatusInfo
avatarSize={avatarSize} avatarSize={avatarSize}
to={`/group/${group.slug}`}
icon={<Icon src={require('@tabler/icons/circles.svg')} className='h-4 w-4 text-primary-600 dark:text-accent-blue' />} icon={<Icon src={require('@tabler/icons/circles.svg')} className='h-4 w-4 text-primary-600 dark:text-accent-blue' />}
text={ text={
<Text size='xs' theme='muted' weight='medium'> <FormattedMessage
<FormattedMessage id='status.group'
id='status.group' defaultMessage='Posted in {group}'
defaultMessage='Posted in {group}' values={{
values={{ group: ( group: (
<span dangerouslySetInnerHTML={{ __html: group.display_name_html }} /> <Link to={`/group/${group.slug}`} className='hover:underline'>
) }} <bdi className='truncate'>
/> <strong className='text-gray-800 dark:text-gray-200'>
</Text> <span dangerouslySetInnerHTML={{ __html: group.display_name_html }} />
</strong>
</bdi>
</Link>
),
}}
/>
} }
/> />
); );

View File

@ -1,37 +1,44 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom';
import { HStack, Text } from '../ui';
interface IStatusInfo { interface IStatusInfo {
avatarSize: number avatarSize: number
to?: string
icon: React.ReactNode icon: React.ReactNode
text: React.ReactNode text: React.ReactNode
} }
const StatusInfo = (props: IStatusInfo) => { const StatusInfo = (props: IStatusInfo) => {
const { avatarSize, to, icon, text } = props; const { avatarSize, icon, text } = props;
const onClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => { const onClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
event.stopPropagation(); event.stopPropagation();
}; };
const Container = to ? Link : 'div';
const containerProps: any = to ? { onClick, to } : {};
return ( return (
<Container // eslint-disable-next-line jsx-a11y/no-static-element-interactions
{...containerProps} <div
className='flex items-center space-x-3 text-xs font-medium text-gray-700 hover:underline rtl:space-x-reverse dark:text-gray-600' // eslint-disable-next-line jsx-a11y/aria-role
role='status-info'
onClick={onClick}
> >
<div <HStack
className='flex justify-end' space={3}
style={{ width: avatarSize }} alignItems='center'
className='cursor-default text-xs font-medium text-gray-700 rtl:space-x-reverse dark:text-gray-600'
> >
{icon} <div
</div> className='flex justify-end'
style={{ width: avatarSize }}
>
{icon}
</div>
{text} <Text size='xs' theme='muted' weight='medium'>
</Container> {text}
</Text>
</HStack>
</div>
); );
}; };

View File

@ -1,5 +1,6 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { FormattedDate, FormattedMessage, useIntl } from 'react-intl'; import { FormattedDate, FormattedMessage, useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import Account from 'soapbox/components/account'; import Account from 'soapbox/components/account';
import StatusContent from 'soapbox/components/status-content'; import StatusContent from 'soapbox/components/status-content';
@ -56,22 +57,28 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
<div className='mb-4'> <div className='mb-4'>
<StatusInfo <StatusInfo
avatarSize={42} avatarSize={42}
to={`/groups/${(status.group as Group).id}`}
icon={ icon={
<Icon <Icon
src={require('@tabler/icons/circles.svg')} src={require('@tabler/icons/circles.svg')}
className='h-4 w-4 text-primary-600 dark:text-accent-blue' className='h-4 w-4 text-primary-600 dark:text-accent-blue'
/>} />
}
text={ text={
<Text size='xs' theme='muted' weight='medium'> <FormattedMessage
<FormattedMessage id='status.group'
id='status.group' defaultMessage='Posted in {group}'
defaultMessage='Posted in {group}' values={{
values={{ group: ( group: (
<span dangerouslySetInnerHTML={{ __html: (status.group as Group).display_name_html }} /> <Link to={`/group/${(status.group as Group).slug}`} className='hover:underline'>
) }} <bdi className='truncate'>
/> <strong className='text-gray-800 dark:text-gray-200'>
</Text> <span dangerouslySetInnerHTML={{ __html: (status.group as Group).display_name_html }} />
</strong>
</bdi>
</Link>
),
}}
/>
} }
/> />
</div> </div>

View File

@ -1469,6 +1469,7 @@
"status.reblog": "Repost", "status.reblog": "Repost",
"status.reblog_private": "Repost to original audience", "status.reblog_private": "Repost to original audience",
"status.reblogged_by": "{name} reposted", "status.reblogged_by": "{name} reposted",
"status.reblogged_by_with_group": "{name} reposted from {group}",
"status.reblogs.empty": "No one has reposted this post yet. When someone does, they will show up here.", "status.reblogs.empty": "No one has reposted this post yet. When someone does, they will show up here.",
"status.redraft": "Delete & re-draft", "status.redraft": "Delete & re-draft",
"status.remove_account_from_group": "Remove account from group", "status.remove_account_from_group": "Remove account from group",