Merge commit '562ea656f495f0619e393b7d93bd07c5abd28e5a' into glitch-soc/merge-upstream

This commit is contained in:
Claire committed 2026-01-21 22:04:02 +01:00
commit 95aaefe083
30 files changed
+404 -155

No files matched your search

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="url(#badgeGradient)" d="M8 .666c.301 0 .595.094.839.268l.101.079.006.005c1.092.956 2.603 1.649 3.721 1.649A1.333 1.333 0 0 1 14 4v4.667c0 1.842-.652 3.259-1.702 4.336-1.032 1.058-2.417 1.76-3.852 2.26l-.005.002a1.334 1.334 0 0 1-.879-.01c-1.437-.496-2.825-1.195-3.858-2.253C2.654 11.926 2 10.509 2 8.667V4a1.334 1.334 0 0 1 1.334-1.333c1.118 0 2.634-.7 3.72-1.65l.007-.004C7.322.789 7.656.666 8 .666Z"/>
<path stroke="#fff" fill="none" stroke-linecap="round" stroke-linejoin="round" d="M5 10.998A3.053 3.053 0 0 1 6.173 9.57a3.333 3.333 0 0 1 1.828-.54m0 0c.653 0 1.29.189 1.826.54.537.353.946.852 1.173 1.43M8 9.03c1.179 0 2.133-.903 2.133-2.015C10.133 5.902 9.178 5 8 5c-1.179 0-2.134.902-2.134 2.015 0 1.112.956 2.015 2.135 2.015Z"/>
<defs>
<linearGradient id="badgeGradient" x1=".5" x2="14" y1="2.5" y2="15" gradientUnits="userSpaceOnUse">
<stop stop-color="#E17100"/>
<stop offset="1" stop-color="#F0B100"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16">
<path fill="url(#VerifiedGradient)" d="M8 .837a3.168 3.168 0 0 1 2.47 1.187 3.166 3.166 0 0 1 2.601.906 3.168 3.168 0 0 1 .905 2.6A3.167 3.167 0 0 1 15.164 8a3.172 3.172 0 0 1-1.188 2.47 3.167 3.167 0 0 1-.903 2.597 3.168 3.168 0 0 1-2.596.909 3.167 3.167 0 0 1-4.95.001 3.166 3.166 0 0 1-3.397-2.258 3.169 3.169 0 0 1-.107-1.24A3.168 3.168 0 0 1 .826 8a3.17 3.17 0 0 1 1.197-2.479 3.168 3.168 0 0 1 .91-2.593 3.166 3.166 0 0 1 2.596-.905A3.169 3.169 0 0 1 8 .837Z"/>
<path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.333" d="m6 8 1.333 1.333L10 6.667"/>
<defs>
<linearGradient id="VerifiedGradient" x1="-.966" x2="12.162" y1="2.629" y2="17.493" gradientUnits="userSpaceOnUse">
<stop offset=".13" stop-color="#5638CC"/>
<stop offset=".995" stop-color="#DC03F0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 930 B

@@ -1,31 +0,0 @@
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import GroupsIcon from '@/material-icons/400-24px/group.svg?react';
import PersonIcon from '@/material-icons/400-24px/person.svg?react';
import SmartToyIcon from '@/material-icons/400-24px/smart_toy.svg?react';
export const Badge = ({ icon = <PersonIcon />, label, domain, roleId }) => (
<div className='account-role' data-account-role-id={roleId}>
{icon}
{label}
{domain && <span className='account-role__domain'>{domain}</span>}
</div>
);
Badge.propTypes = {
icon: PropTypes.node,
label: PropTypes.node,
domain: PropTypes.node,
roleId: PropTypes.string
};
export const GroupBadge = () => (
<Badge icon={<GroupsIcon />} label={<FormattedMessage id='account.badges.group' defaultMessage='Group' />} />
);
export const AutomatedBadge = () => (
<Badge icon={<SmartToyIcon />} label={<FormattedMessage id='account.badges.bot' defaultMessage='Automated' />} />
);
@@ -0,0 +1,46 @@
import type { FC, ReactNode } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import GroupsIcon from '@/material-icons/400-24px/group.svg?react';
import PersonIcon from '@/material-icons/400-24px/person.svg?react';
import SmartToyIcon from '@/material-icons/400-24px/smart_toy.svg?react';
export const Badge: FC<{
label: ReactNode;
icon?: ReactNode;
className?: string;
domain?: ReactNode;
roleId?: string;
}> = ({ icon = <PersonIcon />, label, className, domain, roleId }) => (
<div
className={classNames('account-role', className)}
data-account-role-id={roleId}
>
{icon}
{label}
{domain && <span className='account-role__domain'>{domain}</span>}
</div>
);
export const GroupBadge: FC<{ className?: string }> = ({ className }) => (
<Badge
icon={<GroupsIcon />}
label={
<FormattedMessage id='account.badges.group' defaultMessage='Group' />
}
className={className}
/>
);
export const AutomatedBadge: FC<{ className?: string }> = ({ className }) => (
<Badge
icon={<SmartToyIcon />}
label={
<FormattedMessage id='account.badges.bot' defaultMessage='Automated' />
}
className={className}
/>
);
@@ -10,7 +10,9 @@ import type { MiniCardProps } from '.';
import classes from './styles.module.css';
interface MiniCardListProps {
cards?: (Pick<MiniCardProps, 'label' | 'value'> & { key?: Key })[];
cards?: (Pick<MiniCardProps, 'label' | 'value' | 'className'> & {
key?: Key;
})[];
className?: string;
onOverflowClick?: MouseEventHandler;
}
@@ -42,6 +44,7 @@ export const MiniCardList: FC<MiniCardListProps> = ({
label={card.label}
value={card.value}
hidden={hasOverflow && index >= hiddenIndex}
className={card.className}
/>
))}
</dl>
@@ -1,9 +1,16 @@
import type { FC } from 'react';
import type { FC, ReactNode } from 'react';
import IconAdmin from '@/images/icons/icon_admin.svg?react';
import { AutomatedBadge, Badge, GroupBadge } from '@/mastodon/components/badge';
import { Icon } from '@/mastodon/components/icon';
import { useAccount } from '@/mastodon/hooks/useAccount';
import type { AccountRole } from '@/mastodon/models/account';
import { useAppSelector } from '@/mastodon/store';
import { isRedesignEnabled } from '../common';
import classes from './redesign.module.scss';
export const AccountBadges: FC<{ accountId: string }> = ({ accountId }) => {
const account = useAccount(accountId);
const localDomain = useAppSelector(
@@ -15,22 +22,32 @@ export const AccountBadges: FC<{ accountId: string }> = ({ accountId }) => {
return null;
}
const className = isRedesignEnabled() ? classes.badge : '';
if (account.bot) {
badges.push(<AutomatedBadge key='bot-badge' />);
badges.push(<AutomatedBadge key='bot-badge' className={className} />);
} else if (account.group) {
badges.push(<GroupBadge key='group-badge' />);
badges.push(<GroupBadge key='group-badge' className={className} />);
}
const domain = account.acct.includes('@')
? account.acct.split('@')[1]
: localDomain;
account.roles.forEach((role) => {
let icon: ReactNode = undefined;
if (isAdminBadge(role)) {
icon = (
<Icon icon={IconAdmin} id='badge-admin' className={classes.badgeIcon} />
);
}
badges.push(
<Badge
key={`role-badge-${role.get('id')}`}
label={<span>{role.get('name')}</span>}
domain={domain}
roleId={role.get('id')}
key={role.id}
label={role.name}
className={className}
domain={isRedesignEnabled() ? `(${domain})` : domain}
roleId={role.id}
icon={icon}
/>,
);
});
@@ -39,5 +56,10 @@ export const AccountBadges: FC<{ accountId: string }> = ({ accountId }) => {
return null;
}
return <div className='account__header__badges'>{badges}</div>;
return <div className={'account__header__badges'}>{badges}</div>;
};
function isAdminBadge(role: AccountRole) {
const name = role.name.toLowerCase();
return isRedesignEnabled() && (name === 'admin' || name === 'owner');
}
@@ -3,10 +3,14 @@ import type { FC } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import IconVerified from '@/images/icons/icon_verified.svg?react';
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 { Icon } from '@/mastodon/components/icon';
import { MiniCardList } from '@/mastodon/components/mini_card/list';
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
import { useAccount } from '@/mastodon/hooks/useAccount';
@@ -55,25 +59,40 @@ 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.fields
.toArray()
.map(({ value_emojified, name_emojified, verified_at }) => ({
label: (
<>
<EmojiHTML
htmlString={name_emojified}
extraEmojis={account.emojis}
className='translate'
as='span'
{...htmlHandlers}
/>
{!!verified_at && (
<Icon
id='verified'
icon={IconVerified}
className={classes.fieldIconVerified}
/>
)}
</>
),
value: (
<EmojiHTML
as='span'
htmlString={value_emojified}
extraEmojis={account.emojis}
{...htmlHandlers}
/>
),
className: classNames(
classes.fieldCard,
!!verified_at && classes.fieldCardVerified,
),
})),
[account.emojis, account.fields, htmlHandlers],
);
@@ -2,9 +2,11 @@ import type { FC } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import IconVerified from '@/images/icons/icon_verified.svg?react';
import { DisplayName } from '@/mastodon/components/display_name';
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
import { EmojiHTML } from '@/mastodon/components/emoji/html';
import { Icon } from '@/mastodon/components/icon';
import { IconButton } from '@/mastodon/components/icon_button';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
@@ -56,7 +58,10 @@ export const AccountFieldsModal: FC<{
<AnimateEmojiProvider>
<dl className={classes.modalFieldsList}>
{account.fields.map((field, index) => (
<div key={index} className={classes.modalFieldItem}>
<div
key={index}
className={`${classes.modalFieldItem} ${classes.fieldCard}`}
>
<EmojiHTML
as='dt'
htmlString={field.name_emojified}
@@ -64,12 +69,21 @@ export const AccountFieldsModal: FC<{
className='translate'
{...htmlHandlers}
/>
<EmojiHTML
as='dd'
htmlString={field.value_emojified}
extraEmojis={account.emojis}
{...htmlHandlers}
/>
<dd>
<EmojiHTML
as='span'
htmlString={field.value_emojified}
extraEmojis={account.emojis}
{...htmlHandlers}
/>
{!!field.verified_at && (
<Icon
id='verified'
icon={IconVerified}
className={classes.fieldIconVerified}
/>
)}
</dd>
</div>
))}
</dl>
@@ -39,10 +39,64 @@ h1.name > small {
}
}
.badge {
background-color: var(--color-bg-secondary);
border: none;
color: var(--color-text-secondary);
font-weight: 600;
> span {
font-weight: unset;
opacity: 1;
}
}
svg.badgeIcon {
opacity: 1;
fill: revert-layer;
path {
fill: revert-layer;
}
}
.fieldList {
margin-top: 16px;
}
.fieldCard {
position: relative;
a {
color: var(--color-text-brand);
text-decoration: none;
}
}
.fieldCardVerified {
background-color: var(--color-bg-brand-softer);
dt {
padding-right: 1rem;
}
.fieldIconVerified {
position: absolute;
top: 4px;
right: 4px;
}
}
.fieldIconVerified {
width: 1rem;
height: 1rem;
// Need to override .icon path.
path {
fill: revert-layer;
}
}
.fieldNumbersWrapper {
a {
font-weight: unset;
@@ -85,4 +139,9 @@ h1.name > small {
font-weight: 600;
font-size: 15px;
}
.fieldIconVerified {
vertical-align: middle;
margin-left: 4px;
}
}
+4
View File
@@ -57,6 +57,7 @@
"account.go_to_profile": "Ir al perfil",
"account.hide_reblogs": "Ocultar impulsos de @{name}",
"account.in_memoriam": "Cuenta conmemorativa.",
"account.joined_long": "Se unió el {date}",
"account.joined_short": "Se unió",
"account.languages": "Cambiar idiomas suscritos",
"account.link_verified_on": "La propiedad de este enlace fue verificada el {date}",
@@ -90,6 +91,8 @@
"account.unmute": "Dejar de silenciar a @{name}",
"account.unmute_notifications_short": "Dejar de silenciar notificaciones",
"account.unmute_short": "Dejar de silenciar",
"account_fields_modal.close": "Cerrar",
"account_fields_modal.title": "Información de {name}",
"account_note.placeholder": "Haz clic para añadir nota",
"admin.dashboard.daily_retention": "Tasa de retención de usuarios por día después del registro",
"admin.dashboard.monthly_retention": "Tasa de retención de usuarios por mes después del registro",
@@ -589,6 +592,7 @@
"load_pending": "{count, plural, one {# nuevo elemento} other {# nuevos elementos}}",
"loading_indicator.label": "Cargando…",
"media_gallery.hide": "Ocultar",
"minicard.more_items": "+{count}",
"moved_to_account_banner.text": "Tu cuenta {disabledAccount} está actualmente deshabilitada porque te has mudado a {movedToAccount}.",
"mute_modal.hide_from_notifications": "Ocultar de las notificaciones",
"mute_modal.hide_options": "Ocultar opciones",
@@ -142,6 +142,7 @@
var(--border-strength-primary)
)};
--color-border-media: rgb(252 248 255 / 15%);
--color-border-verified: rgb(220, 3, 240);
--color-border-on-bg-secondary: #{utils.css-alpha(
var(--color-indigo-200),
calc(var(--border-strength-primary) / 1.5)
@@ -140,6 +140,7 @@
var(--color-grey-950) var(--border-strength-primary)
);
--color-border-media: rgb(252 248 255 / 15%);
--color-border-verified: rgb(220, 3, 240);
--color-border-on-bg-secondary: var(--color-grey-200);
--color-border-on-bg-brand-softer: var(--color-indigo-200);
--color-border-on-bg-error-softer: #{utils.css-alpha(