Merge pull request #3071 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 6c743831aa
This commit is contained in:
@@ -124,7 +124,7 @@ GEM
|
||||
binding_of_caller (1.0.1)
|
||||
debug_inspector (>= 1.2.0)
|
||||
blurhash (0.1.8)
|
||||
bootsnap (1.18.4)
|
||||
bootsnap (1.18.5)
|
||||
msgpack (~> 1.2)
|
||||
brakeman (7.0.2)
|
||||
racc
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useHovering } from 'flavours/glitch/hooks/useHovering';
|
||||
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
||||
import type { Account } from 'flavours/glitch/models/account';
|
||||
|
||||
interface Props {
|
||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size: number;
|
||||
account:
|
||||
| Pick<Account, 'id' | 'acct' | 'avatar' | 'avatar_static'>
|
||||
| undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size?: number;
|
||||
style?: React.CSSProperties;
|
||||
inline?: boolean;
|
||||
animate?: boolean;
|
||||
withLink?: boolean;
|
||||
counter?: number | string;
|
||||
counterBorderColor?: string;
|
||||
}
|
||||
@@ -21,6 +25,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
animate = autoPlayGif,
|
||||
size = 20,
|
||||
inline = false,
|
||||
withLink = false,
|
||||
style: styleFromParent,
|
||||
counter,
|
||||
counterBorderColor,
|
||||
@@ -35,10 +40,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
height: `${size}px`,
|
||||
};
|
||||
|
||||
const src =
|
||||
hovering || animate
|
||||
? account?.get('avatar')
|
||||
: account?.get('avatar_static');
|
||||
const src = hovering || animate ? account?.avatar : account?.avatar_static;
|
||||
|
||||
const handleLoad = useCallback(() => {
|
||||
setLoading(false);
|
||||
@@ -48,7 +50,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
setError(true);
|
||||
}, [setError]);
|
||||
|
||||
return (
|
||||
const avatar = (
|
||||
<div
|
||||
className={classNames('account__avatar', {
|
||||
'account__avatar--inline': inline,
|
||||
@@ -57,7 +59,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
style={style}
|
||||
data-avatar-of={account && `@${account.get('acct')}`}
|
||||
data-avatar-of={account && `@${account.acct}`}
|
||||
>
|
||||
{src && !error && (
|
||||
<img src={src} alt='' onLoad={handleLoad} onError={handleError} />
|
||||
@@ -73,4 +75,18 @@ export const Avatar: React.FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (withLink) {
|
||||
return (
|
||||
<Link
|
||||
to={`/@${account?.acct}`}
|
||||
title={`@${account?.acct}`}
|
||||
data-hover-card-account={account?.id}
|
||||
>
|
||||
{avatar}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return avatar;
|
||||
};
|
||||
|
||||
@@ -1,34 +1,17 @@
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import { useAppSelector } from 'flavours/glitch/store';
|
||||
|
||||
const AvatarWrapper: React.FC<{ accountId: string }> = ({ accountId }) => {
|
||||
const account = useAppSelector((state) => state.accounts.get(accountId));
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/@${account.acct}`}
|
||||
title={`@${account.acct}`}
|
||||
data-hover-card-account={account.id}
|
||||
>
|
||||
<Avatar account={account} size={28} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Wrapper for displaying a number of Avatar components horizontally,
|
||||
* either spaced out (default) or overlapping (using the `compact` prop).
|
||||
*/
|
||||
|
||||
export const AvatarGroup: React.FC<{
|
||||
accountIds: string[];
|
||||
compact?: boolean;
|
||||
}> = ({ accountIds, compact = false }) => (
|
||||
children: React.ReactNode;
|
||||
}> = ({ children, compact = false }) => (
|
||||
<div
|
||||
className={classNames('avatar-group', { 'avatar-group--compact': compact })}
|
||||
>
|
||||
{accountIds.map((accountId) => (
|
||||
<AvatarWrapper key={accountId} accountId={accountId} />
|
||||
))}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -916,6 +916,10 @@ export const AccountHeader: React.FC<{
|
||||
<div className='account__header__badges'>{badges}</div>
|
||||
)}
|
||||
|
||||
{account.id !== me && signedIn && (
|
||||
<FamiliarFollowers accountId={accountId} />
|
||||
)}
|
||||
|
||||
{!(suspended || hidden) && (
|
||||
<div className='account__header__extra'>
|
||||
<div
|
||||
@@ -993,7 +997,6 @@ export const AccountHeader: React.FC<{
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{signedIn && <FamiliarFollowers accountId={accountId} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -5,16 +5,25 @@ import { FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { fetchAccountsFamiliarFollowers } from '@/flavours/glitch/actions/accounts_familiar_followers';
|
||||
import { Avatar } from '@/flavours/glitch/components/avatar';
|
||||
import { AvatarGroup } from '@/flavours/glitch/components/avatar_group';
|
||||
import type { Account } from '@/flavours/glitch/models/account';
|
||||
import { getAccountFamiliarFollowers } from '@/flavours/glitch/selectors/accounts';
|
||||
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
|
||||
|
||||
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => (
|
||||
<Link to={`/@${account?.username}`} data-hover-card-account={account?.id}>
|
||||
{account?.display_name}
|
||||
</Link>
|
||||
);
|
||||
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => {
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/@${account.acct}`}
|
||||
data-hover-card-account={account.id}
|
||||
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
|
||||
familiarFollowers,
|
||||
@@ -45,7 +54,7 @@ const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='account.familiar_followers_many'
|
||||
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {# other} other {# others}}'
|
||||
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {one other you know} other {# others you know}}'
|
||||
values={messageData}
|
||||
/>
|
||||
);
|
||||
@@ -74,10 +83,11 @@ export const FamiliarFollowers: React.FC<{ accountId: string }> = ({
|
||||
|
||||
return (
|
||||
<div className='account__header__familiar-followers'>
|
||||
<AvatarGroup
|
||||
compact
|
||||
accountIds={familiarFollowers.slice(0, 3).map((account) => account.id)}
|
||||
/>
|
||||
<AvatarGroup compact>
|
||||
{familiarFollowers.slice(0, 3).map((account) => (
|
||||
<Avatar withLink key={account.id} account={account} size={28} />
|
||||
))}
|
||||
</AvatarGroup>
|
||||
<FamiliarFollowersReadout familiarFollowers={familiarFollowers} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -35,8 +35,11 @@ import { VerifiedBadge } from 'flavours/glitch/components/verified_badge';
|
||||
import { me } from 'flavours/glitch/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.list_members', defaultMessage: 'Manage list members' },
|
||||
export const messages = defineMessages({
|
||||
manageMembers: {
|
||||
id: 'column.list_members',
|
||||
defaultMessage: 'Manage list members',
|
||||
},
|
||||
placeholder: {
|
||||
id: 'lists.search',
|
||||
defaultMessage: 'Search',
|
||||
@@ -255,10 +258,10 @@ const ListMembers: React.FC<{
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
label={intl.formatMessage(messages.manageMembers)}
|
||||
>
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
title={intl.formatMessage(messages.manageMembers)}
|
||||
icon='list-ul'
|
||||
iconComponent={ListAltIcon}
|
||||
multiColumn={multiColumn}
|
||||
@@ -331,7 +334,7 @@ const ListMembers: React.FC<{
|
||||
</ScrollableList>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.heading)}</title>
|
||||
<title>{intl.formatMessage(messages.manageMembers)}</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
|
||||
@@ -9,16 +9,23 @@ import { isFulfilled } from '@reduxjs/toolkit';
|
||||
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||
import { fetchList } from 'flavours/glitch/actions/lists';
|
||||
import { createList, updateList } from 'flavours/glitch/actions/lists_typed';
|
||||
import { apiGetAccounts } from 'flavours/glitch/api/lists';
|
||||
import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
|
||||
import type { RepliesPolicyType } from 'flavours/glitch/api_types/lists';
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import { AvatarGroup } from 'flavours/glitch/components/avatar_group';
|
||||
import { Column } from 'flavours/glitch/components/column';
|
||||
import { ColumnHeader } from 'flavours/glitch/components/column_header';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
||||
|
||||
import { messages as membersMessages } from './members';
|
||||
|
||||
const messages = defineMessages({
|
||||
edit: { id: 'column.edit_list', defaultMessage: 'Edit list' },
|
||||
create: { id: 'column.create_list', defaultMessage: 'Create list' },
|
||||
@@ -27,42 +34,40 @@ const messages = defineMessages({
|
||||
const MembersLink: React.FC<{
|
||||
id: string;
|
||||
}> = ({ id }) => {
|
||||
const [count, setCount] = useState(0);
|
||||
const [avatars, setAvatars] = useState<string[]>([]);
|
||||
const intl = useIntl();
|
||||
const [avatarCount, setAvatarCount] = useState(0);
|
||||
const [avatarAccounts, setAvatarAccounts] = useState<ApiAccountJSON[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
void apiGetAccounts(id)
|
||||
.then((data) => {
|
||||
setCount(data.length);
|
||||
setAvatars(data.slice(0, 3).map((a) => a.avatar));
|
||||
return '';
|
||||
setAvatarCount(data.length);
|
||||
setAvatarAccounts(data.slice(0, 3));
|
||||
})
|
||||
.catch(() => {
|
||||
// Nothing
|
||||
});
|
||||
}, [id, setCount, setAvatars]);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<Link to={`/lists/${id}/members`} className='app-form__link'>
|
||||
<div className='app-form__link__text'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='lists.list_members'
|
||||
defaultMessage='List members'
|
||||
/>
|
||||
{intl.formatMessage(membersMessages.manageMembers)}
|
||||
<Icon id='chevron_right' icon={ChevronRightIcon} />
|
||||
</strong>
|
||||
<FormattedMessage
|
||||
id='lists.list_members_count'
|
||||
defaultMessage='{count, plural, one {# member} other {# members}}'
|
||||
values={{ count }}
|
||||
values={{ count: avatarCount }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='avatar-pile'>
|
||||
{avatars.map((url) => (
|
||||
<img key={url} src={url} alt='' />
|
||||
<AvatarGroup compact>
|
||||
{avatarAccounts.map((a) => (
|
||||
<Avatar key={a.id} account={a} size={30} />
|
||||
))}
|
||||
</div>
|
||||
</AvatarGroup>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HotKeys } from 'react-hotkeys';
|
||||
|
||||
import { replyComposeById } from 'flavours/glitch/actions/compose';
|
||||
import { navigateToStatus } from 'flavours/glitch/actions/statuses';
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import { AvatarGroup } from 'flavours/glitch/components/avatar_group';
|
||||
import type { IconProp } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
@@ -17,6 +18,14 @@ import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||
import { DisplayedName } from './displayed_name';
|
||||
import { EmbeddedStatus } from './embedded_status';
|
||||
|
||||
export const AvatarById: React.FC<{ accountId: string }> = ({ accountId }) => {
|
||||
const account = useAppSelector((state) => state.accounts.get(accountId));
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
return <Avatar withLink account={account} size={28} />;
|
||||
};
|
||||
|
||||
export type LabelRenderer = (
|
||||
displayedName: JSX.Element,
|
||||
total: number,
|
||||
@@ -99,12 +108,13 @@ export const NotificationGroupWithStatus: React.FC<{
|
||||
<div className='notification-group__main'>
|
||||
<div className='notification-group__main__header'>
|
||||
<div className='notification-group__main__header__wrapper'>
|
||||
<AvatarGroup
|
||||
accountIds={accountIds.slice(
|
||||
0,
|
||||
NOTIFICATIONS_GROUP_MAX_AVATARS,
|
||||
)}
|
||||
/>
|
||||
<AvatarGroup>
|
||||
{accountIds
|
||||
.slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS)
|
||||
.map((id) => (
|
||||
<AvatarById key={id} accountId={id} />
|
||||
))}
|
||||
</AvatarGroup>
|
||||
|
||||
{actions && (
|
||||
<div className='notification-group__actions'>{actions}</div>
|
||||
|
||||
@@ -2157,6 +2157,7 @@ body > [data-popper-placement] {
|
||||
display: block;
|
||||
position: relative;
|
||||
border-radius: var(--avatar-border-radius);
|
||||
background: var(--surface-background-color);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@@ -2243,11 +2244,19 @@ a .account__avatar {
|
||||
flex-wrap: nowrap;
|
||||
|
||||
& > :not(:first-child) {
|
||||
margin-inline-start: -8px;
|
||||
margin-inline-start: -12px;
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
box-shadow: 0 0 0 2px var(--background-color);
|
||||
}
|
||||
& > :first-child {
|
||||
transform: rotate(-4deg);
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
box-shadow: 0 0 0 2px var(--background-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8446,16 +8455,13 @@ noscript {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-block-end: 16px;
|
||||
margin-block: 16px;
|
||||
color: $darker-text-color;
|
||||
|
||||
a:any-link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,34 +1440,12 @@ code {
|
||||
display: block;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-pile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 2px solid var(--background-color);
|
||||
background: var(--surface-background-color);
|
||||
margin-inline-end: -16px;
|
||||
transform: rotate(0);
|
||||
|
||||
&:first-child {
|
||||
transform: rotate(-4deg);
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-inline-end: 0;
|
||||
|
||||
.icon {
|
||||
vertical-align: -5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { fromJS } from 'immutable';
|
||||
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import { accountDefaultValues, createAccountFromServerJSON } from '@/mastodon/models/account';
|
||||
|
||||
import { Avatar } from '../avatar';
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
const account = fromJS({
|
||||
const account = createAccountFromServerJSON({
|
||||
...accountDefaultValues,
|
||||
username: 'alice',
|
||||
acct: 'alice',
|
||||
display_name: 'Alice',
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useHovering } from 'mastodon/hooks/useHovering';
|
||||
import { autoPlayGif } from 'mastodon/initial_state';
|
||||
import type { Account } from 'mastodon/models/account';
|
||||
|
||||
interface Props {
|
||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size: number;
|
||||
account:
|
||||
| Pick<Account, 'id' | 'acct' | 'avatar' | 'avatar_static'>
|
||||
| undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size?: number;
|
||||
style?: React.CSSProperties;
|
||||
inline?: boolean;
|
||||
animate?: boolean;
|
||||
withLink?: boolean;
|
||||
counter?: number | string;
|
||||
counterBorderColor?: string;
|
||||
}
|
||||
@@ -21,6 +25,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
animate = autoPlayGif,
|
||||
size = 20,
|
||||
inline = false,
|
||||
withLink = false,
|
||||
style: styleFromParent,
|
||||
counter,
|
||||
counterBorderColor,
|
||||
@@ -35,10 +40,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
height: `${size}px`,
|
||||
};
|
||||
|
||||
const src =
|
||||
hovering || animate
|
||||
? account?.get('avatar')
|
||||
: account?.get('avatar_static');
|
||||
const src = hovering || animate ? account?.avatar : account?.avatar_static;
|
||||
|
||||
const handleLoad = useCallback(() => {
|
||||
setLoading(false);
|
||||
@@ -48,7 +50,7 @@ export const Avatar: React.FC<Props> = ({
|
||||
setError(true);
|
||||
}, [setError]);
|
||||
|
||||
return (
|
||||
const avatar = (
|
||||
<div
|
||||
className={classNames('account__avatar', {
|
||||
'account__avatar--inline': inline,
|
||||
@@ -72,4 +74,18 @@ export const Avatar: React.FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (withLink) {
|
||||
return (
|
||||
<Link
|
||||
to={`/@${account?.acct}`}
|
||||
title={`@${account?.acct}`}
|
||||
data-hover-card-account={account?.id}
|
||||
>
|
||||
{avatar}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return avatar;
|
||||
};
|
||||
|
||||
@@ -1,34 +1,17 @@
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { useAppSelector } from 'mastodon/store';
|
||||
|
||||
const AvatarWrapper: React.FC<{ accountId: string }> = ({ accountId }) => {
|
||||
const account = useAppSelector((state) => state.accounts.get(accountId));
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/@${account.acct}`}
|
||||
title={`@${account.acct}`}
|
||||
data-hover-card-account={account.id}
|
||||
>
|
||||
<Avatar account={account} size={28} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Wrapper for displaying a number of Avatar components horizontally,
|
||||
* either spaced out (default) or overlapping (using the `compact` prop).
|
||||
*/
|
||||
|
||||
export const AvatarGroup: React.FC<{
|
||||
accountIds: string[];
|
||||
compact?: boolean;
|
||||
}> = ({ accountIds, compact = false }) => (
|
||||
children: React.ReactNode;
|
||||
}> = ({ children, compact = false }) => (
|
||||
<div
|
||||
className={classNames('avatar-group', { 'avatar-group--compact': compact })}
|
||||
>
|
||||
{accountIds.map((accountId) => (
|
||||
<AvatarWrapper key={accountId} accountId={accountId} />
|
||||
))}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -912,6 +912,10 @@ export const AccountHeader: React.FC<{
|
||||
<div className='account__header__badges'>{badges}</div>
|
||||
)}
|
||||
|
||||
{account.id !== me && signedIn && (
|
||||
<FamiliarFollowers accountId={accountId} />
|
||||
)}
|
||||
|
||||
{!(suspended || hidden) && (
|
||||
<div className='account__header__extra'>
|
||||
<div
|
||||
@@ -1023,7 +1027,6 @@ export const AccountHeader: React.FC<{
|
||||
/>
|
||||
</NavLink>
|
||||
</div>
|
||||
{signedIn && <FamiliarFollowers accountId={accountId} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -5,16 +5,25 @@ import { FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { fetchAccountsFamiliarFollowers } from '@/mastodon/actions/accounts_familiar_followers';
|
||||
import { Avatar } from '@/mastodon/components/avatar';
|
||||
import { AvatarGroup } from '@/mastodon/components/avatar_group';
|
||||
import type { Account } from '@/mastodon/models/account';
|
||||
import { getAccountFamiliarFollowers } from '@/mastodon/selectors/accounts';
|
||||
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
||||
|
||||
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => (
|
||||
<Link to={`/@${account?.username}`} data-hover-card-account={account?.id}>
|
||||
{account?.display_name}
|
||||
</Link>
|
||||
);
|
||||
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => {
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/@${account.acct}`}
|
||||
data-hover-card-account={account.id}
|
||||
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
|
||||
familiarFollowers,
|
||||
@@ -45,7 +54,7 @@ const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='account.familiar_followers_many'
|
||||
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {# other} other {# others}}'
|
||||
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {one other you know} other {# others you know}}'
|
||||
values={messageData}
|
||||
/>
|
||||
);
|
||||
@@ -74,10 +83,11 @@ export const FamiliarFollowers: React.FC<{ accountId: string }> = ({
|
||||
|
||||
return (
|
||||
<div className='account__header__familiar-followers'>
|
||||
<AvatarGroup
|
||||
compact
|
||||
accountIds={familiarFollowers.slice(0, 3).map((account) => account.id)}
|
||||
/>
|
||||
<AvatarGroup compact>
|
||||
{familiarFollowers.slice(0, 3).map((account) => (
|
||||
<Avatar withLink key={account.id} account={account} size={28} />
|
||||
))}
|
||||
</AvatarGroup>
|
||||
<FamiliarFollowersReadout familiarFollowers={familiarFollowers} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -35,8 +35,11 @@ import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
||||
import { me } from 'mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.list_members', defaultMessage: 'Manage list members' },
|
||||
export const messages = defineMessages({
|
||||
manageMembers: {
|
||||
id: 'column.list_members',
|
||||
defaultMessage: 'Manage list members',
|
||||
},
|
||||
placeholder: {
|
||||
id: 'lists.search',
|
||||
defaultMessage: 'Search',
|
||||
@@ -255,10 +258,10 @@ const ListMembers: React.FC<{
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
label={intl.formatMessage(messages.manageMembers)}
|
||||
>
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
title={intl.formatMessage(messages.manageMembers)}
|
||||
icon='list-ul'
|
||||
iconComponent={ListAltIcon}
|
||||
multiColumn={multiColumn}
|
||||
@@ -331,7 +334,7 @@ const ListMembers: React.FC<{
|
||||
</ScrollableList>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.heading)}</title>
|
||||
<title>{intl.formatMessage(messages.manageMembers)}</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
|
||||
@@ -9,16 +9,23 @@ import { isFulfilled } from '@reduxjs/toolkit';
|
||||
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||
import { fetchList } from 'mastodon/actions/lists';
|
||||
import { createList, updateList } from 'mastodon/actions/lists_typed';
|
||||
import { apiGetAccounts } from 'mastodon/api/lists';
|
||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
import type { RepliesPolicyType } from 'mastodon/api_types/lists';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import { messages as membersMessages } from './members';
|
||||
|
||||
const messages = defineMessages({
|
||||
edit: { id: 'column.edit_list', defaultMessage: 'Edit list' },
|
||||
create: { id: 'column.create_list', defaultMessage: 'Create list' },
|
||||
@@ -27,42 +34,40 @@ const messages = defineMessages({
|
||||
const MembersLink: React.FC<{
|
||||
id: string;
|
||||
}> = ({ id }) => {
|
||||
const [count, setCount] = useState(0);
|
||||
const [avatars, setAvatars] = useState<string[]>([]);
|
||||
const intl = useIntl();
|
||||
const [avatarCount, setAvatarCount] = useState(0);
|
||||
const [avatarAccounts, setAvatarAccounts] = useState<ApiAccountJSON[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
void apiGetAccounts(id)
|
||||
.then((data) => {
|
||||
setCount(data.length);
|
||||
setAvatars(data.slice(0, 3).map((a) => a.avatar));
|
||||
return '';
|
||||
setAvatarCount(data.length);
|
||||
setAvatarAccounts(data.slice(0, 3));
|
||||
})
|
||||
.catch(() => {
|
||||
// Nothing
|
||||
});
|
||||
}, [id, setCount, setAvatars]);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<Link to={`/lists/${id}/members`} className='app-form__link'>
|
||||
<div className='app-form__link__text'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='lists.list_members'
|
||||
defaultMessage='List members'
|
||||
/>
|
||||
{intl.formatMessage(membersMessages.manageMembers)}
|
||||
<Icon id='chevron_right' icon={ChevronRightIcon} />
|
||||
</strong>
|
||||
<FormattedMessage
|
||||
id='lists.list_members_count'
|
||||
defaultMessage='{count, plural, one {# member} other {# members}}'
|
||||
values={{ count }}
|
||||
values={{ count: avatarCount }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='avatar-pile'>
|
||||
{avatars.map((url) => (
|
||||
<img key={url} src={url} alt='' />
|
||||
<AvatarGroup compact>
|
||||
{avatarAccounts.map((a) => (
|
||||
<Avatar key={a.id} account={a} size={30} />
|
||||
))}
|
||||
</div>
|
||||
</AvatarGroup>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HotKeys } from 'react-hotkeys';
|
||||
|
||||
import { replyComposeById } from 'mastodon/actions/compose';
|
||||
import { navigateToStatus } from 'mastodon/actions/statuses';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
||||
import type { IconProp } from 'mastodon/components/icon';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
@@ -17,6 +18,14 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
import { DisplayedName } from './displayed_name';
|
||||
import { EmbeddedStatus } from './embedded_status';
|
||||
|
||||
export const AvatarById: React.FC<{ accountId: string }> = ({ accountId }) => {
|
||||
const account = useAppSelector((state) => state.accounts.get(accountId));
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
return <Avatar withLink account={account} size={28} />;
|
||||
};
|
||||
|
||||
export type LabelRenderer = (
|
||||
displayedName: JSX.Element,
|
||||
total: number,
|
||||
@@ -99,12 +108,13 @@ export const NotificationGroupWithStatus: React.FC<{
|
||||
<div className='notification-group__main'>
|
||||
<div className='notification-group__main__header'>
|
||||
<div className='notification-group__main__header__wrapper'>
|
||||
<AvatarGroup
|
||||
accountIds={accountIds.slice(
|
||||
0,
|
||||
NOTIFICATIONS_GROUP_MAX_AVATARS,
|
||||
)}
|
||||
/>
|
||||
<AvatarGroup>
|
||||
{accountIds
|
||||
.slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS)
|
||||
.map((id) => (
|
||||
<AvatarById key={id} accountId={id} />
|
||||
))}
|
||||
</AvatarGroup>
|
||||
|
||||
{actions && (
|
||||
<div className='notification-group__actions'>{actions}</div>
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
"account.edit_profile": "Редактиране на профила",
|
||||
"account.enable_notifications": "Известяване при публикуване от @{name}",
|
||||
"account.endorse": "Представи в профила",
|
||||
"account.familiar_followers_many": "Последвано от {name1}, {name2} и {othersCount, plural, one {# друг} other {# други}}",
|
||||
"account.familiar_followers_one": "Последвано от {name1}",
|
||||
"account.familiar_followers_two": "Последвано от {name1} и {name2}",
|
||||
"account.featured": "Препоръчано",
|
||||
"account.featured.accounts": "Профили",
|
||||
"account.featured.hashtags": "Хаштагове",
|
||||
@@ -304,6 +307,7 @@
|
||||
"emoji_button.search_results": "Резултати от търсене",
|
||||
"emoji_button.symbols": "Символи",
|
||||
"emoji_button.travel": "Пътуване и места",
|
||||
"empty_column.account_featured_other.unknown": "Този акаунт още не е отличил нищо.",
|
||||
"empty_column.account_hides_collections": "Този потребител е избрал да не дава тази информация",
|
||||
"empty_column.account_suspended": "Спрян акаунт",
|
||||
"empty_column.account_timeline": "Тук няма публикации!",
|
||||
@@ -508,7 +512,6 @@
|
||||
"lists.exclusive": "Скриване на членуващи в Начало",
|
||||
"lists.exclusive_hint": "Ако някой е в този списък, то скрийте го в инфоканала си на Начало, за да избегнете виждането на публикациите му два пъти.",
|
||||
"lists.find_users_to_add": "Намерете потребители за добавяне",
|
||||
"lists.list_members": "Списък членуващи",
|
||||
"lists.list_members_count": "{count, plural, one {# членуващ} other {# членуващи}}",
|
||||
"lists.list_name": "Име на списък",
|
||||
"lists.new_list_name": "Ново име на списък",
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
"account.edit_profile": "Edita el perfil",
|
||||
"account.enable_notifications": "Notifica'm els tuts de @{name}",
|
||||
"account.endorse": "Recomana en el perfil",
|
||||
"account.familiar_followers_many": "Seguit per {name1}, {name2} i {othersCount, plural, one {# altre compte} other {# altres comptes}}",
|
||||
"account.familiar_followers_one": "Seguit per {name1}",
|
||||
"account.familiar_followers_two": "Seguit per {name1} i {name2}",
|
||||
"account.featured": "Destacat",
|
||||
"account.featured.accounts": "Perfils",
|
||||
"account.featured.hashtags": "Etiquetes",
|
||||
@@ -514,7 +517,6 @@
|
||||
"lists.exclusive": "Amaga membres a Inici",
|
||||
"lists.exclusive_hint": "Si algú és a la llista, amagueu-los de la pantalla d'inici, per a no veure'n les publicacions duplicades.",
|
||||
"lists.find_users_to_add": "Troba usuaris per a afegir",
|
||||
"lists.list_members": "Membres de la llista",
|
||||
"lists.list_members_count": "{count, plural, one {# membre} other {# membres}}",
|
||||
"lists.list_name": "Nom de la llista",
|
||||
"lists.new_list_name": "Nom de la nova llista",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Skrýt členy na domovském kanálu",
|
||||
"lists.exclusive_hint": "Pokud je někdo na tomto seznamu, skryjte jej ve vašem domovském kanálu, abyste se vyhnuli dvojímu vidění jejich příspěvků.",
|
||||
"lists.find_users_to_add": "Najít uživatele, které chcete přidat",
|
||||
"lists.list_members": "Členové seznamu",
|
||||
"lists.list_members_count": "{count, plural, one {# člen} few {# členové} many {# členů} other {# členů}}",
|
||||
"lists.list_name": "Název seznamu",
|
||||
"lists.new_list_name": "Název nového seznamu",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "Cuddio aelodau yn y Cartref",
|
||||
"lists.exclusive_hint": "Os oes rhywun ar y rhestr hon, cuddiwch nhw yn eich llif Cartref i osgoi gweld eu postiadau ddwywaith.",
|
||||
"lists.find_users_to_add": "Canfod defnyddwyr i'w hychwanegu",
|
||||
"lists.list_members": "Aelodau rhestr",
|
||||
"lists.list_members_count": "{count, plural, one {# aelod} other {# aelod}}",
|
||||
"lists.list_name": "Enw rhestr",
|
||||
"lists.new_list_name": "Enw rhestr newydd",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Skjul medlemmer i Hjem",
|
||||
"lists.exclusive_hint": "Er nogen er på denne liste, skjul personen i hjemme-feeds for at undgå at se vedkommendes indlæg to gange.",
|
||||
"lists.find_users_to_add": "Find brugere at tilføje",
|
||||
"lists.list_members": "Liste over medlemmer",
|
||||
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmer}}",
|
||||
"lists.list_name": "Listetitel",
|
||||
"lists.new_list_name": "Ny listetitel",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Mitglieder auf der Startseite ausblenden",
|
||||
"lists.exclusive_hint": "Profile, die sich auf dieser Liste befinden, werden nicht auf deiner Startseite angezeigt, damit deren Beiträge nicht doppelt erscheinen.",
|
||||
"lists.find_users_to_add": "Suche nach Profilen, um sie hinzuzufügen",
|
||||
"lists.list_members": "Listenmitglieder",
|
||||
"lists.list_members_count": "{count, plural, one {# Mitglied} other {# Mitglieder}}",
|
||||
"lists.list_name": "Titel der Liste",
|
||||
"lists.new_list_name": "Neuer Listentitel",
|
||||
|
||||
@@ -497,7 +497,6 @@
|
||||
"lists.exclusive": "Απόκρυψη μελών από την Αρχική",
|
||||
"lists.exclusive_hint": "Αν κάποιος είναι σε αυτή τη λίστα, απόκρυψέ τον στην Αρχική σου για να αποφύγεις να βλέπεις τις αναρτήσεις του δύο φορές.",
|
||||
"lists.find_users_to_add": "Εύρεση χρηστών για προσθήκη",
|
||||
"lists.list_members": "Λίστα μελών",
|
||||
"lists.list_members_count": "{count, plural, one {# μέλος} other {# μέλη}}",
|
||||
"lists.list_name": "Όνομα λίστας",
|
||||
"lists.new_list_name": "Νέο όνομα λίστας",
|
||||
|
||||
@@ -490,7 +490,6 @@
|
||||
"lists.exclusive": "Hide members in Home",
|
||||
"lists.exclusive_hint": "If someone is on this list, hide them in your Home feed to avoid seeing their posts twice.",
|
||||
"lists.find_users_to_add": "Find users to add",
|
||||
"lists.list_members": "List members",
|
||||
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
|
||||
"lists.list_name": "List name",
|
||||
"lists.new_list_name": "New list name",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"account.edit_profile": "Edit profile",
|
||||
"account.enable_notifications": "Notify me when @{name} posts",
|
||||
"account.endorse": "Feature on profile",
|
||||
"account.familiar_followers_many": "Followed by {name1}, {name2}, and {othersCount, plural, one {# other} other {# others}}",
|
||||
"account.familiar_followers_many": "Followed by {name1}, {name2}, and {othersCount, plural, one {one other you know} other {# others you know}}",
|
||||
"account.familiar_followers_one": "Followed by {name1}",
|
||||
"account.familiar_followers_two": "Followed by {name1} and {name2}",
|
||||
"account.featured": "Featured",
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Hide members in Home",
|
||||
"lists.exclusive_hint": "If someone is on this list, hide them in your Home feed to avoid seeing their posts twice.",
|
||||
"lists.find_users_to_add": "Find users to add",
|
||||
"lists.list_members": "List members",
|
||||
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
|
||||
"lists.list_name": "List name",
|
||||
"lists.new_list_name": "New list name",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "Kaŝi membrojn en Hejmpaĝo",
|
||||
"lists.exclusive_hint": "Se iu estas en ĉi tiuj listo, kaŝu ilin en via hejmpaĝo por eviti vidi iliajn afiŝojn dufoje.",
|
||||
"lists.find_users_to_add": "Trovi uzantojn por aldoni",
|
||||
"lists.list_members": "Listoj de membroj",
|
||||
"lists.list_members_count": "{count, plural,one {# membro} other {# membroj}}",
|
||||
"lists.list_name": "Nomo de la listo",
|
||||
"lists.new_list_name": "Nomo de nova listo",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Ocultar miembros en la línea temporal principal",
|
||||
"lists.exclusive_hint": "Si alguien está en esta lista, ocultalo en tu línea temporal principal para evitar que aparezcan sus mensajes dos veces.",
|
||||
"lists.find_users_to_add": "Buscar usuarios para agregar",
|
||||
"lists.list_members": "Miembros de lista",
|
||||
"lists.list_members_count": "{count, plural,one {# miembro} other {# miembros}}",
|
||||
"lists.list_name": "Nombre de la lista",
|
||||
"lists.new_list_name": "Nombre de la nueva lista",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Ocultar miembros en Inicio",
|
||||
"lists.exclusive_hint": "Si alguien aparece en esta lista, ocúltalo en tu página de inicio para evitar ver sus publicaciones dos veces.",
|
||||
"lists.find_users_to_add": "Buscar usuarios para agregar",
|
||||
"lists.list_members": "Miembros de la lista",
|
||||
"lists.list_members_count": "{count, plural,one {# miembro} other {# miembros}}",
|
||||
"lists.list_name": "Nombre de la lista",
|
||||
"lists.new_list_name": "Nombre de la nueva lista",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"account.edit_profile": "Editar perfil",
|
||||
"account.enable_notifications": "Notificarme cuando @{name} publique algo",
|
||||
"account.endorse": "Destacar en el perfil",
|
||||
"account.familiar_followers_many": "Seguido por {name1}, {name2} y {othersCount, plural, one {# otro} other {# otros}}",
|
||||
"account.familiar_followers_many": "Seguido por {name1}, {name2} y {othersCount, plural, one {# más} other {# más}}",
|
||||
"account.familiar_followers_one": "Seguido por {name1}",
|
||||
"account.familiar_followers_two": "Seguido por {name1} y {name2}",
|
||||
"account.featured": "Destacado",
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Ocultar miembros en Inicio",
|
||||
"lists.exclusive_hint": "Si alguien está en esta lista, escóndelo en tu página de inicio para evitar ver sus publicaciones dos veces.",
|
||||
"lists.find_users_to_add": "Buscar usuarios para añadir",
|
||||
"lists.list_members": "Miembros de la lista",
|
||||
"lists.list_members_count": "{count, plural,one {# miembro} other {# miembros}}",
|
||||
"lists.list_name": "Nombre de la lista",
|
||||
"lists.new_list_name": "Nombre de la nueva lista",
|
||||
|
||||
@@ -490,7 +490,6 @@
|
||||
"lists.exclusive": "Peida avalehelt liikmed",
|
||||
"lists.exclusive_hint": "Kui keegi on selles loetelus, peida ta avalehe lõimest, vältimaks tema postituste kaks korda nägemist.",
|
||||
"lists.find_users_to_add": "Leia kasutajaid, keda lisada",
|
||||
"lists.list_members": "Loetelu liikmed",
|
||||
"lists.list_members_count": "{count, plural, one {# liige} other {# liiget}}",
|
||||
"lists.list_name": "Loetelu nimi",
|
||||
"lists.new_list_name": "Loetelu uus nimi",
|
||||
|
||||
@@ -510,7 +510,6 @@
|
||||
"lists.exclusive": "نهفتن اعضا در خانه",
|
||||
"lists.exclusive_hint": "اگر کسی در این سیاهه باشد، در خوراک خانگیتان نهفته تا از نمایش دویارهٔ فرستههایش خودداری شود.",
|
||||
"lists.find_users_to_add": "یافتن کاربرانی برای افزودن",
|
||||
"lists.list_members": "اعضای سیاهه",
|
||||
"lists.list_members_count": "{count, plural,one {# عضو}other {# عضو}}",
|
||||
"lists.list_name": "نام سیاهه",
|
||||
"lists.new_list_name": "نام سیاههٔ جدید",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Piilota jäsenet kotisyötteestä",
|
||||
"lists.exclusive_hint": "Jos joku on tässä listassa, piilota hänet kotisyötteestäsi, jotta et näe hänen julkaisujaan kahteen kertaan.",
|
||||
"lists.find_users_to_add": "Etsi lisättäviä käyttäjiä",
|
||||
"lists.list_members": "Listan jäsenet",
|
||||
"lists.list_members_count": "{count, plural, one {# jäsen} other {# jäsentä}}",
|
||||
"lists.list_name": "Listan nimi",
|
||||
"lists.new_list_name": "Uuden listan nimi",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Fjal limir á heimarás",
|
||||
"lists.exclusive_hint": "Um onkur er á hesum listanum, so skulu tey fjalast á heimarásini, so tú sleppir undan at síggja postar teirra tvær ferðir.",
|
||||
"lists.find_users_to_add": "Finn brúkarar at leggja afturat",
|
||||
"lists.list_members": "Lista limir",
|
||||
"lists.list_members_count": "{count, plural, one {# limur} other {# limir}}",
|
||||
"lists.list_name": "Listanavn",
|
||||
"lists.new_list_name": "Nýtt listanavn",
|
||||
|
||||
@@ -494,7 +494,6 @@
|
||||
"lists.exclusive": "Cacher les membres de la page d'accueil",
|
||||
"lists.exclusive_hint": "Si quelqu'un est dans cette liste, les cacher dans votre fil pour éviter de voir leurs messages deux fois.",
|
||||
"lists.find_users_to_add": "Trouver des utilisateurs à ajouter",
|
||||
"lists.list_members": "Lister les membres",
|
||||
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
|
||||
"lists.list_name": "Nom de la liste",
|
||||
"lists.new_list_name": "Nom de la nouvelle liste",
|
||||
|
||||
@@ -494,7 +494,6 @@
|
||||
"lists.exclusive": "Cacher les membres de la page d'accueil",
|
||||
"lists.exclusive_hint": "Si quelqu'un est dans cette liste, les cacher dans votre fil pour éviter de voir leurs messages deux fois.",
|
||||
"lists.find_users_to_add": "Trouver des utilisateurs à ajouter",
|
||||
"lists.list_members": "Lister les membres",
|
||||
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
|
||||
"lists.list_name": "Nom de la liste",
|
||||
"lists.new_list_name": "Nom de la nouvelle liste",
|
||||
|
||||
@@ -510,7 +510,6 @@
|
||||
"lists.exclusive": "Leden op jo Startside ferstopje",
|
||||
"lists.exclusive_hint": "As ien op dizze list stiet, ferstopje dizze persoan dan op jo starttiidline om foar te kommen dat harren berjochten twa kear toand wurde.",
|
||||
"lists.find_users_to_add": "Fyn brûkers om ta te foegjen",
|
||||
"lists.list_members": "Listleden",
|
||||
"lists.list_members_count": "{count, plural, one{# lid} other{# leden}}",
|
||||
"lists.list_name": "Listnamme",
|
||||
"lists.new_list_name": "Nije listnamme",
|
||||
|
||||
@@ -512,7 +512,6 @@
|
||||
"lists.exclusive": "Folaigh baill sa Bhaile",
|
||||
"lists.exclusive_hint": "Má tá duine ar an liosta seo, cuir i bhfolach iad i do fhotha Baile ionas nach bhfeicfidh tú a bpoist faoi dhó.",
|
||||
"lists.find_users_to_add": "Aimsigh úsáideoirí le cur leis",
|
||||
"lists.list_members": "Liostaigh baill",
|
||||
"lists.list_members_count": "{count, plural, one {# ball} two {# bhall} few {# baill} many {# baill} other {# baill}}",
|
||||
"lists.list_name": "Ainm an liosta",
|
||||
"lists.new_list_name": "Ainm liosta nua",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "Falaich na buill san dachaigh",
|
||||
"lists.exclusive_hint": "Falaich an fheadhainn a tha air an liosta seo air loidhne-ama na dachaigh ach nach fhaic thu na postaichean aca dà thuras.",
|
||||
"lists.find_users_to_add": "Lorg cleachdaichean ri chur ris",
|
||||
"lists.list_members": "Buill na liosta",
|
||||
"lists.list_members_count": "{count, plural, one {# bhall} two {# bhall} few {# buill} other {# ball}}",
|
||||
"lists.list_name": "Ainm na liosta",
|
||||
"lists.new_list_name": "Ainm na liosta ùire",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Ocultar membros no Inicio",
|
||||
"lists.exclusive_hint": "Se alguén está nesta lista non aparerá na cronoloxía de Inicio para evitar duplicidades das publicacións.",
|
||||
"lists.find_users_to_add": "Buscar persoas que engadir",
|
||||
"lists.list_members": "Membros da lista",
|
||||
"lists.list_members_count": "{count, plural, one {# membro} other {# membros}}",
|
||||
"lists.list_name": "Nome da lista",
|
||||
"lists.new_list_name": "Novo nome da lista",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "הסתרת החברים בפיד הבית",
|
||||
"lists.exclusive_hint": "אם שם כלשהו ברשימה זו, נסתיר אותי בפיד הבית כדי למנוע כפילות.",
|
||||
"lists.find_users_to_add": "חיפוש משתמשים להוספה",
|
||||
"lists.list_members": "פירוט חברי הרשימה",
|
||||
"lists.list_members_count": "{count, plural, one {חבר רשימה אחד} other {# חברי רשימה}}",
|
||||
"lists.list_name": "שם הרשימה",
|
||||
"lists.new_list_name": "שם רשימה חדשה",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Tagok elrejtése a kezdőlapon",
|
||||
"lists.exclusive_hint": "Ha valaki szerepel ezen a listán, el lesz rejtve a kezdőlapod hírfolyamán, hogy ne lásd kétszer a bejegyzéseit.",
|
||||
"lists.find_users_to_add": "Hozzáadandó felhasználók keresése",
|
||||
"lists.list_members": "Tagok listázása",
|
||||
"lists.list_members_count": "{count, plural, one {# tag} other {# tag}}",
|
||||
"lists.list_name": "Lista neve",
|
||||
"lists.new_list_name": "Új lista neve",
|
||||
|
||||
@@ -509,7 +509,6 @@
|
||||
"lists.exclusive": "Celar memberos in Initio",
|
||||
"lists.exclusive_hint": "Si alcuno es sur iste lista, celar iste persona in tu fluxo de initio pro evitar de vider su messages duo vices.",
|
||||
"lists.find_users_to_add": "Trovar usatores a adder",
|
||||
"lists.list_members": "Membros del lista",
|
||||
"lists.list_members_count": "{count, plural, one {# membro} other {# membros}}",
|
||||
"lists.list_name": "Nomine del lista",
|
||||
"lists.new_list_name": "Nove nomine de lista",
|
||||
|
||||
@@ -490,7 +490,6 @@
|
||||
"lists.exclusive": "Celar membri sur Hemo",
|
||||
"lists.exclusive_hint": "Se ulu es en ca listo, celez lu sur vua hemfluo por evitar vidar lua afishi denove.",
|
||||
"lists.find_users_to_add": "Serchi uzanti por adjuntar",
|
||||
"lists.list_members": "Listigar membri",
|
||||
"lists.list_members_count": "{count, plural,one {# membro} other {#membri}}",
|
||||
"lists.list_name": "Listonomo",
|
||||
"lists.new_list_name": "Nova listonomo",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Fela meðlimi í heimastreyminu",
|
||||
"lists.exclusive_hint": "Ef einhver er á þessum lista, geturðu falið viðkomandi í heimastreyminu þínu til að komast hjá því að sjá færslurnar þeirra í tvígang.",
|
||||
"lists.find_users_to_add": "Finndu notendur til að bæta við",
|
||||
"lists.list_members": "Meðlimir lista",
|
||||
"lists.list_members_count": "{count, plural, one {# meðlimur} other {# meðlimir}}",
|
||||
"lists.list_name": "Heiti lista",
|
||||
"lists.new_list_name": "Heiti á nýjum lista",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "Nascondi i membri in Home",
|
||||
"lists.exclusive_hint": "Se qualcuno è presente in questa lista, nascondilo nel tuo feed Home per evitare di vedere i suoi post due volte.",
|
||||
"lists.find_users_to_add": "Trova utenti da aggiungere",
|
||||
"lists.list_members": "Membri della lista",
|
||||
"lists.list_members_count": "{count, plural, one {# membro} other {# membri}}",
|
||||
"lists.list_name": "Nome della lista",
|
||||
"lists.new_list_name": "Nuovo nome della lista",
|
||||
|
||||
@@ -510,7 +510,6 @@
|
||||
"lists.exclusive": "メンバーをホームに表示しない",
|
||||
"lists.exclusive_hint": "リストにあるユーザーをホームタイムラインに表示しません。二重に表示させたくない場合に使用できます。",
|
||||
"lists.find_users_to_add": "追加するユーザーを探しましょう",
|
||||
"lists.list_members": "リストのメンバー",
|
||||
"lists.list_members_count": "{count, plural, other{#人のメンバー}}",
|
||||
"lists.list_name": "リスト名",
|
||||
"lists.new_list_name": "新しいリスト名",
|
||||
|
||||
@@ -513,7 +513,6 @@
|
||||
"lists.exclusive": "구성원을 홈에서 숨기기",
|
||||
"lists.exclusive_hint": "누군가가 이 리스트에 있으면 홈 피드에서는 숨겨 게시물을 두 번 보는 것을 방지합니다.",
|
||||
"lists.find_users_to_add": "추가할 사용자 검색",
|
||||
"lists.list_members": "리스트 구성원",
|
||||
"lists.list_members_count": "{count, plural, other {# 명}}",
|
||||
"lists.list_name": "리스트 이름",
|
||||
"lists.new_list_name": "새 리스트 이름",
|
||||
|
||||
@@ -504,7 +504,6 @@
|
||||
"lists.exclusive": "Slėpti narius pagrindiniame",
|
||||
"lists.exclusive_hint": "Jei kas nors yra šiame sąraše, paslėpkite juos pagrindinio srauto laiko skalėje, kad nematytumėte jų įrašus dukart.",
|
||||
"lists.find_users_to_add": "Raskite naudotojų, kurių pridėti",
|
||||
"lists.list_members": "Sąrašo nariai",
|
||||
"lists.list_members_count": "{count, plural, one {# narys} few {# nariai} many {# nario} other {# narių}}",
|
||||
"lists.list_name": "Sąrašo pavadinimas",
|
||||
"lists.new_list_name": "Naujas sąrašo pavadinimas",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "佇tshù ê時間線kā成員tshàng起來。",
|
||||
"lists.exclusive_hint": "Nā bóo-mi̍h口座佇tsit ê列單,ē tuì lí tshù ê時間線kā tsit ê口座tshàng起來,避免koh看見in ê PO文。",
|
||||
"lists.find_users_to_add": "Tshuē beh加添ê用者",
|
||||
"lists.list_members": "列單ê成員",
|
||||
"lists.list_members_count": "{count, plural, other {# 位成員}}",
|
||||
"lists.list_name": "列單ê名",
|
||||
"lists.new_list_name": "新ê列單ê名",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Leden op je Startpagina verbergen",
|
||||
"lists.exclusive_hint": "Als iemand op deze lijst staat, verberg deze persoon dan op je starttijdlijn om te voorkomen dat zijn berichten twee keer worden getoond.",
|
||||
"lists.find_users_to_add": "Vind gebruikers om toe te voegen",
|
||||
"lists.list_members": "Lijstleden",
|
||||
"lists.list_members_count": "{count, plural, one{# lid} other{# leden}}",
|
||||
"lists.list_name": "Lijstnaam",
|
||||
"lists.new_list_name": "Nieuwe lijstnaam",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "Gøym medlemer frå startskjermen",
|
||||
"lists.exclusive_hint": "Viss nokon er på denne lista, blir dei gøymde frå startskjermen slik at du slepp sjå innlegga deira to gonger.",
|
||||
"lists.find_users_to_add": "Finn brukarar å leggja til",
|
||||
"lists.list_members": "Syn medlemer",
|
||||
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemer}}",
|
||||
"lists.list_name": "Namn på lista",
|
||||
"lists.new_list_name": "Namn på den nye lista",
|
||||
|
||||
@@ -319,7 +319,6 @@
|
||||
"lists.done": "ਮੁਕੰਮਲ",
|
||||
"lists.edit": "ਸੂਚੀ ਨੂੰ ਸੋਧੋ",
|
||||
"lists.find_users_to_add": "ਜੋੜਨ ਲਈ ਵਰਤੋਂਕਾਰ ਲੱਭੋ",
|
||||
"lists.list_members": "ਮੈਂਬਰਾਂ ਦੀ ਸੂਚੀ",
|
||||
"lists.list_members_count": "{count, plural, one {# ਮੈਂਬਰ} other {# ਮੈਂਬਰ}}",
|
||||
"lists.list_name": "ਸੂਚੀ ਦਾ ਨਾਂ",
|
||||
"lists.new_list_name": "ਨਵੀਂ ਸੂਚੀਂ ਦਾ ਨਾਂ",
|
||||
|
||||
@@ -490,7 +490,6 @@
|
||||
"lists.exclusive": "Nie pokazuj w mojej osi czasu",
|
||||
"lists.exclusive_hint": "Wpisy osób znajdujących się na tej liście nie będą wyświetlane w twojej osi czasu, aby uniknąć duplikowania tych samych wpisów.",
|
||||
"lists.find_users_to_add": "Znajdź kogoś, aby dodać",
|
||||
"lists.list_members": "Lista osób",
|
||||
"lists.list_members_count": "{count, plural, one {# osoba} few {# osoby} many {# osób} other {# osób}}",
|
||||
"lists.list_name": "Nazwa listy",
|
||||
"lists.new_list_name": "Nazwa nowej listy",
|
||||
|
||||
@@ -491,7 +491,6 @@
|
||||
"lists.exclusive": "Ocultar membros no início",
|
||||
"lists.exclusive_hint": "Se existe alguém nesta lista, oculte-os no seu feed inicial para evitar ver suas publicações duas vezes.",
|
||||
"lists.find_users_to_add": "Encontrar usuários para adicionar",
|
||||
"lists.list_members": "Membros da lista",
|
||||
"lists.list_members_count": "{count, plural, one {# membro} other {# membros}}",
|
||||
"lists.list_name": "Nome da lista",
|
||||
"lists.new_list_name": "Nome novo da lista",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Ocultar membros na página inicial",
|
||||
"lists.exclusive_hint": "Se alguém estiver nesta lista, oculta-o na cronologia da tua página inicial para evitar veres as publicações dessa pessoa duas vezes.",
|
||||
"lists.find_users_to_add": "Encontrar utilizadores para adicionar",
|
||||
"lists.list_members": "Membros da lista",
|
||||
"lists.list_members_count": "{count, plural, one {# membro} other {# membros}}",
|
||||
"lists.list_name": "Nome da lista",
|
||||
"lists.new_list_name": "Nome da nova lista",
|
||||
|
||||
@@ -515,7 +515,6 @@
|
||||
"lists.exclusive": "Не показывать участников в домашней ленте",
|
||||
"lists.exclusive_hint": "Если кто-то есть в этом списке, скрыть его в домашней ленте, чтобы не видеть его посты дважды.",
|
||||
"lists.find_users_to_add": "Найти пользователей для добавления",
|
||||
"lists.list_members": "Пользователи в списке",
|
||||
"lists.list_members_count": "{count, plural, one {# пользователь} few {# пользователя} other {# пользователей}}",
|
||||
"lists.list_name": "Название списка",
|
||||
"lists.new_list_name": "Новый список",
|
||||
@@ -797,18 +796,18 @@
|
||||
"search.no_recent_searches": "Недавние запросы отсутствуют",
|
||||
"search.placeholder": "Поиск",
|
||||
"search.quick_action.account_search": "Профили, соответствующие {x}",
|
||||
"search.quick_action.go_to_account": "Перейти в профиль {x}",
|
||||
"search.quick_action.go_to_hashtag": "Перейти к хэштегу {x}",
|
||||
"search.quick_action.go_to_account": "Перейти к профилю {x}",
|
||||
"search.quick_action.go_to_hashtag": "Перейти к хештегу {x}",
|
||||
"search.quick_action.open_url": "Открыть URL в Mastodon",
|
||||
"search.quick_action.status_search": "Посты, соответствующие {x}",
|
||||
"search.search_or_paste": "Поиск (или вставьте URL)",
|
||||
"search_popout.full_text_search_disabled_message": "Недоступно на {domain}.",
|
||||
"search_popout.full_text_search_logged_out_message": "Доступно только при авторизации.",
|
||||
"search_popout.language_code": "Код языка по стандарту ISO",
|
||||
"search_popout.full_text_search_disabled_message": "Недоступно на сервере {domain}.",
|
||||
"search_popout.full_text_search_logged_out_message": "Доступно только авторизованным пользователям.",
|
||||
"search_popout.language_code": "ISO-код языка",
|
||||
"search_popout.options": "Параметры поиска",
|
||||
"search_popout.quick_actions": "Быстрые действия",
|
||||
"search_popout.recent": "Недавние запросы",
|
||||
"search_popout.specific_date": "конкретная дата",
|
||||
"search_popout.specific_date": "дата",
|
||||
"search_popout.user": "пользователь",
|
||||
"search_results.accounts": "Профили",
|
||||
"search_results.all": "Все",
|
||||
@@ -818,7 +817,7 @@
|
||||
"search_results.see_all": "Показать все",
|
||||
"search_results.statuses": "Посты",
|
||||
"search_results.title": "Поиск \"{q}\"",
|
||||
"server_banner.about_active_users": "Люди, заходившие на этот сервер за последние 30 дней (ежемесячные активные пользователи)",
|
||||
"server_banner.about_active_users": "Число зарегистрированных пользователей, заходивших на этот сервер за последние 30 дней (MAU-метрика)",
|
||||
"server_banner.active_users": "активные пользователи",
|
||||
"server_banner.administered_by": "Управляется:",
|
||||
"server_banner.is_one_of_many": "{domain} — это один из многих независимых серверов Mastodon, которые вы можете использовать, чтобы присоединиться к сети Fediverse.",
|
||||
@@ -827,7 +826,7 @@
|
||||
"sign_in_banner.follow_anyone": "Подписывайтесь на кого угодно в федивёрсе и читайте ленту в хронологическом порядке. Никаких алгоритмов, рекламы или кликбейта.",
|
||||
"sign_in_banner.mastodon_is": "Mastodon — лучший способ быть в курсе всего происходящего.",
|
||||
"sign_in_banner.sign_in": "Войти",
|
||||
"sign_in_banner.sso_redirect": "Войдите или Зарегистрируйтесь",
|
||||
"sign_in_banner.sso_redirect": "Вход/Регистрация",
|
||||
"status.admin_account": "Открыть интерфейс модератора для @{name}",
|
||||
"status.admin_domain": "Открыть интерфейс модератора для {domain}",
|
||||
"status.admin_status": "Открыть этот пост в интерфейсе модератора",
|
||||
@@ -846,45 +845,45 @@
|
||||
"status.edited_x_times": "{count, plural, one {{count} изменение} many {{count} изменений} other {{count} изменения}}",
|
||||
"status.embed": "Встроить на свой сайт",
|
||||
"status.favourite": "Добавить в избранное",
|
||||
"status.favourites": "{count, plural, other {в избранном}}",
|
||||
"status.favourites": "{count, plural, one {звёздочка} few {звёздочки} other {звёздочек}}",
|
||||
"status.filter": "Фильтровать этот пост",
|
||||
"status.history.created": "{name} создал(а) {date}",
|
||||
"status.history.edited": "{name} отредактировал(а) {date}",
|
||||
"status.load_more": "Загрузить остальное",
|
||||
"status.load_more": "Загрузить ещё",
|
||||
"status.media.open": "Нажмите, чтобы открыть.",
|
||||
"status.media.show": "Нажмите для просмотра",
|
||||
"status.media_hidden": "Файл скрыт",
|
||||
"status.media.show": "Нажмите, чтобы показать",
|
||||
"status.media_hidden": "Вложения скрыты",
|
||||
"status.mention": "Упомянуть @{name}",
|
||||
"status.more": "Ещё",
|
||||
"status.mute": "Игнорировать @{name}",
|
||||
"status.mute_conversation": "Игнорировать обсуждение",
|
||||
"status.open": "Открыть пост",
|
||||
"status.pin": "Рекомендовать в профиле",
|
||||
"status.read_more": "Ещё",
|
||||
"status.pin": "Закрепить в профиле",
|
||||
"status.read_more": "Читать далее",
|
||||
"status.reblog": "Продвинуть",
|
||||
"status.reblog_private": "Продвинуть для своей аудитории",
|
||||
"status.reblogged_by": "{name} продвинул(а)",
|
||||
"status.reblogs": "{count, plural, one {продвижение} few {продвижения} other {продвижений}}",
|
||||
"status.reblogs.empty": "Никто ещё не продвинул этот пост. Как только кто-то это сделает, они появятся здесь.",
|
||||
"status.redraft": "Создать заново",
|
||||
"status.reblogs.empty": "Никто ещё не продвинул этот пост. Все пользователи, продвинувшие этот пост, будут показаны здесь.",
|
||||
"status.redraft": "Удалить и исправить",
|
||||
"status.remove_bookmark": "Убрать из закладок",
|
||||
"status.remove_favourite": "Убрать из избранного",
|
||||
"status.replied_in_thread": "Ответил(а) в треде",
|
||||
"status.replied_in_thread": "Ответил(а) в обсуждении",
|
||||
"status.replied_to": "Ответил(а) {name}",
|
||||
"status.reply": "Ответить",
|
||||
"status.replyAll": "Ответить всем",
|
||||
"status.replyAll": "Ответить в обсуждении",
|
||||
"status.report": "Пожаловаться на @{name}",
|
||||
"status.sensitive_warning": "Содержимое «деликатного характера»",
|
||||
"status.sensitive_warning": "Медиа деликатного содержания",
|
||||
"status.share": "Поделиться",
|
||||
"status.show_less_all": "Свернуть все спойлеры в ветке",
|
||||
"status.show_more_all": "Развернуть все спойлеры в ветке",
|
||||
"status.show_original": "Показать оригинал",
|
||||
"status.title.with_attachments": "{user} опубликовал {attachmentCount, plural, one {{attachmentCount} вложение} few {{attachmentCount} вложения} other {{attachmentCount} вложений}}",
|
||||
"status.title.with_attachments": "{user} опубликовал(а) {attachmentCount, plural, one {{attachmentCount} вложение} few {{attachmentCount} вложения} other {{attachmentCount} вложений}}",
|
||||
"status.translate": "Перевод",
|
||||
"status.translated_from_with": "Переведено с {lang} с помощью {provider}",
|
||||
"status.uncached_media_warning": "Предварительный просмотр недоступен",
|
||||
"status.unmute_conversation": "Не игнорировать обсуждение",
|
||||
"status.unpin": "Не рекомендовать в профиле",
|
||||
"status.unpin": "Открепить от профиля",
|
||||
"subscribed_languages.lead": "Посты лишь на выбранных языках будут появляться в вашей домашней ленте и в списках после изменения. Снимите выбор, чтобы получать посты на всех языках.",
|
||||
"subscribed_languages.save": "Сохранить изменения",
|
||||
"subscribed_languages.target": "Изменить языки подписки для {target}",
|
||||
@@ -906,7 +905,7 @@
|
||||
"units.short.thousand": "{count} тыс.",
|
||||
"upload_area.title": "Перетащите сюда, чтобы загрузить",
|
||||
"upload_button.label": "Прикрепить фото, видео или аудио",
|
||||
"upload_error.limit": "Достигнут лимит загруженных файлов.",
|
||||
"upload_error.limit": "Превышено максимальное количество вложений.",
|
||||
"upload_error.poll": "К опросам нельзя прикреплять файлы.",
|
||||
"upload_form.drag_and_drop.instructions": "Чтобы выбрать вложение, нажмите \"Пробел\" (Space) или \"Ввод\" (Enter). Используйте клавиши со стрелками, чтобы передвинуть вложение в любом направлении. Нажмите \"Пробел\" (Space) или \"Ввод\" (Enter) ещё раз, чтобы переместить вложение на новое место, либо нажмите кнопку \"Выйти\" (Escape), чтобы отменить перемещение.",
|
||||
"upload_form.drag_and_drop.on_drag_cancel": "Перемещение отменено. Вложение {item} было оставлено на прежнем месте.",
|
||||
|
||||
@@ -461,7 +461,6 @@
|
||||
"lists.exclusive": "Skryť členov na Domovskej osi",
|
||||
"lists.exclusive_hint": "Ak je niekto na tomto zozname, skry ich na tvojej Domácej osi, aby si ich príspevky nevidel/a dvakrát.",
|
||||
"lists.find_users_to_add": "Nájdi užívateľov na pridanie",
|
||||
"lists.list_members": "Členovia zoznamu",
|
||||
"lists.list_name": "Názov zoznamu",
|
||||
"lists.new_list_name": "Názov nového zoznamu",
|
||||
"lists.no_lists_yet": "Ešte žiadne zoznamy.",
|
||||
|
||||
@@ -490,7 +490,6 @@
|
||||
"lists.exclusive": "Skrij člane v domovanju",
|
||||
"lists.exclusive_hint": "Objave vseh, ki so na tem seznamu, se ne pokažejo v vašem domačem viru. Tako se izognete podvojenim objavam.",
|
||||
"lists.find_users_to_add": "Poišči člane za dodajanje",
|
||||
"lists.list_members": "Člani seznama",
|
||||
"lists.list_members_count": "{count, plural, one {# član} two {# člana} few {# člani} other {# članov}}",
|
||||
"lists.list_name": "Ime seznama",
|
||||
"lists.new_list_name": "Novo ime seznama",
|
||||
|
||||
@@ -513,7 +513,6 @@
|
||||
"lists.exclusive": "Fshihni anëtarët në Krye",
|
||||
"lists.exclusive_hint": "Nëse dikush gjendje në këtë listë, fshihini ata te prurja juaj e Kreut, që të shmangni parjen dy herë të postimeve të tyre.",
|
||||
"lists.find_users_to_add": "Gjeni përdorues për t’i shtuar",
|
||||
"lists.list_members": "Shfaq anëtarë",
|
||||
"lists.list_members_count": "{count, plural, one {# anëtar} other {# anëtarë}}",
|
||||
"lists.list_name": "Emër liste",
|
||||
"lists.new_list_name": "Emër liste të re",
|
||||
|
||||
@@ -491,7 +491,6 @@
|
||||
"lists.exclusive": "Dölj medlemmar i Hem flödet",
|
||||
"lists.exclusive_hint": "Om någon är med på den här listan, göm dem i ditt Hemtidlinje för att undvika att se deras inlägg två gånger.",
|
||||
"lists.find_users_to_add": "Hitta användare att lägga till",
|
||||
"lists.list_members": "Lista medlemmar",
|
||||
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmar}}",
|
||||
"lists.list_name": "Listnamn",
|
||||
"lists.new_list_name": "Nytt listnamn",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"account.copy": "คัดลอกลิงก์ไปยังโปรไฟล์",
|
||||
"account.direct": "กล่าวถึง @{name} แบบส่วนตัว",
|
||||
"account.disable_notifications": "หยุดแจ้งเตือนฉันเมื่อ @{name} โพสต์",
|
||||
"account.domain_blocking": "โดเมน",
|
||||
"account.edit_profile": "แก้ไขโปรไฟล์",
|
||||
"account.enable_notifications": "แจ้งเตือนฉันเมื่อ @{name} โพสต์",
|
||||
"account.endorse": "แสดงในโปรไฟล์",
|
||||
@@ -483,7 +484,6 @@
|
||||
"lists.exclusive": "ซ่อนสมาชิกในหน้าแรก",
|
||||
"lists.exclusive_hint": "หากใครสักคนอยู่ในรายการนี้ ให้ซ่อนเขาในฟีดหน้าแรกของคุณเพื่อหลีกเลี่ยงการเห็นโพสต์ของเขาสองครั้ง",
|
||||
"lists.find_users_to_add": "ค้นหาผู้ใช้ที่จะเพิ่ม",
|
||||
"lists.list_members": "สมาชิกของรายการ",
|
||||
"lists.list_members_count": "{count, plural, other {# สมาชิก}}",
|
||||
"lists.list_name": "ชื่อรายการ",
|
||||
"lists.new_list_name": "ชื่อรายการใหม่",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Anasayfada üyeleri gizle",
|
||||
"lists.exclusive_hint": "Birisi bu listede yer alıyorsa, gönderilerini iki kez görmekten kaçınmak için onu anasayfa akışınızda gizleyin.",
|
||||
"lists.find_users_to_add": "Eklenecek kullanıcıları bul",
|
||||
"lists.list_members": "Liste üyeleri",
|
||||
"lists.list_members_count": "{count, plural, one {# üye} other {# üye}}",
|
||||
"lists.list_name": "Liste adı",
|
||||
"lists.new_list_name": "Yeni liste adı",
|
||||
|
||||
@@ -500,7 +500,6 @@
|
||||
"lists.exclusive": "Сховати учасників на головній сторінці",
|
||||
"lists.exclusive_hint": "Якщо хтось є у цьому списку, сховайте їх на своїй домашній сторінці, щоб не бачити їхні дописи двічі.",
|
||||
"lists.find_users_to_add": "Знайти користувачів, щоб додати їх",
|
||||
"lists.list_members": "Учасники списку",
|
||||
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
|
||||
"lists.list_name": "Назва списку",
|
||||
"lists.new_list_name": "Нова назва списку",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "Ẩn thành viên trong Trang chủ",
|
||||
"lists.exclusive_hint": "Nếu ai đó có trong danh sách này, ẩn họ trong Trang chủ để tránh thấy tút của họ hiện trùng lặp.",
|
||||
"lists.find_users_to_add": "Tìm người để thêm vào",
|
||||
"lists.list_members": "Liệt kê các thành viên",
|
||||
"lists.list_members_count": "{count, plural, other {# thành viên}}",
|
||||
"lists.list_name": "Tên danh sách",
|
||||
"lists.new_list_name": "Tên danh sách mới",
|
||||
|
||||
@@ -507,7 +507,6 @@
|
||||
"lists.exclusive": "在主页动态中隐藏列表成员",
|
||||
"lists.exclusive_hint": "列表成员的嘟文将不会在你的主页动态中显示,以免重复阅读。",
|
||||
"lists.find_users_to_add": "查找要添加的用户",
|
||||
"lists.list_members": "列表成员",
|
||||
"lists.list_members_count": "{count, plural, other {# 人}}",
|
||||
"lists.list_name": "列表名称",
|
||||
"lists.new_list_name": "新列表名称",
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
"lists.exclusive": "於首頁隱藏成員",
|
||||
"lists.exclusive_hint": "如果某個帳號於此列表中,將自您的首頁時間軸中隱藏此帳號,以防重複見到他們的嘟文。",
|
||||
"lists.find_users_to_add": "尋找欲新增之使用者",
|
||||
"lists.list_members": "列表成員",
|
||||
"lists.list_members_count": "{count, plural, other {# 個成員}}",
|
||||
"lists.list_name": "列表名稱",
|
||||
"lists.new_list_name": "新列表名稱",
|
||||
|
||||
@@ -2091,6 +2091,7 @@ body > [data-popper-placement] {
|
||||
display: block;
|
||||
position: relative;
|
||||
border-radius: var(--avatar-border-radius);
|
||||
background: var(--surface-background-color);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@@ -2178,11 +2179,19 @@ a .account__avatar {
|
||||
flex-wrap: nowrap;
|
||||
|
||||
& > :not(:first-child) {
|
||||
margin-inline-start: -8px;
|
||||
margin-inline-start: -12px;
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
box-shadow: 0 0 0 2px var(--background-color);
|
||||
}
|
||||
& > :first-child {
|
||||
transform: rotate(-4deg);
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
box-shadow: 0 0 0 2px var(--background-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8143,16 +8152,13 @@ noscript {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-block-end: 16px;
|
||||
margin-block: 16px;
|
||||
color: $darker-text-color;
|
||||
|
||||
a:any-link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,34 +1440,12 @@ code {
|
||||
display: block;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-pile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 2px solid var(--background-color);
|
||||
background: var(--surface-background-color);
|
||||
margin-inline-end: -16px;
|
||||
transform: rotate(0);
|
||||
|
||||
&:first-child {
|
||||
transform: rotate(-4deg);
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-inline-end: 0;
|
||||
|
||||
.icon {
|
||||
vertical-align: -5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1836,6 +1836,10 @@ ca:
|
||||
limit: Ja has fixat el màxim nombre de tuts
|
||||
ownership: No es pot fixar el tut d'algú altre
|
||||
reblog: No es pot fixar un impuls
|
||||
quote_policies:
|
||||
followers: Seguidors i usuaris mencionats
|
||||
nobody: Només usuaris mencionats
|
||||
public: Tothom
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Directe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
lt:
|
||||
about:
|
||||
about_mastodon_html: 'Ateities socialinis tinklas: jokių reklamų, jokių įmonių sekimo, etiškas dizainas ir decentralizacija! Turėk savo duomenis su Mastodon.'
|
||||
about_mastodon_html: 'Ateities socialinis tinklas: jokių reklamų ir įmonių sekimo, etiškas dizainas bei decentralizacija! Turėkite savo duomenis su „Mastodon“.'
|
||||
contact_missing: Nenustatyta
|
||||
contact_unavailable: Nėra
|
||||
hosted_on: "„Mastodon“ talpinamas domene %{domain}"
|
||||
|
||||
@@ -56,6 +56,7 @@ bg:
|
||||
scopes: Указва до кои API има достъп приложението. Ако изберете диапазон от най-високо ниво, няма нужда да избирате индивидуални.
|
||||
setting_aggregate_reblogs: Без показване на нови подсилвания за публикации, които са неотдавна подсилени (засяга само новополучени подсилвания)
|
||||
setting_always_send_emails: Обикновено известията по имейл няма да са изпратени при дейна употреба на Mastodon
|
||||
setting_default_quote_policy: Споменатите потребители винаги им е позволено да цитират. Тази настройка ще се отрази за публикациите, създадени със следващата версия на Mastodon, но може да изберете предпочитанията си в подготовката
|
||||
setting_default_sensitive: Деликатната мултимедия е скрита по подразбиране и може да се разкрие с едно щракване
|
||||
setting_display_media_default: Скриване на мултимедия отбелязана като деликатна
|
||||
setting_display_media_hide_all: Винаги скриване на мултимедията
|
||||
@@ -147,6 +148,9 @@ bg:
|
||||
min_age: Не трябва да е под изискваната минимална възраст от закона на юрисдикцията ви.
|
||||
user:
|
||||
chosen_languages: Само публикации на отметнатите езици ще се показват в публичните часови оси
|
||||
date_of_birth:
|
||||
one: Трябва да се уверим, че сте поне на %{count}, за да употребявате Mastodon. Няма да съхраняваме това.
|
||||
other: Трябва да се уверим, че сте поне на %{count}, за да употребявате Mastodon. Няма да съхраняваме това.
|
||||
role: Ролята управлява какви позволения има потребителят.
|
||||
user_role:
|
||||
color: Цветът, използван за ролите в потребителския интерфейс, като RGB в шестнадесетичен формат
|
||||
@@ -227,6 +231,7 @@ bg:
|
||||
setting_boost_modal: Показване на прозорец за потвърждение преди подсилване
|
||||
setting_default_language: Език на публикуване
|
||||
setting_default_privacy: Поверителност на публикуване
|
||||
setting_default_quote_policy: Кой може да цитира
|
||||
setting_default_sensitive: Все да се бележи мултимедията като деликатна
|
||||
setting_delete_modal: Показване на прозорче за потвърждение преди изтриване на публикация
|
||||
setting_disable_hover_cards: Изключване на прегледа на профила, премествайки показалеца отгоре
|
||||
|
||||
@@ -56,6 +56,7 @@ ca:
|
||||
scopes: API permeses per a accedir a l'aplicació. Si selecciones un àmbit de nivell superior, no cal que en seleccionis un d'individual.
|
||||
setting_aggregate_reblogs: No mostra els nous impulsos dels tuts que ja s'han impulsat recentment (només afecta als impulsos nous rebuts)
|
||||
setting_always_send_emails: Normalment, no s'enviarà cap notificació per correu electrònic mentre facis servir Mastodon
|
||||
setting_default_quote_policy: Els usuaris mencionats sempre poden citar. Aquesta configuració només tindrà efecte en les publicacions creades amb la següent versió de Mastodon, però podeu seleccionar-ho en preparació
|
||||
setting_default_sensitive: El contingut sensible està ocult per defecte i es pot mostrar fent-hi clic
|
||||
setting_display_media_default: Amaga el contingut gràfic marcat com a sensible
|
||||
setting_display_media_hide_all: Oculta sempre tot el contingut multimèdia
|
||||
@@ -145,6 +146,9 @@ ca:
|
||||
min_age: No hauria de ser inferior a l'edat mínima exigida per la llei de la vostra jurisdicció.
|
||||
user:
|
||||
chosen_languages: Quan estigui marcat, només es mostraran els tuts de les llengües seleccionades en les línies de temps públiques
|
||||
date_of_birth:
|
||||
one: Ens hem d'assegurar que teniu com a mínim %{count} any per a fer servir Mastodon. No ho desarem.
|
||||
other: Ens hem d'assegurar que teniu com a mínim %{count} anys per a fer servir Mastodon. No ho desarem.
|
||||
role: El rol controla quins permisos té l'usuari.
|
||||
user_role:
|
||||
color: Color que s'usarà per al rol a tota la interfície d'usuari, com a RGB en format hexadecimal
|
||||
@@ -225,6 +229,7 @@ ca:
|
||||
setting_boost_modal: Mostra la finestra de confirmació abans d'impulsar
|
||||
setting_default_language: Llengua dels tuts
|
||||
setting_default_privacy: Privacitat dels tuts
|
||||
setting_default_quote_policy: Qui pot citar
|
||||
setting_default_sensitive: Marcar sempre el contingut gràfic com a sensible
|
||||
setting_delete_modal: Mostra la finestra de confirmació abans d'esborrar un tut
|
||||
setting_disable_hover_cards: Deshabilita la vista prèvia del perfil en passar-hi per sobre
|
||||
|
||||
@@ -56,6 +56,7 @@ gl:
|
||||
scopes: A que APIs terá acceso a aplicación. Se escolles un ámbito de alto nivel, non precisas seleccionar elementos individuais.
|
||||
setting_aggregate_reblogs: Non mostrar novas promocións de publicacións que foron promovidas recentemente (só afecta a promocións recén recibidas)
|
||||
setting_always_send_emails: Como norma xeral non che enviamos correos electrónicos se usas activamente Mastodon
|
||||
setting_default_quote_policy: As usuarias mencionadas sempre teñen permiso para citar. Este axuste só ten efecto para publicacións creadas coa próxima versión de Mastodon, pero xa podes ir preparando o axuste.
|
||||
setting_default_sensitive: Medios sensibles marcados como ocultos por defecto e móstranse cun click
|
||||
setting_display_media_default: Ocultar medios marcados como sensibles
|
||||
setting_display_media_hide_all: Ocultar sempre os medios
|
||||
@@ -148,6 +149,9 @@ gl:
|
||||
min_age: Non debería ser inferior á idade mínima requerida polas leis da túa xurisdición.
|
||||
user:
|
||||
chosen_languages: Se ten marca, só as publicacións nos idiomas seleccionados serán mostrados en cronoloxías públicas
|
||||
date_of_birth:
|
||||
one: Temos que confirmar que tes %{count} anos polo menos para usar Mastodon. Non gardamos este dato.
|
||||
other: Temos que confirmar que tes %{count} anos polo menos para usar Mastodon. Non gardamos este dato.
|
||||
role: Os roles establecen os permisos que ten a usuaria.
|
||||
user_role:
|
||||
color: Cor que se usará para o rol a través da IU, como RGB en formato hex
|
||||
@@ -228,6 +232,7 @@ gl:
|
||||
setting_boost_modal: Solicitar confirmación antes de promover
|
||||
setting_default_language: Idioma de publicación
|
||||
setting_default_privacy: Privacidade da publicación
|
||||
setting_default_quote_policy: Quen pode citar
|
||||
setting_default_sensitive: Marcar sempre multimedia como sensible
|
||||
setting_delete_modal: Solicitar confirmación antes de eliminar unha publicación
|
||||
setting_disable_hover_cards: Desactivar vista previa do perfil ao poñerse enriba
|
||||
|
||||
@@ -56,6 +56,7 @@ tr:
|
||||
scopes: Uygulamanın erişmesine izin verilen API'ler. Üst seviye bir kapsam seçtiyseniz, bireysel kapsam seçmenize gerek yoktur.
|
||||
setting_aggregate_reblogs: Yakın zamanda teşvik edilmiş gönderiler için yeni teşvikleri göstermeyin (yalnızca yeni alınan teşvikleri etkiler)
|
||||
setting_always_send_emails: Normalde, Mastodon'u aktif olarak kullanırken e-posta bildirimleri gönderilmeyecektir
|
||||
setting_default_quote_policy: Bahsedilen kullanıcıların her zaman alıntı yapmasına izin verilir. Bu ayar yalnızca bir sonraki Mastodon sürümü ile oluşturulan gönderiler için geçerli olacaktır, ancak tercihinizi hazırlık aşamasında seçebilirsiniz
|
||||
setting_default_sensitive: Hassas medya varsayılan olarak gizlidir ve bir tıklama ile gösterilebilir
|
||||
setting_display_media_default: Hassas olarak işaretlenmiş medyayı gizle
|
||||
setting_display_media_hide_all: Medyayı her zaman gizle
|
||||
@@ -228,6 +229,7 @@ tr:
|
||||
setting_boost_modal: Paylaşmadan önce onay iletişim kutusu göster
|
||||
setting_default_language: Gönderi dili
|
||||
setting_default_privacy: Gönderi gizliliği
|
||||
setting_default_quote_policy: Kimler alıntılayabilir
|
||||
setting_default_sensitive: Medyayı her zaman hassas olarak işaretle
|
||||
setting_delete_modal: Bir gönderiyi silmeden önce onay iletişim kutusu göster
|
||||
setting_disable_hover_cards: Üstüne geldiğinde profil önizlemesini devre dışı bırak
|
||||
|
||||
@@ -1858,6 +1858,10 @@ tr:
|
||||
limit: Halihazırda maksimum sayıda gönderi sabitlediniz
|
||||
ownership: Başkasının gönderisi sabitlenemez
|
||||
reblog: Bir gönderi sabitlenemez
|
||||
quote_policies:
|
||||
followers: Takipçiler ve bahsedilen kullanıcılar
|
||||
nobody: Sadece bahsedilen kullanıcılar
|
||||
public: Herkes
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Doğrudan
|
||||
|
||||
@@ -90,6 +90,7 @@ development environment configured with the software needed for this project.
|
||||
- Once you have successfully set up a development environment, it will be available on http://localhost:3000
|
||||
- Log in as the default admin user with the username `admin@mastodon.local` and the password `mastodonadmin`.
|
||||
- Check out the [Mastodon docs] for tips on working with emails in development (you'll need this when creating new user accounts) as well as a list of useful commands for testing and updating your dev instance.
|
||||
- You can optionally populate your database with sample data by running `bin/rails dev:populate_sample_data`. This will create a `@showcase_account` account with various types of contents.
|
||||
|
||||
[codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json
|
||||
[CONTRIBUTING]: ../CONTRIBUTING.md
|
||||
|
||||
354
lib/tasks/dev.rake
Normal file
354
lib/tasks/dev.rake
Normal file
@@ -0,0 +1,354 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
namespace :dev do
|
||||
desc 'Populate database with test data. Can be run multiple times. Should not be run in production environments'
|
||||
task populate_sample_data: :environment do
|
||||
# Create a valid account to showcase multiple post types
|
||||
showcase_account = Account.create_with(username: 'showcase_account').find_or_create_by!(id: 10_000_000)
|
||||
showcase_user = User.create_with(
|
||||
account_id: showcase_account.id,
|
||||
agreement: true,
|
||||
password: SecureRandom.hex,
|
||||
email: ENV.fetch('TEST_DATA_SHOWCASE_EMAIL', 'showcase_account@joinmastodon.org'),
|
||||
confirmed_at: Time.now.utc,
|
||||
approved: true
|
||||
).find_or_create_by!(id: 10_000_000)
|
||||
showcase_user.mark_email_as_confirmed!
|
||||
showcase_user.approve!
|
||||
|
||||
french_post = Status.create_with(
|
||||
text: 'Ceci est un sondage public écrit en Français',
|
||||
language: 'fr',
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
poll_attributes: {
|
||||
voters_count: 0,
|
||||
account: showcase_account,
|
||||
expires_at: 1.day.from_now,
|
||||
options: ['ceci est un choix', 'ceci est un autre choix'],
|
||||
multiple: false,
|
||||
}
|
||||
).find_or_create_by!(id: 10_000_000)
|
||||
|
||||
private_mentionless = Status.create_with(
|
||||
text: 'This is a private message written in English',
|
||||
language: 'en',
|
||||
account: showcase_account,
|
||||
visibility: :private
|
||||
).find_or_create_by!(id: 10_000_001)
|
||||
|
||||
public_self_reply_with_cw = Status.create_with(
|
||||
text: 'This is a public self-reply written in English; it has a CW and a multi-choice poll',
|
||||
spoiler_text: 'poll (CW example)',
|
||||
language: 'en',
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
thread: french_post,
|
||||
poll_attributes: {
|
||||
voters_count: 0,
|
||||
account: showcase_account,
|
||||
expires_at: 1.day.from_now,
|
||||
options: ['this is a choice', 'this is another choice', 'you can chose any number of them'],
|
||||
multiple: true,
|
||||
}
|
||||
).find_or_create_by!(id: 10_000_002)
|
||||
ProcessHashtagsService.new.call(public_self_reply_with_cw)
|
||||
|
||||
unlisted_self_reply_with_cw_tag_mention = Status.create_with(
|
||||
text: 'This is an unlisted (Quiet Public) self-reply written in #English; it has a CW, mentions @showcase_account, and uses an emoji 🦣',
|
||||
spoiler_text: 'CW example',
|
||||
language: 'en',
|
||||
account: showcase_account,
|
||||
visibility: :unlisted,
|
||||
thread: public_self_reply_with_cw
|
||||
).find_or_create_by!(id: 10_000_003)
|
||||
Mention.find_or_create_by!(status: unlisted_self_reply_with_cw_tag_mention, account: showcase_account)
|
||||
ProcessHashtagsService.new.call(unlisted_self_reply_with_cw_tag_mention)
|
||||
|
||||
media_attachment = MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/600x400.png'),
|
||||
description: 'Mastodon logo'
|
||||
).find_or_create_by!(id: 10_000_000)
|
||||
status_with_media = Status.create_with(
|
||||
text: "This is a public status with a picture and tags. The attached picture has an alt text\n\n#Mastodon #Logo #English #Test",
|
||||
ordered_media_attachment_ids: [media_attachment.id],
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_004)
|
||||
media_attachment.update(status_id: status_with_media.id)
|
||||
ProcessHashtagsService.new.call(status_with_media)
|
||||
|
||||
media_attachment = MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/600x400.png'),
|
||||
description: 'Mastodon logo'
|
||||
).find_or_create_by!(id: 10_000_001)
|
||||
status_with_sensitive_media = Status.create_with(
|
||||
text: "This is the same public status with a picture and tags, but it is marked as sensitive. The attached picture has an alt text\n\n#Mastodon #Logo #English #Test",
|
||||
ordered_media_attachment_ids: [media_attachment.id],
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
sensitive: true,
|
||||
thread: status_with_media
|
||||
).find_or_create_by!(id: 10_000_005)
|
||||
media_attachment.update(status_id: status_with_sensitive_media.id)
|
||||
ProcessHashtagsService.new.call(status_with_sensitive_media)
|
||||
|
||||
media_attachment = MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/600x400.png'),
|
||||
description: 'Mastodon logo'
|
||||
).find_or_create_by!(id: 10_000_002)
|
||||
status_with_cw_media = Status.create_with(
|
||||
text: "This is the same public status with a picture and tags, but it is behind a CW. The attached picture has an alt text\n\n#Mastodon #Logo #English #Test",
|
||||
spoiler_text: 'Mastodon logo',
|
||||
ordered_media_attachment_ids: [media_attachment.id],
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
sensitive: true,
|
||||
thread: status_with_sensitive_media
|
||||
).find_or_create_by!(id: 10_000_006)
|
||||
media_attachment.update(status_id: status_with_cw_media.id)
|
||||
ProcessHashtagsService.new.call(status_with_cw_media)
|
||||
|
||||
media_attachment = MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/boop.ogg'),
|
||||
description: 'Mastodon boop'
|
||||
).find_or_create_by!(id: 10_000_003)
|
||||
status_with_audio = Status.create_with(
|
||||
text: "This is the same public status with an audio file and tags. The attached picture has an alt text\n\n#Mastodon #English #Test",
|
||||
ordered_media_attachment_ids: [media_attachment.id],
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
thread: status_with_cw_media
|
||||
).find_or_create_by!(id: 10_000_007)
|
||||
media_attachment.update(status_id: status_with_audio.id)
|
||||
ProcessHashtagsService.new.call(status_with_audio)
|
||||
|
||||
media_attachment = MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/boop.ogg'),
|
||||
description: 'Mastodon boop'
|
||||
).find_or_create_by!(id: 10_000_004)
|
||||
status_with_sensitive_audio = Status.create_with(
|
||||
text: "This is the same public status with an audio file and tags, but it is marked as sensitive. The attached picture has an alt text\n\n#Mastodon #English #Test",
|
||||
ordered_media_attachment_ids: [media_attachment.id],
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
sensitive: true,
|
||||
thread: status_with_audio
|
||||
).find_or_create_by!(id: 10_000_008)
|
||||
media_attachment.update(status_id: status_with_sensitive_audio.id)
|
||||
ProcessHashtagsService.new.call(status_with_sensitive_audio)
|
||||
|
||||
media_attachment = MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/boop.ogg'),
|
||||
description: 'Mastodon boop'
|
||||
).find_or_create_by!(id: 10_000_005)
|
||||
status_with_cw_audio = Status.create_with(
|
||||
text: "This is the same public status with an audio file and tags, but it is behind a CW. The attached picture has an alt text\n\n#Mastodon #English #Test",
|
||||
spoiler_text: 'Mastodon boop',
|
||||
ordered_media_attachment_ids: [media_attachment.id],
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
sensitive: true,
|
||||
thread: status_with_sensitive_audio
|
||||
).find_or_create_by!(id: 10_000_009)
|
||||
media_attachment.update(status_id: status_with_cw_audio.id)
|
||||
ProcessHashtagsService.new.call(status_with_cw_audio)
|
||||
|
||||
media_attachments = [
|
||||
MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/600x400.png'),
|
||||
description: 'Mastodon logo'
|
||||
).find_or_create_by!(id: 10_000_006),
|
||||
MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/attachment.jpg')
|
||||
).find_or_create_by!(id: 10_000_007),
|
||||
MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/avatar-high.gif'),
|
||||
description: 'Walking cartoon cat'
|
||||
).find_or_create_by!(id: 10_000_008),
|
||||
MediaAttachment.create_with(
|
||||
account: showcase_account,
|
||||
file: File.open('spec/fixtures/files/text.png'),
|
||||
description: 'Text saying “Hello Mastodon”'
|
||||
).find_or_create_by!(id: 10_000_009),
|
||||
]
|
||||
status_with_multiple_attachments = Status.create_with(
|
||||
text: "This is a post with multiple attachments, not all of which have a description\n\n#Mastodon #English #Test",
|
||||
spoiler_text: 'multiple attachments',
|
||||
ordered_media_attachment_ids: media_attachments.pluck(:id),
|
||||
account: showcase_account,
|
||||
visibility: :public,
|
||||
sensitive: true,
|
||||
thread: status_with_cw_audio
|
||||
).find_or_create_by!(id: 10_000_010)
|
||||
media_attachments.each { |attachment| attachment.update!(status_id: status_with_multiple_attachments.id) }
|
||||
ProcessHashtagsService.new.call(status_with_multiple_attachments)
|
||||
|
||||
remote_account = Account.create_with(
|
||||
username: 'fake.example',
|
||||
domain: 'example.org',
|
||||
uri: 'https://example.org/foo/bar',
|
||||
url: 'https://example.org/foo/bar',
|
||||
locked: true
|
||||
).find_or_create_by!(id: 10_000_001)
|
||||
|
||||
remote_formatted_post = Status.create_with(
|
||||
text: <<~HTML,
|
||||
<p>This is a post with a variety of HTML in it</p>
|
||||
<p>For instance, <strong>this text is bold</strong> and <b>this one as well</b>, while <del>this text is stricken through</del> and <s>this one as well</s>.</p>
|
||||
<blockquote>
|
||||
<p>This thing, here, is a block quote<br/>with some <strong>bold</strong> as well</p>
|
||||
<ul>
|
||||
<li>a list item</li>
|
||||
<li>
|
||||
and another with
|
||||
<ul>
|
||||
<li>nested</li>
|
||||
<li>items!</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<pre><code>// And this is some code
|
||||
// with two lines of comments
|
||||
</code></pre>
|
||||
<p>And this is <code>inline</code> code</p>
|
||||
<p>Finally, please observe this Ruby element: <ruby> 明日 <rp>(</rp><rt>Ashita</rt><rp>)</rp> </ruby></p>
|
||||
HTML
|
||||
account: remote_account,
|
||||
uri: 'https://example.org/foo/bar/baz',
|
||||
url: 'https://example.org/foo/bar/baz'
|
||||
).find_or_create_by!(id: 10_000_011)
|
||||
Status.create_with(account: showcase_account, reblog: remote_formatted_post).find_or_create_by!(id: 10_000_012)
|
||||
|
||||
unattached_quote_post = Status.create_with(
|
||||
text: 'This is a quote of a post that does not exist',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_013)
|
||||
Quote.create_with(
|
||||
status: unattached_quote_post,
|
||||
quoted_status: nil
|
||||
).find_or_create_by!(id: 10_000_000)
|
||||
|
||||
self_quote = Status.create_with(
|
||||
text: 'This is a quote of a public self-post',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_014)
|
||||
Quote.create_with(
|
||||
status: self_quote,
|
||||
quoted_status: status_with_media,
|
||||
state: :accepted
|
||||
).find_or_create_by!(id: 10_000_001)
|
||||
|
||||
nested_self_quote = Status.create_with(
|
||||
text: 'This is a quote of a public self-post which itself is a self-quote',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_015)
|
||||
Quote.create_with(
|
||||
status: nested_self_quote,
|
||||
quoted_status: self_quote,
|
||||
state: :accepted
|
||||
).find_or_create_by!(id: 10_000_002)
|
||||
|
||||
recursive_self_quote = Status.create_with(
|
||||
text: 'This is a recursive self-quote; no real reason for it to exist, but just to make sure we handle them gracefuly',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_016)
|
||||
Quote.create_with(
|
||||
status: recursive_self_quote,
|
||||
quoted_status: recursive_self_quote,
|
||||
state: :accepted
|
||||
).find_or_create_by!(id: 10_000_003)
|
||||
|
||||
self_private_quote = Status.create_with(
|
||||
text: 'This is a public post of a private self-post: the quoted post should not be visible to non-followers',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_017)
|
||||
Quote.create_with(
|
||||
status: self_private_quote,
|
||||
quoted_status: private_mentionless,
|
||||
state: :accepted
|
||||
).find_or_create_by!(id: 10_000_004)
|
||||
|
||||
uncwed_quote_cwed = Status.create_with(
|
||||
text: 'This is a quote without CW of a quoted post that has a CW',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_018)
|
||||
Quote.create_with(
|
||||
status: uncwed_quote_cwed,
|
||||
quoted_status: public_self_reply_with_cw,
|
||||
state: :accepted
|
||||
).find_or_create_by!(id: 10_000_005)
|
||||
|
||||
cwed_quote_cwed = Status.create_with(
|
||||
text: 'This is a quote with a CW of a quoted post that itself has a CW',
|
||||
spoiler_text: 'Quote post with a CW',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_019)
|
||||
Quote.create_with(
|
||||
status: cwed_quote_cwed,
|
||||
quoted_status: public_self_reply_with_cw,
|
||||
state: :accepted
|
||||
).find_or_create_by!(id: 10_000_006)
|
||||
|
||||
pending_quote_post = Status.create_with(
|
||||
text: 'This quote post is pending',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_020)
|
||||
Quote.create_with(
|
||||
status: pending_quote_post,
|
||||
quoted_status: remote_formatted_post,
|
||||
activity_uri: 'https://foo/bar',
|
||||
state: :pending
|
||||
).find_or_create_by!(id: 10_000_007)
|
||||
|
||||
rejected_quote_post = Status.create_with(
|
||||
text: 'This quote post is rejected',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_021)
|
||||
Quote.create_with(
|
||||
status: rejected_quote_post,
|
||||
quoted_status: remote_formatted_post,
|
||||
activity_uri: 'https://foo/foo',
|
||||
state: :rejected
|
||||
).find_or_create_by!(id: 10_000_008)
|
||||
|
||||
revoked_quote_post = Status.create_with(
|
||||
text: 'This quote post is revoked',
|
||||
account: showcase_account,
|
||||
visibility: :public
|
||||
).find_or_create_by!(id: 10_000_022)
|
||||
Quote.create_with(
|
||||
status: revoked_quote_post,
|
||||
quoted_status: remote_formatted_post,
|
||||
activity_uri: 'https://foo/baz',
|
||||
state: :revoked
|
||||
).find_or_create_by!(id: 10_000_009)
|
||||
|
||||
StatusPin.create_with(account: showcase_account, status: public_self_reply_with_cw).find_or_create_by!(id: 10_000_000)
|
||||
StatusPin.create_with(account: showcase_account, status: private_mentionless).find_or_create_by!(id: 10_000_001)
|
||||
|
||||
showcase_account.update!(
|
||||
display_name: 'Mastodon test/showcase account',
|
||||
note: 'Test account to showcase many Mastodon features. Most of its posts are public, but some are private!'
|
||||
)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user