[Glitch] Add "Follows you" badge to AccountListItem component
Port ffd7160980a98111323c8608a3e557b7fba00c59 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
11f3393825
commit
20e9618e6d
@ -1,6 +1,8 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
|
||||
import { accountFactoryState } from '@/testing/factories';
|
||||
import { accountFactoryState, relationshipsFactory } from '@/testing/factories';
|
||||
|
||||
import { PendingBadge } from '../badge';
|
||||
|
||||
import { AccountListItem } from './index';
|
||||
|
||||
@ -26,12 +28,30 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const FollowsYou: Story = {
|
||||
parameters: {
|
||||
state: {
|
||||
relationships: {
|
||||
'1': relationshipsFactory({
|
||||
followed_by: true,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithCustomStats: Story = {
|
||||
args: {
|
||||
stats: ['posts', 'last-active'],
|
||||
},
|
||||
};
|
||||
|
||||
export const WithCustomBadge: Story = {
|
||||
args: {
|
||||
badge: <PendingBadge />,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithBorder: Story = {
|
||||
args: {
|
||||
withBorder: true,
|
||||
|
||||
@ -1,18 +1,26 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Account } from 'flavours/glitch/components/account';
|
||||
import { VerifiedBadge } from 'flavours/glitch/components/badge';
|
||||
import {
|
||||
FollowsYouBadge,
|
||||
VerifiedBadge,
|
||||
} from 'flavours/glitch/components/badge';
|
||||
import { useAccount } from 'flavours/glitch/hooks/useAccount';
|
||||
import { useRelationship } from 'flavours/glitch/hooks/useRelationship';
|
||||
import { domain } from 'flavours/glitch/initial_state';
|
||||
import type { Relationship } from 'flavours/glitch/models/relationship';
|
||||
|
||||
import { Avatar } from '../avatar';
|
||||
import { useAccountHandle } from '../display_name/default';
|
||||
import { DisplayNameSimple } from '../display_name/simple';
|
||||
import { EmojiHTML } from '../emoji/html';
|
||||
import { FollowButton } from '../follow_button';
|
||||
import { FormattedDateWrapper } from '../formatted_date';
|
||||
import { ListItemLink, ListItemWrapper } from '../list_item';
|
||||
import { NumberFields, NumberFieldsItem } from '../number_fields';
|
||||
import { RelativeTimestamp } from '../relative_timestamp';
|
||||
import { ShortNumber } from '../short_number';
|
||||
@ -29,9 +37,10 @@ type Stat = 'followers' | 'following' | 'posts' | 'joined' | 'last-active';
|
||||
interface Props {
|
||||
accountId: string | undefined;
|
||||
stats?: Stat[];
|
||||
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
|
||||
withBio?: boolean;
|
||||
withBorder?: boolean;
|
||||
badge?: ReactNode;
|
||||
renderButton?: (options: RenderButtonOptions) => React.ReactNode;
|
||||
}
|
||||
|
||||
const DEFAULT_STATS: Stat[] = ['followers', 'posts', 'last-active'];
|
||||
@ -48,10 +57,12 @@ export const AccountListItem: React.FC<Props> = ({
|
||||
stats = DEFAULT_STATS,
|
||||
withBio = true,
|
||||
withBorder = true,
|
||||
badge: badgeProp,
|
||||
renderButton = defaultRenderButton,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const account = useAccount(accountId);
|
||||
const handle = useAccountHandle(account, domain);
|
||||
const relationship = useRelationship(accountId);
|
||||
|
||||
const createdThisYear = useMemo(
|
||||
@ -63,22 +74,34 @@ export const AccountListItem: React.FC<Props> = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const badge =
|
||||
badgeProp ?? (relationship?.followed_by ? <FollowsYouBadge /> : null);
|
||||
|
||||
const firstVerifiedField = account.fields.find((item) => !!item.verified_at);
|
||||
|
||||
return (
|
||||
<div className={classes.wrapper} data-with-border={withBorder}>
|
||||
<div className={classes.header}>
|
||||
<Account
|
||||
id={accountId}
|
||||
minimal
|
||||
size={40}
|
||||
withMenu={false}
|
||||
withBorder={false}
|
||||
className={classes.account}
|
||||
/>
|
||||
|
||||
{renderButton({ accountId, relationship })}
|
||||
</div>
|
||||
<ListItemWrapper
|
||||
className={classes.main}
|
||||
icon={<Avatar account={account} size={40} />}
|
||||
sideContent={
|
||||
<span className={classes.button}>
|
||||
{renderButton({ accountId, relationship })}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<ListItemLink
|
||||
to={`/@${account.acct}`}
|
||||
data-hover-card-account={accountId}
|
||||
subtitle={handle}
|
||||
>
|
||||
<DisplayNameSimple
|
||||
account={account}
|
||||
className={classes.displayName}
|
||||
/>
|
||||
{badge && <span className={classes.badge}>{badge}</span>}
|
||||
</ListItemLink>
|
||||
</ListItemWrapper>
|
||||
|
||||
<NumberFields>
|
||||
{stats.includes('followers') && (
|
||||
|
||||
@ -10,22 +10,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
width: 100%;
|
||||
.main {
|
||||
--list-item-padding: 0;
|
||||
}
|
||||
|
||||
.account {
|
||||
--account-name-size: 15px;
|
||||
--account-handle-color: var(--color-text-secondary);
|
||||
--account-handle-size: 13px;
|
||||
--account-bio-color: var(--color-text-primary);
|
||||
--account-bio-size: 13px;
|
||||
--account-outer-spacing: 0;
|
||||
.displayName {
|
||||
// Spacing for badge
|
||||
margin-inline-end: 6px;
|
||||
}
|
||||
|
||||
flex-grow: 1;
|
||||
margin-inline-end: 16px;
|
||||
.badge {
|
||||
// Sort out vertical alignment next to name
|
||||
vertical-align: -4px;
|
||||
}
|
||||
|
||||
.button {
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.verifiedBadge {
|
||||
|
||||
@ -6,6 +6,8 @@ import classNames from 'classnames';
|
||||
|
||||
import type { OnAttributeHandler } from '@/flavours/glitch/utils/html';
|
||||
import AdminIcon from '@/images/icons/icon_admin.svg?react';
|
||||
import ClockIcon from '@/images/icons/icon_clock.svg?react';
|
||||
import FollowerIcon from '@/images/icons/icon_follower.svg?react';
|
||||
import IconVerified from '@/images/icons/icon_verified.svg?react';
|
||||
import BlockIcon from '@/material-icons/400-24px/block.svg?react';
|
||||
import GroupsIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
@ -32,6 +34,11 @@ interface BadgeProps extends React.ComponentPropsWithoutRef<'div'> {
|
||||
| 'danger';
|
||||
}
|
||||
|
||||
type PresetBadgeProps = Omit<
|
||||
BadgeProps,
|
||||
'label' | 'icon' | 'domain' | 'roleId'
|
||||
>;
|
||||
|
||||
export const Badge: FC<BadgeProps> = ({
|
||||
icon = <PersonIcon />,
|
||||
variant = 'default',
|
||||
@ -83,13 +90,32 @@ export const GroupBadge: FC<Partial<BadgeProps>> = ({ label, ...props }) => (
|
||||
/>
|
||||
);
|
||||
|
||||
export const AutomatedBadge: FC<{ className?: string }> = ({ className }) => (
|
||||
export const AutomatedBadge: FC<PresetBadgeProps> = (props) => (
|
||||
<Badge
|
||||
icon={<SmartToyIcon />}
|
||||
label={
|
||||
<FormattedMessage id='account.badges.bot' defaultMessage='Automated' />
|
||||
}
|
||||
className={className}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const FollowsYouBadge: FC<PresetBadgeProps> = (props) => (
|
||||
<Badge
|
||||
icon={<FollowerIcon />}
|
||||
label={
|
||||
<FormattedMessage id='account.follows_you' defaultMessage='Follows you' />
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const PendingBadge: FC<PresetBadgeProps> = (props) => (
|
||||
<Badge
|
||||
variant='warning'
|
||||
icon={<ClockIcon />}
|
||||
label={<FormattedMessage id='account.pending' defaultMessage='Pending' />}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
.badge {
|
||||
color: var(--color-text-primary);
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
display: inline-flex;
|
||||
max-width: 100%;
|
||||
padding: 4px;
|
||||
@ -61,7 +62,6 @@
|
||||
|
||||
.warning {
|
||||
background-color: var(--color-bg-warning-softest);
|
||||
color: var(--color-text-warning);
|
||||
}
|
||||
|
||||
.danger {
|
||||
|
||||
@ -8,14 +8,13 @@ import classNames from 'classnames';
|
||||
import Overlay from 'react-overlays/esm/Overlay';
|
||||
|
||||
import { showAlert } from '@/flavours/glitch/actions/alerts';
|
||||
import { Badge } from '@/flavours/glitch/components/badge';
|
||||
import { FollowsYouBadge } from '@/flavours/glitch/components/badge';
|
||||
import { Button } from '@/flavours/glitch/components/button';
|
||||
import { DisplayName } from '@/flavours/glitch/components/display_name';
|
||||
import { Icon } from '@/flavours/glitch/components/icon';
|
||||
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||
import { useRelationship } from '@/flavours/glitch/hooks/useRelationship';
|
||||
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
|
||||
import FollowerIcon from '@/images/icons/icon_follower.svg?react';
|
||||
import AtIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
|
||||
import HelpIcon from '@/material-icons/400-24px/help.svg?react';
|
||||
@ -60,17 +59,7 @@ export const AccountName: FC<{ accountId: string }> = ({ accountId }) => {
|
||||
<h1>
|
||||
<DisplayName account={account} variant='simple' />
|
||||
</h1>
|
||||
{relationship?.followed_by && (
|
||||
<Badge
|
||||
icon={<FollowerIcon className={classes.followerBadgeIcon} />}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='account.follows_you'
|
||||
defaultMessage='Follows you'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{relationship?.followed_by && <FollowsYouBadge />}
|
||||
</div>
|
||||
|
||||
<AccountNameHelp
|
||||
|
||||
@ -37,10 +37,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.followerBadgeIcon {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.badges {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user