Merge commit 'cc3c7ba532f75617505bb41297651a5c14f71bdd' into glitch-soc/merge-upstream
Conflicts: - `app/helpers/theme_helper.rb`: Upstream simplified `theme_style_tags`. Our version is different because of the different theming system. Adapted upstream's changes. - `app/views/layouts/error.html.haml`: Theming system.
This commit is contained in:
commit
7839c8d9af
20 files changed
+456
-214
No files matched your search
@@ -0,0 +1,5 @@
|
||||
import { isClientFeatureEnabled } from '@/mastodon/utils/environment';
|
||||
|
||||
export function isRedesignEnabled() {
|
||||
return isClientFeatureEnabled('profile_redesign');
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useIntl, FormattedMessage } from 'react-intl';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
import { AccountBio } from '@/mastodon/components/account_bio';
|
||||
import { AccountFields } from '@/mastodon/components/account_fields';
|
||||
import { DisplayName } from '@/mastodon/components/display_name';
|
||||
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
|
||||
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { AccountNote } from 'mastodon/features/account/components/account_note';
|
||||
import { DomainPill } from 'mastodon/features/account/components/domain_pill';
|
||||
@@ -25,10 +23,11 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
import { AccountBadges } from './badges';
|
||||
import { AccountButtons } from './buttons';
|
||||
import { FamiliarFollowers } from './familiar_followers';
|
||||
import { AccountHeaderFields } from './fields';
|
||||
import { AccountInfo } from './info';
|
||||
import { AccountLinks } from './links';
|
||||
import { MemorialNote } from './memorial_note';
|
||||
import { MovedNote } from './moved_note';
|
||||
import { AccountNumberFields } from './number_fields';
|
||||
import { AccountTabs } from './tabs';
|
||||
|
||||
const titleFromAccount = (account: Account) => {
|
||||
@@ -192,32 +191,10 @@ export const AccountHeader: React.FC<{
|
||||
className='account__header__content'
|
||||
/>
|
||||
|
||||
<div className='account__header__fields'>
|
||||
<dl>
|
||||
<dt>
|
||||
<FormattedMessage
|
||||
id='account.joined_short'
|
||||
defaultMessage='Joined'
|
||||
/>
|
||||
</dt>
|
||||
<dd>
|
||||
<FormattedDateWrapper
|
||||
value={account.created_at}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<AccountFields
|
||||
fields={account.fields}
|
||||
emojis={account.emojis}
|
||||
/>
|
||||
</div>
|
||||
<AccountHeaderFields accountId={accountId} />
|
||||
</div>
|
||||
|
||||
<AccountLinks accountId={accountId} />
|
||||
<AccountNumberFields accountId={accountId} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { openModal } from '@/mastodon/actions/modal';
|
||||
import { AccountFields } from '@/mastodon/components/account_fields';
|
||||
import { EmojiHTML } from '@/mastodon/components/emoji/html';
|
||||
import { FormattedDateWrapper } from '@/mastodon/components/formatted_date';
|
||||
import { MiniCardList } from '@/mastodon/components/mini_card/list';
|
||||
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
import type { Account } from '@/mastodon/models/account';
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
|
||||
import { isRedesignEnabled } from '../common';
|
||||
|
||||
import classes from './redesign.module.scss';
|
||||
|
||||
export const AccountHeaderFields: FC<{ accountId: string }> = ({
|
||||
accountId,
|
||||
}) => {
|
||||
const account = useAccount(accountId);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isRedesignEnabled()) {
|
||||
return <RedesignAccountHeaderFields account={account} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account__header__fields'>
|
||||
<dl>
|
||||
<dt>
|
||||
<FormattedMessage id='account.joined_short' defaultMessage='Joined' />
|
||||
</dt>
|
||||
<dd>
|
||||
<FormattedDateWrapper
|
||||
value={account.created_at}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<AccountFields fields={account.fields} emojis={account.emojis} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const RedesignAccountHeaderFields: FC<{ account: Account }> = ({ account }) => {
|
||||
const htmlHandlers = useElementHandledLink();
|
||||
const cards = useMemo(
|
||||
() =>
|
||||
account.fields.toArray().map(({ value_emojified, name_emojified }) => ({
|
||||
label: (
|
||||
<EmojiHTML
|
||||
htmlString={name_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
className='translate'
|
||||
as='span'
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
),
|
||||
value: (
|
||||
<EmojiHTML
|
||||
as='span'
|
||||
htmlString={value_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
),
|
||||
})),
|
||||
[account.emojis, account.fields, htmlHandlers],
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleOverflowClick = useCallback(() => {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'ACCOUNT_FIELDS',
|
||||
modalProps: { accountId: account.id },
|
||||
}),
|
||||
);
|
||||
}, [account.id, dispatch]);
|
||||
|
||||
return (
|
||||
<MiniCardList
|
||||
cards={cards}
|
||||
className={classes.fieldList}
|
||||
onOverflowClick={handleOverflowClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { DisplayName } from '@/mastodon/components/display_name';
|
||||
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
|
||||
import { EmojiHTML } from '@/mastodon/components/emoji/html';
|
||||
import { IconButton } from '@/mastodon/components/icon_button';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
|
||||
import classes from './redesign.module.scss';
|
||||
|
||||
export const AccountFieldsModal: FC<{
|
||||
accountId: string;
|
||||
onClose: () => void;
|
||||
}> = ({ accountId, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAccount(accountId);
|
||||
const htmlHandlers = useElementHandledLink();
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
<div className='modal-root__modal dialog-modal'>
|
||||
<LoadingIndicator />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal dialog-modal'>
|
||||
<div className='dialog-modal__header'>
|
||||
<IconButton
|
||||
icon='close'
|
||||
className={classes.modalCloseButton}
|
||||
onClick={onClose}
|
||||
iconComponent={CloseIcon}
|
||||
title={intl.formatMessage({
|
||||
id: 'account_fields_modal.close',
|
||||
defaultMessage: 'Close',
|
||||
})}
|
||||
/>
|
||||
<span className={`${classes.modalTitle} dialog-modal__header__title`}>
|
||||
<FormattedMessage
|
||||
id='account_fields_modal.title'
|
||||
defaultMessage="{name}'s info"
|
||||
values={{
|
||||
name: <DisplayName account={account} variant='simple' />,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className='dialog-modal__content'>
|
||||
<AnimateEmojiProvider>
|
||||
<dl className={classes.modalFieldsList}>
|
||||
{account.fields.map((field, index) => (
|
||||
<div key={index} className={classes.modalFieldItem}>
|
||||
<EmojiHTML
|
||||
as='dt'
|
||||
htmlString={field.name_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
className='translate'
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
<EmojiHTML
|
||||
as='dd'
|
||||
htmlString={field.value_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</AnimateEmojiProvider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,58 +0,0 @@
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
FollowersCounter,
|
||||
FollowingCounter,
|
||||
StatusesCounter,
|
||||
} from '@/mastodon/components/counters';
|
||||
import { ShortNumber } from '@/mastodon/components/short_number';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
|
||||
export const AccountLinks: FC<{ accountId: string }> = ({ accountId }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAccount(accountId);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account__header__extra__links'>
|
||||
<NavLink
|
||||
to={`/@${account.acct}`}
|
||||
title={intl.formatNumber(account.statuses_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.statuses_count}
|
||||
renderer={StatusesCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/following`}
|
||||
title={intl.formatNumber(account.following_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.following_count}
|
||||
renderer={FollowingCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/followers`}
|
||||
title={intl.formatNumber(account.followers_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.followers_count}
|
||||
renderer={FollowersCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
FollowersCounter,
|
||||
FollowingCounter,
|
||||
StatusesCounter,
|
||||
} from '@/mastodon/components/counters';
|
||||
import { FormattedDateWrapper } from '@/mastodon/components/formatted_date';
|
||||
import { ShortNumber } from '@/mastodon/components/short_number';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
|
||||
import { isRedesignEnabled } from '../common';
|
||||
|
||||
import classes from './redesign.module.scss';
|
||||
|
||||
export const AccountNumberFields: FC<{ accountId: string }> = ({
|
||||
accountId,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const account = useAccount(accountId);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'account__header__extra__links',
|
||||
isRedesignEnabled() && classes.fieldNumbersWrapper,
|
||||
)}
|
||||
>
|
||||
{!isRedesignEnabled() && (
|
||||
<NavLink
|
||||
to={`/@${account.acct}`}
|
||||
title={intl.formatNumber(account.statuses_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.statuses_count}
|
||||
renderer={StatusesCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/following`}
|
||||
title={intl.formatNumber(account.following_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.following_count}
|
||||
renderer={FollowingCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/followers`}
|
||||
title={intl.formatNumber(account.followers_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.followers_count}
|
||||
renderer={FollowersCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
{isRedesignEnabled() && (
|
||||
<NavLink exact to={`/@${account.acct}`}>
|
||||
<FormattedMessage
|
||||
id='account.joined_long'
|
||||
defaultMessage='Joined on {date}'
|
||||
values={{
|
||||
date: (
|
||||
<strong>
|
||||
<FormattedDateWrapper
|
||||
value={account.created_at}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
/>
|
||||
</strong>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
.fieldList {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.fieldNumbersWrapper {
|
||||
a {
|
||||
font-weight: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.modalCloseButton {
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.modalTitle {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modalFieldsList {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.modalFieldItem {
|
||||
&:not(:first-child) {
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
&:not(:last-child)::after {
|
||||
content: '';
|
||||
display: block;
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
dt {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
dd {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ export const MODAL_COMPONENTS = {
|
||||
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
||||
'ANNUAL_REPORT': AnnualReportModal,
|
||||
'COMPOSE_PRIVACY': () => Promise.resolve({ default: VisibilityModal }),
|
||||
'ACCOUNT_FIELDS': () => import('mastodon/features/account_timeline/components/fields_modal.tsx').then(module => ({ default: module.AccountFieldsModal })),
|
||||
};
|
||||
|
||||
export default class ModalRoot extends PureComponent {
|
||||
|
||||
Reference in new issue
Block a user