139 lines
3.7 KiB
TypeScript
139 lines
3.7 KiB
TypeScript
import { FormattedMessage } from 'react-intl';
|
|
|
|
import classNames from 'classnames';
|
|
|
|
import { ListItemLink, ListItemWrapper } from '@/mastodon/components/list_item';
|
|
import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
|
|
import type { ApiCollectionJSON } from 'mastodon/api_types/collections';
|
|
import { AvatarById } from 'mastodon/components/avatar';
|
|
import { useAccountHandle } from 'mastodon/components/display_name/default';
|
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
|
import { useAccount } from 'mastodon/hooks/useAccount';
|
|
import { domain } from 'mastodon/initial_state';
|
|
|
|
import { getCollectionPath } from '../utils';
|
|
|
|
import classes from './collection_lockup.module.scss';
|
|
|
|
export const AvatarGrid: React.FC<{
|
|
accountIds: (string | undefined)[];
|
|
sensitive?: boolean;
|
|
}> = ({ accountIds: ids, sensitive }) => {
|
|
const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
|
|
return (
|
|
<div
|
|
className={classNames(
|
|
classes.avatarGrid,
|
|
sensitive ? classes.avatarGridSensitive : null,
|
|
)}
|
|
>
|
|
{avatarIds.map((id, index) => (
|
|
<AvatarById
|
|
animate={false}
|
|
key={index}
|
|
accountId={id}
|
|
className={classes.avatar}
|
|
size={25}
|
|
/>
|
|
))}
|
|
{sensitive && <WarningIcon className={classes.avatarSensitiveBadge} />}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export interface CollectionLockupProps {
|
|
collection: ApiCollectionJSON;
|
|
withAuthorHandle?: boolean;
|
|
withTimestamp?: boolean;
|
|
sideContent?: React.ReactNode;
|
|
className?: string;
|
|
headingLevel?: 'h2' | 'h3' | 'h4';
|
|
}
|
|
|
|
export const CollectionLockup: React.FC<CollectionLockupProps> = ({
|
|
collection,
|
|
withAuthorHandle = true,
|
|
withTimestamp,
|
|
sideContent,
|
|
headingLevel = 'h3',
|
|
className,
|
|
}) => {
|
|
const { id, name } = collection;
|
|
|
|
return (
|
|
<ListItemWrapper
|
|
className={classNames(classes.wrapper, className)}
|
|
icon={
|
|
<AvatarGrid
|
|
accountIds={collection.items.map((item) => item.account_id)}
|
|
sensitive={collection.sensitive}
|
|
/>
|
|
}
|
|
sideContent={sideContent}
|
|
>
|
|
<ListItemLink
|
|
as={headingLevel}
|
|
to={getCollectionPath(id)}
|
|
subtitle={
|
|
<CollectionInfo
|
|
collection={collection}
|
|
withAuthorHandle={withAuthorHandle}
|
|
withTimestamp={withTimestamp}
|
|
/>
|
|
}
|
|
>
|
|
{name}
|
|
</ListItemLink>
|
|
</ListItemWrapper>
|
|
);
|
|
};
|
|
|
|
export const CollectionInfo: React.FC<
|
|
Pick<
|
|
CollectionLockupProps,
|
|
'collection' | 'withAuthorHandle' | 'withTimestamp'
|
|
>
|
|
> = ({ collection, withAuthorHandle, withTimestamp }) => {
|
|
const authorAccount = useAccount(collection.account_id);
|
|
const authorHandle = useAccountHandle(authorAccount, domain);
|
|
|
|
return (
|
|
<ul>
|
|
{collection.sensitive && (
|
|
<li className='sr-only'>
|
|
<FormattedMessage
|
|
id='collections.sensitive'
|
|
defaultMessage='Sensitive'
|
|
/>
|
|
</li>
|
|
)}
|
|
{withAuthorHandle && authorAccount && (
|
|
<FormattedMessage
|
|
id='collections.by_account'
|
|
defaultMessage='by {account_handle}'
|
|
values={{
|
|
account_handle: authorHandle,
|
|
}}
|
|
tagName='li'
|
|
/>
|
|
)}
|
|
<FormattedMessage
|
|
id='collections.account_count'
|
|
defaultMessage='{count, plural, one {# account} other {# accounts}}'
|
|
values={{ count: collection.item_count }}
|
|
tagName='li'
|
|
/>
|
|
{withTimestamp && (
|
|
<FormattedMessage
|
|
id='collections.last_updated_at'
|
|
defaultMessage='Last updated: {date}'
|
|
values={{
|
|
date: <RelativeTimestamp timestamp={collection.updated_at} long />,
|
|
}}
|
|
tagName='li'
|
|
/>
|
|
)}
|
|
</ul>
|
|
);
|
|
};
|