@ -1,4 +1,5 @@
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import clsx from 'clsx';
|
||||
import React, { useMemo } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
@ -6,10 +7,7 @@ import DropdownMenu from 'pl-fe/components/dropdown-menu';
|
||||
import { ParsedContent } from 'pl-fe/components/parsed-content';
|
||||
import RelativeTimestamp from 'pl-fe/components/relative-timestamp';
|
||||
import Avatar from 'pl-fe/components/ui/avatar';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import IconButton from 'pl-fe/components/ui/icon-button';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import VerificationBadge from 'pl-fe/components/verification-badge';
|
||||
import { useChatContext } from 'pl-fe/contexts/chat-context';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
@ -85,58 +83,46 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
||||
data-testid='chat-list-item'
|
||||
tabIndex={0}
|
||||
>
|
||||
<HStack alignItems='center' justifyContent='between' space={2} className='w-full'>
|
||||
<HStack alignItems='center' space={2} className='overflow-hidden'>
|
||||
<div>
|
||||
<div className='⁂-chat-list-item__info'>
|
||||
<Avatar
|
||||
src={chat.account.avatar}
|
||||
alt={chat.account.avatar_description}
|
||||
size={40}
|
||||
className='flex-none'
|
||||
className='⁂-chat-list-item__avatar'
|
||||
isCat={chat.account.is_cat}
|
||||
username={chat.account.username}
|
||||
/>
|
||||
|
||||
<Stack alignItems='start' className='overflow-hidden'>
|
||||
<div className='flex w-full grow items-center space-x-1'>
|
||||
<Text weight='bold' size='sm' align='left' truncate>{chat.account?.display_name || `@${chat.account.username}`}</Text>
|
||||
<div className='⁂-chat-list-item__content'>
|
||||
<div className='⁂-chat-list-item__name'>
|
||||
<p>{chat.account?.display_name || `@${chat.account.username}`}</p>
|
||||
{chat.account?.verified && <VerificationBadge />}
|
||||
</div>
|
||||
|
||||
{(isBlocked || isBlocking) ? (
|
||||
<Text
|
||||
align='left'
|
||||
size='sm'
|
||||
weight='medium'
|
||||
theme='muted'
|
||||
truncate
|
||||
className='pointer-events-none h-5 w-full italic'
|
||||
data-testid='chat-last-message'
|
||||
>
|
||||
{isBlocked
|
||||
? <FormattedMessage id='chat_list_item.blocked_you' defaultMessage='This user has blocked you' />
|
||||
: <FormattedMessage id='chat_list_item.blocking' defaultMessage='You have blocked this user' />}
|
||||
</Text>
|
||||
) : (
|
||||
<>
|
||||
{chat.last_message?.content && (
|
||||
<Text
|
||||
align='left'
|
||||
size='sm'
|
||||
weight='medium'
|
||||
theme={chat.last_message.unread ? 'default' : 'muted'}
|
||||
truncate
|
||||
className='truncate-child pointer-events-none h-5 w-full'
|
||||
data-testid='chat-last-message'
|
||||
>
|
||||
<ParsedContent html={chat.last_message?.content} emojis={chat.last_message.emojis} />
|
||||
</Text>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</HStack>
|
||||
<p
|
||||
className={clsx('⁂-chat-list-item__message', {
|
||||
'⁂-chat-list-item__message--unread': !(isBlocked || isBlocking) && chat.last_message?.unread,
|
||||
'⁂-chat-list-item__message--blocking': isBlocked || isBlocking,
|
||||
})}
|
||||
>
|
||||
{isBlocked ? (
|
||||
<FormattedMessage id='chat_list_item.blocked_you' defaultMessage='This user has blocked you' />
|
||||
) : isBlocking ? (
|
||||
<FormattedMessage id='chat_list_item.blocking' defaultMessage='You have blocked this user' />
|
||||
) : (
|
||||
chat.last_message?.content && (
|
||||
<ParsedContent
|
||||
html={chat.last_message?.content}
|
||||
emojis={chat.last_message.emojis}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<HStack alignItems='center' space={2}>
|
||||
<div className='⁂-chat-list-item__actions'>
|
||||
{features.chatsDelete && (
|
||||
<div className='⁂-chat-list-item__menu'>
|
||||
<DropdownMenu items={menu}>
|
||||
@ -152,7 +138,7 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
||||
<>
|
||||
{chat.last_message.unread && (
|
||||
<div
|
||||
className='size-2 rounded-full bg-secondary-500'
|
||||
className='⁂-chat-list-item__unread'
|
||||
data-testid='chat-unread-indicator'
|
||||
/>
|
||||
)}
|
||||
@ -166,8 +152,8 @@ const ChatListItem: React.FC<IChatListItemInterface> = ({ chat, onClick }) => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</HStack>
|
||||
</HStack>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -4,9 +4,6 @@ import { FormattedMessage } from 'react-intl';
|
||||
import { useAccount } from 'pl-fe/api/hooks/accounts/use-account';
|
||||
import { ParsedContent } from 'pl-fe/components/parsed-content';
|
||||
import Avatar from 'pl-fe/components/ui/avatar';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config';
|
||||
import { useShoutboxMessages } from 'pl-fe/stores/shoutbox';
|
||||
@ -37,43 +34,34 @@ const ChatListShoutbox: React.FC<IChatListShoutboxInterface> = ({ onClick }) =>
|
||||
key='shoutbox'
|
||||
onClick={() => onClick('shoutbox')}
|
||||
onKeyDown={handleKeyDown}
|
||||
className='⁂-chat-list-item'
|
||||
className='⁂-chat-list-item ⁂-chat-list-item--shoutbox'
|
||||
data-testid='chat-list-item'
|
||||
tabIndex={0}
|
||||
>
|
||||
<HStack alignItems='center' justifyContent='between' space={2} className='w-full'>
|
||||
<HStack alignItems='center' space={2} className='overflow-hidden'>
|
||||
<Avatar src={logo} alt='' size={40} className='flex-none' />
|
||||
<Stack alignItems='start' className='overflow-hidden'>
|
||||
<div className='flex w-full grow items-center space-x-1'>
|
||||
<Text weight='bold' size='sm' align='left' truncate>
|
||||
<FormattedMessage id='chat_list_item_shoutbox' defaultMessage='{instance} shoutbox' values={{ instance: instance.title }} />
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Avatar src={logo} alt='' size={40} className='flex-none' />
|
||||
<div className='⁂-chat-list-item__content'>
|
||||
<div className='⁂-chat-list-item__name'>
|
||||
<p>
|
||||
<FormattedMessage id='chat_list_item_shoutbox' defaultMessage='{instance} shoutbox' values={{ instance: instance.title }} />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{lastMessage && (
|
||||
<>
|
||||
<Text
|
||||
align='left'
|
||||
size='sm'
|
||||
weight='medium'
|
||||
theme='muted'
|
||||
truncate
|
||||
className='truncate-child pointer-events-none h-5 w-full'
|
||||
>
|
||||
{lastMessageAuthor && (
|
||||
<Text weight='bold' size='sm' align='left' theme='muted' truncate tag='span'>
|
||||
{lastMessageAuthor.display_name || `@${lastMessageAuthor.username}`}:
|
||||
{' '}
|
||||
</Text>
|
||||
)}
|
||||
<ParsedContent html={lastMessage.text} />
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</HStack>
|
||||
</HStack>
|
||||
{lastMessage && (
|
||||
<>
|
||||
<p className='⁂-chat-list-item__message'>
|
||||
{lastMessageAuthor && (
|
||||
<span className='⁂-chat-list-item__message__author'>
|
||||
{lastMessageAuthor.display_name || `@${lastMessageAuthor.username}`}:
|
||||
{' '}
|
||||
</span>
|
||||
)}
|
||||
<ParsedContent html={lastMessage.text} />
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -131,6 +131,55 @@
|
||||
.⁂-chat-list-item {
|
||||
@apply flex w-full flex-col rounded-lg px-2 py-3 hover:bg-gray-100 focus:shadow-inset-ring dark:hover:bg-gray-800;
|
||||
|
||||
> div {
|
||||
@apply flex items-center justify-between gap-2 w-full;
|
||||
}
|
||||
|
||||
&--shoutbox > div {
|
||||
@apply justify-normal;
|
||||
}
|
||||
|
||||
&__info {
|
||||
@apply flex items-center gap-2 overflow-hidden;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
@apply flex-none;
|
||||
}
|
||||
|
||||
&__content {
|
||||
@apply flex flex-col items-start overflow-hidden;
|
||||
}
|
||||
|
||||
&__name {
|
||||
@apply flex w-full grow items-center space-x-1;
|
||||
|
||||
p {
|
||||
@include mixins.text($weight: bold, $size: sm, $align: left, $truncate: true);
|
||||
}
|
||||
}
|
||||
|
||||
&__message {
|
||||
@include mixins.text($theme: muted, $size: sm, $align: left, $truncate: true);
|
||||
@apply truncate-child pointer-events-none h-5 w-full;
|
||||
|
||||
&--unread {
|
||||
@apply text-gray-900 dark:text-gray-100;
|
||||
}
|
||||
|
||||
&:not(&--blocking) > * {
|
||||
@apply truncate;
|
||||
}
|
||||
|
||||
&__author {
|
||||
@include mixins.text($weight: bold, $size: sm, $align: left, $theme: muted, $truncate: true);
|
||||
}
|
||||
}
|
||||
|
||||
&__actions {
|
||||
@apply flex items-center gap-2;
|
||||
}
|
||||
|
||||
&__menu {
|
||||
@apply max-w-0 overflow-hidden text-gray-600 hover:text-gray-100;
|
||||
|
||||
@ -146,4 +195,16 @@
|
||||
&:hover .⁂-chat-list-item__menu {
|
||||
@apply max-w-full;
|
||||
}
|
||||
|
||||
&__unread {
|
||||
@apply size-2 rounded-full bg-secondary-500;
|
||||
}
|
||||
|
||||
&__timestamp {
|
||||
@include mixins.text($theme: muted, $size: xs, $align: right, $truncate: true);
|
||||
}
|
||||
|
||||
&__unread + &__timestamp {
|
||||
@apply text-gray-900 dark:text-gray-100;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user