Change hints for missing remote content in web UI (#31516)
parent
9ba7c90151
commit
b06c7b6b5a
|
@ -1,28 +1,23 @@
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
resource: JSX.Element;
|
message: React.ReactNode;
|
||||||
|
label: React.ReactNode;
|
||||||
url: string;
|
url: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TimelineHint: React.FC<Props> = ({ className, resource, url }) => (
|
export const TimelineHint: React.FC<Props> = ({
|
||||||
|
className,
|
||||||
|
message,
|
||||||
|
label,
|
||||||
|
url,
|
||||||
|
}) => (
|
||||||
<div className={classNames('timeline-hint', className)}>
|
<div className={classNames('timeline-hint', className)}>
|
||||||
<strong>
|
<p>{message}</p>
|
||||||
<FormattedMessage
|
|
||||||
id='timeline_hint.remote_resource_not_displayed'
|
|
||||||
defaultMessage='{resource} from other servers are not displayed.'
|
|
||||||
values={{ resource }}
|
|
||||||
/>
|
|
||||||
</strong>
|
|
||||||
<br />
|
|
||||||
<a href={url} target='_blank' rel='noopener noreferrer'>
|
<a href={url} target='_blank' rel='noopener noreferrer'>
|
||||||
<FormattedMessage
|
{label}
|
||||||
id='account.browse_more_on_origin_server'
|
|
||||||
defaultMessage='Browse more on the original profile'
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@ import BundleColumnError from 'mastodon/features/ui/components/bundle_column_err
|
||||||
import { me } from 'mastodon/initial_state';
|
import { me } from 'mastodon/initial_state';
|
||||||
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
||||||
import { getAccountHidden } from 'mastodon/selectors';
|
import { getAccountHidden } from 'mastodon/selectors';
|
||||||
|
import { useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
import { lookupAccount, fetchAccount } from '../../actions/accounts';
|
import { lookupAccount, fetchAccount } from '../../actions/accounts';
|
||||||
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
||||||
|
@ -59,12 +60,22 @@ const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = fa
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const RemoteHint = ({ url }) => (
|
const RemoteHint = ({ accountId, url }) => {
|
||||||
<TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.statuses' defaultMessage='Older posts' />} />
|
const acct = useAppSelector(state => state.accounts.get(accountId)?.acct);
|
||||||
);
|
const domain = acct ? acct.split('@')[1] : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TimelineHint
|
||||||
|
url={url}
|
||||||
|
message={<FormattedMessage id='hints.profiles.posts_may_be_missing' defaultMessage='Some posts from this profile may be missing.' />}
|
||||||
|
label={<FormattedMessage id='hints.profiles.see_more_posts' defaultMessage='See more posts on {domain}' values={{ domain: <strong>{domain}</strong> }} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
RemoteHint.propTypes = {
|
RemoteHint.propTypes = {
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
|
accountId: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class AccountTimeline extends ImmutablePureComponent {
|
class AccountTimeline extends ImmutablePureComponent {
|
||||||
|
@ -175,12 +186,12 @@ class AccountTimeline extends ImmutablePureComponent {
|
||||||
} else if (blockedBy) {
|
} else if (blockedBy) {
|
||||||
emptyMessage = <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />;
|
emptyMessage = <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />;
|
||||||
} else if (remote && statusIds.isEmpty()) {
|
} else if (remote && statusIds.isEmpty()) {
|
||||||
emptyMessage = <RemoteHint url={remoteUrl} />;
|
emptyMessage = <RemoteHint accountId={accountId} url={remoteUrl} />;
|
||||||
} else {
|
} else {
|
||||||
emptyMessage = <FormattedMessage id='empty_column.account_timeline' defaultMessage='No posts found' />;
|
emptyMessage = <FormattedMessage id='empty_column.account_timeline' defaultMessage='No posts found' />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteMessage = remote ? <RemoteHint url={remoteUrl} /> : null;
|
const remoteMessage = remote ? <RemoteHint accountId={accountId} url={remoteUrl} /> : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { TimelineHint } from 'mastodon/components/timeline_hint';
|
||||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||||
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
||||||
import { getAccountHidden } from 'mastodon/selectors';
|
import { getAccountHidden } from 'mastodon/selectors';
|
||||||
|
import { useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
lookupAccount,
|
lookupAccount,
|
||||||
|
@ -51,12 +52,22 @@ const mapStateToProps = (state, { params: { acct, id } }) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const RemoteHint = ({ url }) => (
|
const RemoteHint = ({ accountId, url }) => {
|
||||||
<TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.followers' defaultMessage='Followers' />} />
|
const acct = useAppSelector(state => state.accounts.get(accountId)?.acct);
|
||||||
);
|
const domain = acct ? acct.split('@')[1] : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TimelineHint
|
||||||
|
url={url}
|
||||||
|
message={<FormattedMessage id='hints.profiles.followers_may_be_missing' defaultMessage='Followers for this profile may be missing.' />}
|
||||||
|
label={<FormattedMessage id='hints.profiles.see_more_followers' defaultMessage='See more followers on {domain}' values={{ domain: <strong>{domain}</strong> }} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
RemoteHint.propTypes = {
|
RemoteHint.propTypes = {
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
|
accountId: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Followers extends ImmutablePureComponent {
|
class Followers extends ImmutablePureComponent {
|
||||||
|
@ -141,12 +152,12 @@ class Followers extends ImmutablePureComponent {
|
||||||
} else if (hideCollections && accountIds.isEmpty()) {
|
} else if (hideCollections && accountIds.isEmpty()) {
|
||||||
emptyMessage = <FormattedMessage id='empty_column.account_hides_collections' defaultMessage='This user has chosen to not make this information available' />;
|
emptyMessage = <FormattedMessage id='empty_column.account_hides_collections' defaultMessage='This user has chosen to not make this information available' />;
|
||||||
} else if (remote && accountIds.isEmpty()) {
|
} else if (remote && accountIds.isEmpty()) {
|
||||||
emptyMessage = <RemoteHint url={remoteUrl} />;
|
emptyMessage = <RemoteHint accountId={accountId} url={remoteUrl} />;
|
||||||
} else {
|
} else {
|
||||||
emptyMessage = <FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />;
|
emptyMessage = <FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteMessage = remote ? <RemoteHint url={remoteUrl} /> : null;
|
const remoteMessage = remote ? <RemoteHint accountId={accountId} url={remoteUrl} /> : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { TimelineHint } from 'mastodon/components/timeline_hint';
|
||||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||||
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
||||||
import { getAccountHidden } from 'mastodon/selectors';
|
import { getAccountHidden } from 'mastodon/selectors';
|
||||||
|
import { useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
lookupAccount,
|
lookupAccount,
|
||||||
|
@ -51,12 +52,22 @@ const mapStateToProps = (state, { params: { acct, id } }) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const RemoteHint = ({ url }) => (
|
const RemoteHint = ({ accountId, url }) => {
|
||||||
<TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.follows' defaultMessage='Follows' />} />
|
const acct = useAppSelector(state => state.accounts.get(accountId)?.acct);
|
||||||
);
|
const domain = acct ? acct.split('@')[1] : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TimelineHint
|
||||||
|
url={url}
|
||||||
|
message={<FormattedMessage id='hints.profiles.follows_may_be_missing' defaultMessage='Follows for this profile may be missing.' />}
|
||||||
|
label={<FormattedMessage id='hints.profiles.see_more_follows' defaultMessage='See more follows on {domain}' values={{ domain: <strong>{domain}</strong> }} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
RemoteHint.propTypes = {
|
RemoteHint.propTypes = {
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
|
accountId: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Following extends ImmutablePureComponent {
|
class Following extends ImmutablePureComponent {
|
||||||
|
@ -141,12 +152,12 @@ class Following extends ImmutablePureComponent {
|
||||||
} else if (hideCollections && accountIds.isEmpty()) {
|
} else if (hideCollections && accountIds.isEmpty()) {
|
||||||
emptyMessage = <FormattedMessage id='empty_column.account_hides_collections' defaultMessage='This user has chosen to not make this information available' />;
|
emptyMessage = <FormattedMessage id='empty_column.account_hides_collections' defaultMessage='This user has chosen to not make this information available' />;
|
||||||
} else if (remote && accountIds.isEmpty()) {
|
} else if (remote && accountIds.isEmpty()) {
|
||||||
emptyMessage = <RemoteHint url={remoteUrl} />;
|
emptyMessage = <RemoteHint accountId={accountId} url={remoteUrl} />;
|
||||||
} else {
|
} else {
|
||||||
emptyMessage = <FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />;
|
emptyMessage = <FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteMessage = remote ? <RemoteHint url={remoteUrl} /> : null;
|
const remoteMessage = remote ? <RemoteHint accountId={accountId} url={remoteUrl} /> : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
|
|
|
@ -629,7 +629,14 @@ class Status extends ImmutablePureComponent {
|
||||||
const isIndexable = !status.getIn(['account', 'noindex']);
|
const isIndexable = !status.getIn(['account', 'noindex']);
|
||||||
|
|
||||||
if (!isLocal) {
|
if (!isLocal) {
|
||||||
remoteHint = <TimelineHint className={classNames(!!descendants && 'timeline-hint--with-descendants')} url={status.get('url')} resource={<FormattedMessage id='timeline_hint.resources.replies' defaultMessage='Some replies' />} />;
|
remoteHint = (
|
||||||
|
<TimelineHint
|
||||||
|
className={classNames(!!descendants && 'timeline-hint--with-descendants')}
|
||||||
|
url={status.get('url')}
|
||||||
|
message={<FormattedMessage id='hints.threads.replies_may_be_missing' defaultMessage='Replies from other servers may be missing.' />}
|
||||||
|
label={<FormattedMessage id='hints.threads.see_more' defaultMessage='See more replies on {domain}' values={{ domain: <strong>{status.getIn(['account', 'acct']).split('@')[1]}</strong> }} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlers = {
|
const handlers = {
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
"account.block_domain": "Block domain {domain}",
|
"account.block_domain": "Block domain {domain}",
|
||||||
"account.block_short": "Block",
|
"account.block_short": "Block",
|
||||||
"account.blocked": "Blocked",
|
"account.blocked": "Blocked",
|
||||||
"account.browse_more_on_origin_server": "Browse more on the original profile",
|
|
||||||
"account.cancel_follow_request": "Cancel follow",
|
"account.cancel_follow_request": "Cancel follow",
|
||||||
"account.copy": "Copy link to profile",
|
"account.copy": "Copy link to profile",
|
||||||
"account.direct": "Privately mention @{name}",
|
"account.direct": "Privately mention @{name}",
|
||||||
|
@ -349,6 +348,14 @@
|
||||||
"hashtag.follow": "Follow hashtag",
|
"hashtag.follow": "Follow hashtag",
|
||||||
"hashtag.unfollow": "Unfollow hashtag",
|
"hashtag.unfollow": "Unfollow hashtag",
|
||||||
"hashtags.and_other": "…and {count, plural, other {# more}}",
|
"hashtags.and_other": "…and {count, plural, other {# more}}",
|
||||||
|
"hints.profiles.followers_may_be_missing": "Followers for this profile may be missing.",
|
||||||
|
"hints.profiles.follows_may_be_missing": "Follows for this profile may be missing.",
|
||||||
|
"hints.profiles.posts_may_be_missing": "Some posts from this profile may be missing.",
|
||||||
|
"hints.profiles.see_more_followers": "See more followers on {domain}",
|
||||||
|
"hints.profiles.see_more_follows": "See more follows on {domain}",
|
||||||
|
"hints.profiles.see_more_posts": "See more posts on {domain}",
|
||||||
|
"hints.threads.replies_may_be_missing": "Replies from other servers may be missing.",
|
||||||
|
"hints.threads.see_more": "See more replies on {domain}",
|
||||||
"home.column_settings.show_reblogs": "Show boosts",
|
"home.column_settings.show_reblogs": "Show boosts",
|
||||||
"home.column_settings.show_replies": "Show replies",
|
"home.column_settings.show_replies": "Show replies",
|
||||||
"home.hide_announcements": "Hide announcements",
|
"home.hide_announcements": "Hide announcements",
|
||||||
|
@ -826,11 +833,6 @@
|
||||||
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
|
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
|
||||||
"time_remaining.moments": "Moments remaining",
|
"time_remaining.moments": "Moments remaining",
|
||||||
"time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
|
"time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
|
||||||
"timeline_hint.remote_resource_not_displayed": "{resource} from other servers are not displayed.",
|
|
||||||
"timeline_hint.resources.followers": "Followers",
|
|
||||||
"timeline_hint.resources.follows": "Follows",
|
|
||||||
"timeline_hint.resources.replies": "Some replies",
|
|
||||||
"timeline_hint.resources.statuses": "Older posts",
|
|
||||||
"trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
|
"trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
|
||||||
"trends.trending_now": "Trending now",
|
"trends.trending_now": "Trending now",
|
||||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||||
|
|
|
@ -4217,11 +4217,12 @@ a.status-card {
|
||||||
|
|
||||||
.timeline-hint {
|
.timeline-hint {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $darker-text-color;
|
color: $dark-text-color;
|
||||||
padding: 15px;
|
padding: 16px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
cursor: default;
|
font-size: 14px;
|
||||||
|
line-height: 21px;
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
@ -4238,10 +4239,10 @@ a.status-card {
|
||||||
color: lighten($highlight-text-color, 4%);
|
color: lighten($highlight-text-color, 4%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.timeline-hint--with-descendants {
|
&--with-descendants {
|
||||||
border-top: 1px solid var(--background-border-color);
|
border-top: 1px solid var(--background-border-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.regeneration-indicator {
|
.regeneration-indicator {
|
||||||
|
|
Loading…
Reference in New Issue