Merge tag 'v2.7.0' into instance_only_statuses
This commit is contained in:
@ -25,7 +25,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
||||
end
|
||||
|
||||
def paginated_statuses
|
||||
Status.where(reblog_of_id: @status.id).paginate_by_max_id(
|
||||
Status.where(reblog_of_id: @status.id).where(visibility: [:public, :unlisted]).paginate_by_max_id(
|
||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||
params[:max_id],
|
||||
params[:since_id]
|
||||
|
@ -28,7 +28,7 @@ class DirectoriesController < ApplicationController
|
||||
end
|
||||
|
||||
def set_tags
|
||||
@tags = Tag.discoverable.limit(30)
|
||||
@tags = Tag.discoverable.limit(30).reject { |tag| tag.cached_sample_accounts.empty? }
|
||||
end
|
||||
|
||||
def set_accounts
|
||||
|
@ -3,6 +3,8 @@
|
||||
class TagsController < ApplicationController
|
||||
PAGE_SIZE = 20
|
||||
|
||||
layout 'public'
|
||||
|
||||
before_action :set_body_classes
|
||||
before_action :set_instance_presenter
|
||||
|
||||
|
@ -69,8 +69,12 @@ module ApplicationHelper
|
||||
tag(:meta, content: content, property: property)
|
||||
end
|
||||
|
||||
def react_component(name, props = {})
|
||||
content_tag(:div, nil, data: { component: name.to_s.camelcase, props: Oj.dump(props) })
|
||||
def react_component(name, props = {}, &block)
|
||||
if block.nil?
|
||||
content_tag(:div, nil, data: { component: name.to_s.camelcase, props: Oj.dump(props) })
|
||||
else
|
||||
content_tag(:div, data: { component: name.to_s.camelcase, props: Oj.dump(props) }, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def body_classes
|
||||
|
@ -4,5 +4,9 @@ export function start() {
|
||||
require('font-awesome/css/font-awesome.css');
|
||||
require.context('../images/', true);
|
||||
|
||||
Rails.start();
|
||||
try {
|
||||
Rails.start();
|
||||
} catch (e) {
|
||||
// If called twice
|
||||
}
|
||||
};
|
||||
|
@ -1,15 +1,17 @@
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class DisplayName extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
others: ImmutablePropTypes.list,
|
||||
localDomain: PropTypes.string,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, others } = this.props;
|
||||
const { account, others, localDomain } = this.props;
|
||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||
|
||||
let suffix;
|
||||
@ -17,7 +19,13 @@ export default class DisplayName extends React.PureComponent {
|
||||
if (others && others.size > 1) {
|
||||
suffix = `+${others.size}`;
|
||||
} else {
|
||||
suffix = <span className='display-name__account'>@{account.get('acct')}</span>;
|
||||
let acct = account.get('acct');
|
||||
|
||||
if (acct.indexOf('@') === -1 && localDomain) {
|
||||
acct = `${acct}@${localDomain}`;
|
||||
}
|
||||
|
||||
suffix = <span className='display-name__account'>@{acct}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,16 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import Permalink from './permalink';
|
||||
import { shortNumberFormat } from '../utils/numbers';
|
||||
|
||||
const Hashtag = ({ hashtag }) => (
|
||||
<div className='trends__item'>
|
||||
<div className='trends__item__name'>
|
||||
<Link to={`/timelines/tag/${hashtag.get('name')}`}>
|
||||
<Permalink href={hashtag.get('url')} to={`/timelines/tag/${hashtag.get('name')}`}>
|
||||
#<span>{hashtag.get('name')}</span>
|
||||
</Link>
|
||||
</Permalink>
|
||||
|
||||
<FormattedMessage id='trends.count_by_accounts' defaultMessage='{count} {rawCount, plural, one {person} other {people}} talking' values={{ rawCount: hashtag.getIn(['history', 0, 'accounts']), count: <strong>{shortNumberFormat(hashtag.getIn(['history', 0, 'accounts']))}</strong> }} />
|
||||
</div>
|
||||
|
@ -77,7 +77,7 @@ class Status extends ImmutablePureComponent {
|
||||
'account',
|
||||
'muted',
|
||||
'hidden',
|
||||
]
|
||||
];
|
||||
|
||||
handleClick = () => {
|
||||
if (this.props.onClick) {
|
||||
|
@ -1,28 +1,32 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../../ui/containers/status_list_container';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { expandHashtagTimeline } from '../../../actions/timelines';
|
||||
import Column from '../../../components/column';
|
||||
import ColumnHeader from '../../../components/column_header';
|
||||
import { connectHashtagStream } from '../../../actions/streaming';
|
||||
import Masonry from 'react-masonry-infinite';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import DetailedStatusContainer from '../../status/containers/detailed_status_container';
|
||||
import { debounce } from 'lodash';
|
||||
import LoadingIndicator from '../../../components/loading_indicator';
|
||||
|
||||
export default @connect()
|
||||
const mapStateToProps = (state, { hashtag }) => ({
|
||||
statusIds: state.getIn(['timelines', `hashtag:${hashtag}`, 'items'], ImmutableList()),
|
||||
isLoading: state.getIn(['timelines', `hashtag:${hashtag}`, 'isLoading'], false),
|
||||
hasMore: state.getIn(['timelines', `hashtag:${hashtag}`, 'hasMore'], false),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
class HashtagTimeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
statusIds: ImmutablePropTypes.list.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
hasMore: PropTypes.bool.isRequired,
|
||||
hashtag: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, hashtag } = this.props;
|
||||
|
||||
@ -37,28 +41,52 @@ class HashtagTimeline extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));
|
||||
handleLoadMore = () => {
|
||||
const maxId = this.props.statusIds.last();
|
||||
|
||||
if (maxId) {
|
||||
this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.masonry = c;
|
||||
}
|
||||
|
||||
handleHeightChange = debounce(() => {
|
||||
if (!this.masonry) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.masonry.forcePack();
|
||||
}, 50)
|
||||
|
||||
render () {
|
||||
const { hashtag } = this.props;
|
||||
const { statusIds, hasMore, isLoading } = this.props;
|
||||
|
||||
const sizes = [
|
||||
{ columns: 1, gutter: 0 },
|
||||
{ mq: '415px', columns: 1, gutter: 10 },
|
||||
{ mq: '640px', columns: 2, gutter: 10 },
|
||||
{ mq: '960px', columns: 3, gutter: 10 },
|
||||
{ mq: '1255px', columns: 3, gutter: 10 },
|
||||
];
|
||||
|
||||
const loader = (isLoading && statusIds.isEmpty()) ? <LoadingIndicator key={0} /> : undefined;
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon='hashtag'
|
||||
title={hashtag}
|
||||
onClick={this.handleHeaderClick}
|
||||
/>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={false}
|
||||
scrollKey='standalone_hashtag_timeline'
|
||||
timelineId={`hashtag:${hashtag}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
/>
|
||||
</Column>
|
||||
<Masonry ref={this.setRef} className='statuses-grid' hasMore={hasMore} loadMore={this.handleLoadMore} sizes={sizes} loader={loader}>
|
||||
{statusIds.map(statusId => (
|
||||
<div className='statuses-grid__item' key={statusId}>
|
||||
<DetailedStatusContainer
|
||||
id={statusId}
|
||||
compact
|
||||
measureHeight
|
||||
onHeightChange={this.handleHeightChange}
|
||||
/>
|
||||
</div>
|
||||
)).toArray()}
|
||||
</Masonry>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,8 @@ import { defineMessages, injectIntl, FormattedDate, FormattedNumber } from 'reac
|
||||
import Card from './card';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Video from '../../video';
|
||||
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const messages = defineMessages({
|
||||
local_only: { id: 'status.local_only', defaultMessage: 'This post is only visible by other users of your instance' },
|
||||
@ -28,10 +30,18 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||
onOpenMedia: PropTypes.func.isRequired,
|
||||
onOpenVideo: PropTypes.func.isRequired,
|
||||
onToggleHidden: PropTypes.func.isRequired,
|
||||
measureHeight: PropTypes.bool,
|
||||
onHeightChange: PropTypes.func,
|
||||
domain: PropTypes.string.isRequired,
|
||||
compact: PropTypes.bool,
|
||||
};
|
||||
|
||||
state = {
|
||||
height: null,
|
||||
};
|
||||
|
||||
handleAccountClick = (e) => {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.context.router) {
|
||||
e.preventDefault();
|
||||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);
|
||||
}
|
||||
@ -47,15 +57,59 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||
this.props.onToggleHidden(this.props.status);
|
||||
}
|
||||
|
||||
_measureHeight (heightJustChanged) {
|
||||
if (this.props.measureHeight && this.node) {
|
||||
scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 }));
|
||||
|
||||
if (this.props.onHeightChange && heightJustChanged) {
|
||||
this.props.onHeightChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
this._measureHeight();
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
this._measureHeight(prevState.height !== this.state.height);
|
||||
}
|
||||
|
||||
handleModalLink = e => {
|
||||
e.preventDefault();
|
||||
|
||||
let href;
|
||||
|
||||
if (e.target.nodeName !== 'A') {
|
||||
href = e.target.parentNode.href;
|
||||
} else {
|
||||
href = e.target.href;
|
||||
}
|
||||
|
||||
window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
|
||||
}
|
||||
|
||||
render () {
|
||||
const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status;
|
||||
const intl = this.props.intl;
|
||||
const outerStyle = { boxSizing: 'border-box' };
|
||||
const { compact } = this.props;
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let media = '';
|
||||
let applicationLink = '';
|
||||
let reblogLink = '';
|
||||
let localOnly = '';
|
||||
let reblogIcon = 'retweet';
|
||||
let favouriteLink = '';
|
||||
|
||||
if (this.props.measureHeight) {
|
||||
outerStyle.height = `${this.state.height}px`;
|
||||
}
|
||||
|
||||
if (status.get('media_attachments').size > 0) {
|
||||
if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) {
|
||||
@ -102,39 +156,67 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||
|
||||
if (status.get('visibility') === 'private') {
|
||||
reblogLink = <i className={`fa fa-${reblogIcon}`} />;
|
||||
} else if (this.context.router) {
|
||||
reblogLink = (
|
||||
<Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>
|
||||
<i className={`fa fa-${reblogIcon}`} />
|
||||
<span className='detailed-status__reblogs'>
|
||||
<FormattedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
reblogLink = (<Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>
|
||||
<i className={`fa fa-${reblogIcon}`} />
|
||||
<span className='detailed-status__reblogs'>
|
||||
<FormattedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
</Link>);
|
||||
reblogLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<i className={`fa fa-${reblogIcon}`} />
|
||||
<span className='detailed-status__reblogs'>
|
||||
<FormattedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
if(status.get('local_only')) {
|
||||
localOnly = <span> · <i className='fa fa-chain-broken' title={intl.formatMessage(messages.local_only)} /></span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='detailed-status'>
|
||||
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>
|
||||
<div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
|
||||
<DisplayName account={status.get('account')} />
|
||||
if (this.context.router) {
|
||||
favouriteLink = (
|
||||
<Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
|
||||
<i className='fa fa-star' />
|
||||
<span className='detailed-status__favorites'>
|
||||
<FormattedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
favouriteLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<i className='fa fa-star' />
|
||||
<span className='detailed-status__favorites'>
|
||||
<FormattedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
<StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
|
||||
return (
|
||||
<div style={outerStyle}>
|
||||
<div ref={this.setRef} className={classNames('detailed-status', { compact })}>
|
||||
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>
|
||||
<div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
|
||||
<DisplayName account={status.get('account')} localDomain={this.props.domain} />
|
||||
</a>
|
||||
|
||||
{media}
|
||||
<StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
|
||||
|
||||
<div className='detailed-status__meta'>
|
||||
<a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'>
|
||||
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
||||
</a>{applicationLink} · {reblogLink} · <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'>
|
||||
<i className='fa fa-star' />
|
||||
<span className='detailed-status__favorites'>
|
||||
<FormattedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
</Link>{localOnly}
|
||||
{media}
|
||||
|
||||
<div className='detailed-status__meta'>
|
||||
<a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'>
|
||||
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
|
||||
</a>{applicationLink} · {reblogLink} · {favouriteLink}{localOnly}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -0,0 +1,172 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import DetailedStatus from '../components/detailed_status';
|
||||
import { makeGetStatus } from '../../../selectors';
|
||||
import {
|
||||
replyCompose,
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../../../actions/compose';
|
||||
import {
|
||||
reblog,
|
||||
favourite,
|
||||
unreblog,
|
||||
unfavourite,
|
||||
pin,
|
||||
unpin,
|
||||
} from '../../../actions/interactions';
|
||||
import { blockAccount } from '../../../actions/accounts';
|
||||
import {
|
||||
muteStatus,
|
||||
unmuteStatus,
|
||||
deleteStatus,
|
||||
hideStatus,
|
||||
revealStatus,
|
||||
} from '../../../actions/statuses';
|
||||
import { initMuteModal } from '../../../actions/mutes';
|
||||
import { initReport } from '../../../actions/reports';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { boostModal, deleteModal } from '../../../initial_state';
|
||||
import { showAlertForError } from '../../../actions/alerts';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
|
||||
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
|
||||
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' },
|
||||
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
|
||||
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
|
||||
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getStatus = makeGetStatus();
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
status: getStatus(state, props),
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onReply (status, router) {
|
||||
dispatch((_, getState) => {
|
||||
let state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.replyMessage),
|
||||
confirm: intl.formatMessage(messages.replyConfirm),
|
||||
onConfirm: () => dispatch(replyCompose(status, router)),
|
||||
}));
|
||||
} else {
|
||||
dispatch(replyCompose(status, router));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onModalReblog (status) {
|
||||
dispatch(reblog(status));
|
||||
},
|
||||
|
||||
onReblog (status, e) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
} else {
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
} else {
|
||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onFavourite (status) {
|
||||
if (status.get('favourited')) {
|
||||
dispatch(unfavourite(status));
|
||||
} else {
|
||||
dispatch(favourite(status));
|
||||
}
|
||||
},
|
||||
|
||||
onPin (status) {
|
||||
if (status.get('pinned')) {
|
||||
dispatch(unpin(status));
|
||||
} else {
|
||||
dispatch(pin(status));
|
||||
}
|
||||
},
|
||||
|
||||
onEmbed (status) {
|
||||
dispatch(openModal('EMBED', {
|
||||
url: status.get('url'),
|
||||
onError: error => dispatch(showAlertForError(error)),
|
||||
}));
|
||||
},
|
||||
|
||||
onDelete (status, history, withRedraft = false) {
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id'), history, withRedraft));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
|
||||
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
onDirect (account, router) {
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
|
||||
onMention (account, router) {
|
||||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
|
||||
onOpenMedia (media, index) {
|
||||
dispatch(openModal('MEDIA', { media, index }));
|
||||
},
|
||||
|
||||
onOpenVideo (media, time) {
|
||||
dispatch(openModal('VIDEO', { media, time }));
|
||||
},
|
||||
|
||||
onBlock (account) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.get('id'))),
|
||||
}));
|
||||
},
|
||||
|
||||
onReport (status) {
|
||||
dispatch(initReport(status.get('account'), status));
|
||||
},
|
||||
|
||||
onMute (account) {
|
||||
dispatch(initMuteModal(account));
|
||||
},
|
||||
|
||||
onMuteConversation (status) {
|
||||
if (status.get('muted')) {
|
||||
dispatch(unmuteStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(muteStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onToggleHidden (status) {
|
||||
if (status.get('hidden')) {
|
||||
dispatch(revealStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(hideStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(DetailedStatus));
|
@ -101,6 +101,7 @@ const makeMapStateToProps = () => {
|
||||
ancestorsIds,
|
||||
descendantsIds,
|
||||
askReplyConfirmation: state.getIn(['compose', 'text']).trim().length !== 0,
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
};
|
||||
};
|
||||
|
||||
@ -123,6 +124,7 @@ class Status extends ImmutablePureComponent {
|
||||
descendantsIds: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
askReplyConfirmation: PropTypes.bool,
|
||||
domain: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
@ -387,7 +389,7 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
render () {
|
||||
let ancestors, descendants;
|
||||
const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl } = this.props;
|
||||
const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl, domain } = this.props;
|
||||
const { fullscreen } = this.state;
|
||||
|
||||
if (status === null) {
|
||||
@ -438,6 +440,7 @@ class Status extends ImmutablePureComponent {
|
||||
onOpenVideo={this.handleOpenVideo}
|
||||
onOpenMedia={this.handleOpenMedia}
|
||||
onToggleHidden={this.handleToggleHidden}
|
||||
domain={domain}
|
||||
/>
|
||||
|
||||
<ActionBar
|
||||
|
@ -33,7 +33,7 @@ const messages = defineMessages({
|
||||
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
|
||||
});
|
||||
|
||||
const shouldHideFAB = path => path.match(/^\/statuses\//);
|
||||
const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/);
|
||||
|
||||
export default @(component => injectIntl(component, { withRef: true }))
|
||||
class ColumnsArea extends ImmutablePureComponent {
|
||||
|
@ -243,6 +243,7 @@ class UI extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleDragOver = (e) => {
|
||||
if (this.dataTransferIsText(e.dataTransfer)) return false;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
@ -256,9 +257,11 @@ class UI extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleDrop = (e) => {
|
||||
if (this.dataTransferIsText(e.dataTransfer)) return;
|
||||
e.preventDefault();
|
||||
|
||||
this.setState({ draggingOver: false });
|
||||
this.dragTargets = [];
|
||||
|
||||
if (e.dataTransfer && e.dataTransfer.files.length === 1) {
|
||||
this.props.dispatch(uploadCompose(e.dataTransfer.files));
|
||||
@ -278,6 +281,10 @@ class UI extends React.PureComponent {
|
||||
this.setState({ draggingOver: false });
|
||||
}
|
||||
|
||||
dataTransferIsText = (dataTransfer) => {
|
||||
return (dataTransfer && Array.from(dataTransfer.types).includes('text/plain') && dataTransfer.items.length === 1);
|
||||
}
|
||||
|
||||
closeUploadModal = () => {
|
||||
this.setState({ draggingOver: false });
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
"account.follows_you": "يتابعك",
|
||||
"account.hide_reblogs": "إخفاء ترقيات @{name}",
|
||||
"account.link_verified_on": "تم التحقق مِن مالك هذا الرابط بتاريخ {date}",
|
||||
"account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
|
||||
"account.locked_info": "تم تأمين خصوصية هذا الحساب عبر قُفل. فصاحب الحساب يُراجِع يدويا طلبات المتابَعة و الاشتراك بحسابه.",
|
||||
"account.media": "وسائط",
|
||||
"account.mention": "أُذكُر @{name}",
|
||||
"account.moved_to": "{name} إنتقل إلى :",
|
||||
@ -137,8 +137,8 @@
|
||||
"follow_request.authorize": "ترخيص",
|
||||
"follow_request.reject": "رفض",
|
||||
"getting_started.developers": "المُطوِّرون",
|
||||
"getting_started.directory": "Profile directory",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.directory": "دليل المستخدِمين والمستخدِمات",
|
||||
"getting_started.documentation": "الدليل",
|
||||
"getting_started.heading": "إستعدّ للبدء",
|
||||
"getting_started.invite": "دعوة أشخاص",
|
||||
"getting_started.open_source_notice": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على جيت هب {github}.",
|
||||
@ -160,17 +160,17 @@
|
||||
"introduction.federation.home.headline": "Home",
|
||||
"introduction.federation.home.text": "سوف تُعرَض منشورات الأشخاص الذين تُتابِعهم على الخيط الرئيسي. بإمكانك متابعة أي حساب أيا كان الخادم الذي هو عليه!",
|
||||
"introduction.federation.local.headline": "Local",
|
||||
"introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
|
||||
"introduction.interactions.action": "Finish tutorial!",
|
||||
"introduction.federation.local.text": "المنشورات المُوجّهة للعامة على نفس الخادم الذي أنتم عليه ستظهر على الخيط الزمني المحلي.",
|
||||
"introduction.interactions.action": "إنهاء العرض التوضيحي!",
|
||||
"introduction.interactions.favourite.headline": "الإضافة إلى المفضلة",
|
||||
"introduction.interactions.favourite.text": "يمكِنك إضافة أي تبويق إلى المفضلة و إعلام صاحبه أنك أعجِبت بذاك التبويق.",
|
||||
"introduction.interactions.reblog.headline": "الترقية",
|
||||
"introduction.interactions.reblog.text": "يمكنكم مشاركة تبويقات الأشخاص الآخرين مع متابِعيكم عن طريق ترقيتها.",
|
||||
"introduction.interactions.reply.headline": "الرد",
|
||||
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
|
||||
"introduction.interactions.reply.text": "يمكنكم الرد على تبويقاتكم و تبويقات الآخرين على شكل سلسلة محادثة.",
|
||||
"introduction.welcome.action": "هيا بنا!",
|
||||
"introduction.welcome.headline": "الخطوات الأولى",
|
||||
"introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
|
||||
"introduction.welcome.text": "مرحبا بكم على الفيديفيرس! بعد لحظات قليلة ، سيكون بمقدوركم بث رسائل والتحدث إلى أصدقائكم عبر تشكيلة واسعة من الخوادم المختلفة. هذا الخادم ، {domain} ، يستضيف ملفكم الشخصي ، لذا يجب تذكر اسمه جيدا.",
|
||||
"keyboard_shortcuts.back": "للعودة",
|
||||
"keyboard_shortcuts.blocked": "لفتح قائمة المستخدمين المحظورين",
|
||||
"keyboard_shortcuts.boost": "للترقية",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "التبويقات",
|
||||
"search_results.total": "{count, number} {count, plural, one {result} و {results}}",
|
||||
"standalone.public_title": "نظرة على ...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "افتح الواجهة الإدارية لـ @{name}",
|
||||
"status.admin_status": "افتح هذا المنشور على واجهة الإشراف",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "إلغاء الترقية",
|
||||
"status.cannot_reblog": "تعذرت ترقية هذا المنشور",
|
||||
|
@ -8,7 +8,7 @@
|
||||
"account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.",
|
||||
"account.domain_blocked": "Domini ocult",
|
||||
"account.edit_profile": "Editar el perfil",
|
||||
"account.endorse": "Característica del perfil",
|
||||
"account.endorse": "Recomanar en el teu perfil",
|
||||
"account.follow": "Segueix",
|
||||
"account.followers": "Seguidors",
|
||||
"account.followers.empty": "Encara ningú no segueix aquest usuari.",
|
||||
@ -155,9 +155,9 @@
|
||||
"home.column_settings.show_reblogs": "Mostrar impulsos",
|
||||
"home.column_settings.show_replies": "Mostrar respostes",
|
||||
"introduction.federation.action": "Següent",
|
||||
"introduction.federation.federated.headline": "Federated",
|
||||
"introduction.federation.federated.headline": "Federada",
|
||||
"introduction.federation.federated.text": "Les publicacions públiques d'altres servidors del fedivers apareixeran a la línia de temps federada.",
|
||||
"introduction.federation.home.headline": "Home",
|
||||
"introduction.federation.home.headline": "Inici",
|
||||
"introduction.federation.home.text": "Les publicacions de les persones que segueixes apareixeran a la línia de temps Inici. Pots seguir qualsevol persona de qualsevol servidor!",
|
||||
"introduction.federation.local.headline": "Local",
|
||||
"introduction.federation.local.text": "Les publicacions públiques de les persones del teu mateix servidor apareixeran a la línia de temps local.",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.total": "{count, number} {count, plural, un {result} altres {results}}",
|
||||
"standalone.public_title": "Una mirada a l'interior ...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Obre l'interfície de moderació per a @{name}",
|
||||
"status.admin_status": "Obre aquest estat a la interfície de moderació",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Desfer l'impuls",
|
||||
"status.cannot_reblog": "Aquesta publicació no pot ser retootejada",
|
||||
|
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Statuti",
|
||||
"search_results.total": "{count, number} {count, plural, one {risultatu} other {risultati}}",
|
||||
"standalone.public_title": "Una vista à l'internu...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Apre l'interfaccia di muderazione per @{name}",
|
||||
"status.admin_status": "Apre stu statutu in l'interfaccia di muderazione",
|
||||
"status.block": "Bluccà @{name}",
|
||||
"status.cancel_reblog_private": "Ùn sparte più",
|
||||
"status.cannot_reblog": "Stu statutu ùn pò micca esse spartutu",
|
||||
|
@ -150,7 +150,7 @@
|
||||
"hashtag.column_settings.tag_mode.all": "Všechny z těchto",
|
||||
"hashtag.column_settings.tag_mode.any": "Jakékoliv z těchto",
|
||||
"hashtag.column_settings.tag_mode.none": "Žádné z těchto",
|
||||
"hashtag.column_settings.tag_toggle": "Zahrnout v tomto sloupci dodatečné hashtagy",
|
||||
"hashtag.column_settings.tag_toggle": "Zahrnout v tomto sloupci dodatečné tagy",
|
||||
"home.column_settings.basic": "Základní",
|
||||
"home.column_settings.show_reblogs": "Zobrazit boosty",
|
||||
"home.column_settings.show_replies": "Zobrazit odpovědi",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Tooty",
|
||||
"search_results.total": "{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledku} other {výsledků}}",
|
||||
"standalone.public_title": "Nahlédněte dovnitř...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Otevřít moderační rozhraní pro uživatele @{name}",
|
||||
"status.admin_status": "Otevřít tento příspěvek v moderačním rozhraní",
|
||||
"status.block": "Zablokovat uživatele @{name}",
|
||||
"status.cancel_reblog_private": "Zrušit boost",
|
||||
"status.cannot_reblog": "Tento příspěvek nemůže být boostnutý",
|
||||
|
@ -84,7 +84,7 @@
|
||||
"confirmations.block.confirm": "Blocio",
|
||||
"confirmations.block.message": "Ydych chi'n sicr eich bod eisiau blocio {name}?",
|
||||
"confirmations.delete.confirm": "Dileu",
|
||||
"confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y statws hwn?",
|
||||
"confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y tŵt hwn?",
|
||||
"confirmations.delete_list.confirm": "Dileu",
|
||||
"confirmations.delete_list.message": "Ydych chi'n sicr eich bod eisiau dileu y rhestr hwn am byth?",
|
||||
"confirmations.domain_block.confirm": "Cuddio parth cyfan",
|
||||
@ -92,12 +92,12 @@
|
||||
"confirmations.mute.confirm": "Tawelu",
|
||||
"confirmations.mute.message": "Ydych chi'n sicr eich bod am ddistewi {name}?",
|
||||
"confirmations.redraft.confirm": "Dileu & ailddrafftio",
|
||||
"confirmations.redraft.message": "Ydych chi'n siwr eich bod eisiau dileu y statws hwn a'i ailddrafftio? Bydd ffefrynnau a bwstiau'n cael ei colli, a bydd ymatebion i'r statws gwreiddiol yn cael eu hamddifadu.",
|
||||
"confirmations.redraft.message": "Ydych chi'n siwr eich bod eisiau dileu y tŵt hwn a'i ailddrafftio? Bydd ffefrynnau a bwstiau'n cael ei colli, a bydd ymatebion i'r tŵt gwreiddiol yn cael eu hamddifadu.",
|
||||
"confirmations.reply.confirm": "Ateb",
|
||||
"confirmations.reply.message": "Bydd ateb nawr yn cymryd lle y neges yr ydych yn cyfansoddi ar hyn o bryd. Ydych chi'n sicr yr ydych am barhau?",
|
||||
"confirmations.unfollow.confirm": "Dad-ddilynwch",
|
||||
"confirmations.unfollow.message": "Ydych chi'n sicr eich bod am ddad-ddilyn {name}?",
|
||||
"embed.instructions": "Mewnblannwch y statws hwn ar eich gwefan drwy gopïo'r côd isod.",
|
||||
"embed.instructions": "Mewnblannwch y tŵt hwn ar eich gwefan drwy gopïo'r côd isod.",
|
||||
"embed.preview": "Dyma sut olwg fydd arno:",
|
||||
"emoji_button.activity": "Gweithgarwch",
|
||||
"emoji_button.custom": "Unigryw",
|
||||
@ -144,29 +144,29 @@
|
||||
"getting_started.open_source_notice": "Mae Mastodon yn feddalwedd côd agored. Mae modd cyfrannu neu adrodd materion ar GitHUb ar {github}.",
|
||||
"getting_started.security": "Diogelwch",
|
||||
"getting_started.terms": "Telerau Gwasanaeth",
|
||||
"hashtag.column_header.tag_mode.all": "and {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "or {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "without {additional}",
|
||||
"hashtag.column_settings.tag_mode.all": "All of these",
|
||||
"hashtag.column_settings.tag_mode.any": "Any of these",
|
||||
"hashtag.column_settings.tag_mode.none": "None of these",
|
||||
"hashtag.column_header.tag_mode.all": "a {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "neu {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "heb {additional}",
|
||||
"hashtag.column_settings.tag_mode.all": "Pob un o'r rhain",
|
||||
"hashtag.column_settings.tag_mode.any": "Unrhyw un o'r rhain",
|
||||
"hashtag.column_settings.tag_mode.none": "Dim o'r rhain",
|
||||
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
|
||||
"home.column_settings.basic": "Syml",
|
||||
"home.column_settings.show_reblogs": "Dangos bŵstiau",
|
||||
"home.column_settings.show_replies": "Dangos ymatebion",
|
||||
"introduction.federation.action": "Next",
|
||||
"introduction.federation.federated.headline": "Federated",
|
||||
"introduction.federation.action": "Nesaf",
|
||||
"introduction.federation.federated.headline": "Ffederasiwn",
|
||||
"introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
|
||||
"introduction.federation.home.headline": "Home",
|
||||
"introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
|
||||
"introduction.federation.local.headline": "Local",
|
||||
"introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
|
||||
"introduction.interactions.action": "Finish tutorial!",
|
||||
"introduction.interactions.favourite.headline": "Favourite",
|
||||
"introduction.interactions.favourite.headline": "Ffefryn",
|
||||
"introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
|
||||
"introduction.interactions.reblog.headline": "Boost",
|
||||
"introduction.interactions.reblog.headline": "Hwb",
|
||||
"introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
|
||||
"introduction.interactions.reply.headline": "Reply",
|
||||
"introduction.interactions.reply.headline": "Ateb",
|
||||
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
|
||||
"introduction.welcome.action": "Let's go!",
|
||||
"introduction.welcome.headline": "First steps",
|
||||
@ -174,12 +174,12 @@
|
||||
"keyboard_shortcuts.back": "i lywio nôl",
|
||||
"keyboard_shortcuts.blocked": "i agor rhestr defnyddwyr a flociwyd",
|
||||
"keyboard_shortcuts.boost": "i fŵstio",
|
||||
"keyboard_shortcuts.column": "i ffocysu statws yn un o'r colofnau",
|
||||
"keyboard_shortcuts.column": "i ffocysu tŵt yn un o'r colofnau",
|
||||
"keyboard_shortcuts.compose": "i ffocysu yr ardal cyfansoddi testun",
|
||||
"keyboard_shortcuts.description": "Disgrifiad",
|
||||
"keyboard_shortcuts.direct": "i agor colofn negeseuon preifat",
|
||||
"keyboard_shortcuts.down": "i symud lawr yn y rhestr",
|
||||
"keyboard_shortcuts.enter": "i agor statws",
|
||||
"keyboard_shortcuts.enter": "i agor tŵt",
|
||||
"keyboard_shortcuts.favourite": "i hoffi",
|
||||
"keyboard_shortcuts.favourites": "i agor rhestr hoffi",
|
||||
"keyboard_shortcuts.federated": "i agor ffrwd y ffederasiwn",
|
||||
@ -239,30 +239,30 @@
|
||||
"navigation_bar.preferences": "Dewisiadau",
|
||||
"navigation_bar.public_timeline": "Ffrwd y ffederasiwn",
|
||||
"navigation_bar.security": "Diogelwch",
|
||||
"notification.favourite": "hoffodd {name} eich statws",
|
||||
"notification.favourite": "hoffodd {name} eich tŵt",
|
||||
"notification.follow": "dilynodd {name} chi",
|
||||
"notification.mention": "Soniodd {name} amdanoch chi",
|
||||
"notification.reblog": "{name} boosted your status",
|
||||
"notification.reblog": "Hysbysebodd {name} eich tŵt",
|
||||
"notifications.clear": "Clirio hysbysiadau",
|
||||
"notifications.clear_confirmation": "Ydych chi'n sicr eich bod am glirio'ch holl hysbysiadau am byth?",
|
||||
"notifications.column_settings.alert": "Hysbysiadau bwrdd gwaith",
|
||||
"notifications.column_settings.favourite": "Ffefrynnau:",
|
||||
"notifications.column_settings.filter_bar.advanced": "Display all categories",
|
||||
"notifications.column_settings.filter_bar.category": "Quick filter bar",
|
||||
"notifications.column_settings.filter_bar.show": "Show",
|
||||
"notifications.column_settings.filter_bar.show": "Dangos",
|
||||
"notifications.column_settings.follow": "Dilynwyr newydd:",
|
||||
"notifications.column_settings.mention": "Crybwylliadau:",
|
||||
"notifications.column_settings.push": "Hysbysiadau push",
|
||||
"notifications.column_settings.reblog": "Boosts:",
|
||||
"notifications.column_settings.reblog": "Hybiadau:",
|
||||
"notifications.column_settings.show": "Dangos yn y golofn",
|
||||
"notifications.column_settings.sound": "Chwarae sain",
|
||||
"notifications.filter.all": "All",
|
||||
"notifications.filter.boosts": "Boosts",
|
||||
"notifications.filter.favourites": "Favourites",
|
||||
"notifications.filter.follows": "Follows",
|
||||
"notifications.filter.all": "Pob",
|
||||
"notifications.filter.boosts": "Hybiadau",
|
||||
"notifications.filter.favourites": "Ffefrynnau",
|
||||
"notifications.filter.follows": "Yn dilyn",
|
||||
"notifications.filter.mentions": "Mentions",
|
||||
"notifications.group": "{count} o hysbysiadau",
|
||||
"privacy.change": "Addasu preifatrwdd y statws",
|
||||
"privacy.change": "Addasu preifatrwdd y tŵt",
|
||||
"privacy.direct.long": "Cyhoeddi i'r defnyddwyr sy'n cael eu crybwyll yn unig",
|
||||
"privacy.direct.short": "Uniongyrchol",
|
||||
"privacy.private.long": "Cyhoeddi i ddilynwyr yn unig",
|
||||
@ -289,7 +289,7 @@
|
||||
"search_popout.search_format": "Fformat chwilio uwch",
|
||||
"search_popout.tips.full_text": "Mae testun syml yn dychwelyd tŵtiau yr ydych wedi ysgrifennu, hoffi, wedi'u bŵstio, neu wedi'ch crybwyll ynddynt, ynghyd a chyfateb a enwau defnyddwyr, enwau arddangos ac hashnodau.",
|
||||
"search_popout.tips.hashtag": "hashnod",
|
||||
"search_popout.tips.status": "statws",
|
||||
"search_popout.tips.status": "tŵt",
|
||||
"search_popout.tips.text": "Mae testun syml yn dychwelyd enwau arddangos, enwau defnyddwyr a hashnodau sy'n cyfateb",
|
||||
"search_popout.tips.user": "defnyddiwr",
|
||||
"search_results.accounts": "Pobl",
|
||||
@ -298,7 +298,7 @@
|
||||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"standalone.public_title": "Golwg tu fewn...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_status": "Open this tŵt in the moderation interface",
|
||||
"status.block": "Blocio @{name}",
|
||||
"status.cancel_reblog_private": "Dadfŵstio",
|
||||
"status.cannot_reblog": "Ni ellir sbarduno'r tŵt hwn",
|
||||
@ -307,7 +307,7 @@
|
||||
"status.direct": "Neges breifat @{name}",
|
||||
"status.embed": "Plannu",
|
||||
"status.favourite": "Hoffi",
|
||||
"status.filtered": "Filtered",
|
||||
"status.filtered": "Wedi'i hidlo",
|
||||
"status.load_more": "Llwythwch mwy",
|
||||
"status.local_only": "This post is only visible by other users of your instance",
|
||||
"status.media_hidden": "Cyfryngau wedi'u cuddio",
|
||||
@ -315,7 +315,7 @@
|
||||
"status.more": "Mwy",
|
||||
"status.mute": "Tawelu @{name}",
|
||||
"status.mute_conversation": "Tawelu sgwrs",
|
||||
"status.open": "Ehangu'r statws hwn",
|
||||
"status.open": "Ehangu'r tŵt hwn",
|
||||
"status.pin": "Pinio ar y proffil",
|
||||
"status.pinned": "Pinio tŵt",
|
||||
"status.read_more": "Darllen mwy",
|
||||
@ -334,12 +334,12 @@
|
||||
"status.show_less_all": "Dangos llai i bawb",
|
||||
"status.show_more": "Dangos mwy",
|
||||
"status.show_more_all": "Dangos mwy i bawb",
|
||||
"status.show_thread": "Show thread",
|
||||
"status.show_thread": "Dangos edefyn",
|
||||
"status.unmute_conversation": "Dad-dawelu sgwrs",
|
||||
"status.unpin": "Dadbinio o'r proffil",
|
||||
"suggestions.dismiss": "Dismiss suggestion",
|
||||
"suggestions.header": "You might be interested in…",
|
||||
"tabs_bar.federated_timeline": "Wedi'i ffedereiddio",
|
||||
"tabs_bar.federated_timeline": "Ffederasiwn",
|
||||
"tabs_bar.home": "Hafan",
|
||||
"tabs_bar.local_timeline": "Lleol",
|
||||
"tabs_bar.notifications": "Hysbysiadau",
|
||||
@ -349,7 +349,7 @@
|
||||
"upload_area.title": "Llusgwch & gollwing i uwchlwytho",
|
||||
"upload_button.label": "Ychwanegwch gyfryngau (JPEG, PNG, GIF, WebM, MP4, MOV)",
|
||||
"upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg",
|
||||
"upload_form.focus": "Cropio",
|
||||
"upload_form.focus": "Newid rhagolwg",
|
||||
"upload_form.undo": "Dileu",
|
||||
"upload_progress.label": "Uwchlwytho...",
|
||||
"video.close": "Cau fideo",
|
||||
|
@ -92,7 +92,7 @@
|
||||
"confirmations.mute.confirm": "Stummschalten",
|
||||
"confirmations.mute.message": "Bist du dir sicher, dass du {name} stummschalten möchtest?",
|
||||
"confirmations.redraft.confirm": "Löschen und neu erstellen",
|
||||
"confirmations.redraft.message": "Bist du dir sicher, dass du diesen Status löschen und neu machen möchtest? Favoriten und Boosts werden verloren gehen und Antworten zu diesem Post werden verwaist sein.",
|
||||
"confirmations.redraft.message": "Bist du dir sicher, dass du diesen Beitrag löschen und neu machen möchtest? Favoriten und Boosts werden verloren gehen und Antworten zu diesem Beitrag werden verwaist sein.",
|
||||
"confirmations.reply.confirm": "Antworten",
|
||||
"confirmations.reply.message": "Wenn du jetzt antwortest wird es die gesamte Nachricht verwerfen, die du gerade schreibst. Möchtest du wirklich fortfahren?",
|
||||
"confirmations.unfollow.confirm": "Entfolgen",
|
||||
@ -165,7 +165,7 @@
|
||||
"introduction.interactions.favourite.headline": "Favorisieren",
|
||||
"introduction.interactions.favourite.text": "Du kannst einen Beitrag für später speichern und dem Autor wissen lassen, dass du ihn magst, indem du ihn favorisierst.",
|
||||
"introduction.interactions.reblog.headline": "Teilen",
|
||||
"introduction.interactions.reblog.text": "Du kannst Beiträge von anderen Leuten an deine Follower teilen (oder auch \"boosten\").",
|
||||
"introduction.interactions.reblog.text": "Du kannst Beiträge von anderen Leuten an deine Follower teilen.",
|
||||
"introduction.interactions.reply.headline": "Antworten",
|
||||
"introduction.interactions.reply.text": "Du kannst auf die Beiträge von anderen Leuten antworten und die Beiträge werden dann in eine Konversation zusammengebunden.",
|
||||
"introduction.welcome.action": "Lasst uns loslegen!",
|
||||
@ -173,7 +173,7 @@
|
||||
"introduction.welcome.text": "Willkommen im Fediverse! In wenigen Momenten wirst du in der Lage sein Nachrichten zu versenden und mit deinen Freunden über Server hinweg in Kontakt zu treten. Aber dieser Server, {domain}, ist sehr speziell — er hostet dein Profil, also merke dir den Namen.",
|
||||
"keyboard_shortcuts.back": "zurück navigieren",
|
||||
"keyboard_shortcuts.blocked": "Liste blockierter Profile öffnen",
|
||||
"keyboard_shortcuts.boost": "boosten",
|
||||
"keyboard_shortcuts.boost": "teilen",
|
||||
"keyboard_shortcuts.column": "einen Status in einer der Spalten fokussieren",
|
||||
"keyboard_shortcuts.compose": "fokussiere das Eingabefeld",
|
||||
"keyboard_shortcuts.description": "Beschreibung",
|
||||
@ -257,9 +257,9 @@
|
||||
"notifications.column_settings.show": "In der Spalte anzeigen",
|
||||
"notifications.column_settings.sound": "Ton abspielen",
|
||||
"notifications.filter.all": "Alle",
|
||||
"notifications.filter.boosts": "Boosts",
|
||||
"notifications.filter.boosts": "Erneut geteilte Beiträge",
|
||||
"notifications.filter.favourites": "Favoriten",
|
||||
"notifications.filter.follows": "Follows",
|
||||
"notifications.filter.follows": "Folgende",
|
||||
"notifications.filter.mentions": "Erwähnungen",
|
||||
"notifications.group": "{count} Benachrichtigungen",
|
||||
"privacy.change": "Sichtbarkeit des Beitrags anpassen",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Beiträge",
|
||||
"search_results.total": "{count, number} {count, plural, one {Ergebnis} other {Ergebnisse}}",
|
||||
"standalone.public_title": "Ein kleiner Einblick …",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Öffne Moderationsoberfläche für @{name}",
|
||||
"status.admin_status": "Öffne diesen Status in der Moderationsoberfläche",
|
||||
"status.block": "Blockiere @{name}",
|
||||
"status.cancel_reblog_private": "Nicht mehr teilen",
|
||||
"status.cannot_reblog": "Dieser Beitrag kann nicht geteilt werden",
|
||||
@ -322,7 +322,7 @@
|
||||
"status.reblog": "Teilen",
|
||||
"status.reblog_private": "An das eigentliche Publikum teilen",
|
||||
"status.reblogged_by": "{name} teilte",
|
||||
"status.reblogs.empty": "Diesen Beitrag hat noch niemand geboostet. Sobald es jemand tun, wird er hier angezeigt.",
|
||||
"status.reblogs.empty": "Diesen Beitrag hat noch niemand geteilt. Sobald es jemand tut, wird die Person hier angezeigt.",
|
||||
"status.redraft": "Löschen und neu erstellen",
|
||||
"status.reply": "Antworten",
|
||||
"status.replyAll": "Auf Thread antworten",
|
||||
|
@ -1988,6 +1988,43 @@
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/status/components/detailed_status.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Delete",
|
||||
"id": "confirmations.delete.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to delete this status?",
|
||||
"id": "confirmations.delete.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Delete & redraft",
|
||||
"id": "confirmations.redraft.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
|
||||
"id": "confirmations.redraft.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Block",
|
||||
"id": "confirmations.block.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Reply",
|
||||
"id": "confirmations.reply.confirm"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
|
||||
"id": "confirmations.reply.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to block {name}?",
|
||||
"id": "confirmations.block.message"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/status/containers/detailed_status_container.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Pouets",
|
||||
"search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}",
|
||||
"standalone.public_title": "Un aperçu …",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Ouvrir l'interface de modération pour @{name}",
|
||||
"status.admin_status": "Ouvrir ce statut dans l'interface de modération",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Dé-booster",
|
||||
"status.cannot_reblog": "Cette publication ne peut être boostée",
|
||||
|
@ -137,7 +137,7 @@
|
||||
"follow_request.authorize": "Autorizar",
|
||||
"follow_request.reject": "Rexeitar",
|
||||
"getting_started.developers": "Desenvolvedoras",
|
||||
"getting_started.directory": "Profile directory",
|
||||
"getting_started.directory": "Directorio do perfil",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Comezando",
|
||||
"getting_started.invite": "Convide a xente",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.total": "{count, number} {count,plural,one {result} outros {results}}",
|
||||
"standalone.public_title": "Ollada dentro...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Abrir interface de moderación para @{name}",
|
||||
"status.admin_status": "Abrir este estado na interface de moderación",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Non promover",
|
||||
"status.cannot_reblog": "Esta mensaxe non pode ser promovida",
|
||||
|
@ -137,7 +137,7 @@
|
||||
"follow_request.authorize": "許可",
|
||||
"follow_request.reject": "拒否",
|
||||
"getting_started.developers": "開発",
|
||||
"getting_started.directory": "Profile directory",
|
||||
"getting_started.directory": "ディレクトリ",
|
||||
"getting_started.documentation": "ドキュメント",
|
||||
"getting_started.heading": "スタート",
|
||||
"getting_started.invite": "招待",
|
||||
@ -262,7 +262,7 @@
|
||||
"notifications.filter.follows": "フォロー",
|
||||
"notifications.filter.mentions": "返信",
|
||||
"notifications.group": "{count} 件の通知",
|
||||
"privacy.change": "投稿のプライバシーを変更",
|
||||
"privacy.change": "公開範囲を変更",
|
||||
"privacy.direct.long": "メンションしたユーザーだけに公開",
|
||||
"privacy.direct.short": "ダイレクト",
|
||||
"privacy.private.long": "フォロワーだけに公開",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "トゥート",
|
||||
"search_results.total": "{count, number}件の結果",
|
||||
"standalone.public_title": "今こんな話をしています...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "@{name} のモデレーション画面を開く",
|
||||
"status.admin_status": "このトゥートをモデレーション画面で開く",
|
||||
"status.block": "@{name}さんをブロック",
|
||||
"status.cancel_reblog_private": "ブースト解除",
|
||||
"status.cannot_reblog": "この投稿はブーストできません",
|
||||
|
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "툿",
|
||||
"search_results.total": "{count, number}건의 결과",
|
||||
"standalone.public_title": "지금 이런 이야기를 하고 있습니다…",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "@{name}에 대한 모더레이션 인터페이스 열기",
|
||||
"status.admin_status": "모더레이션 인터페이스에서 이 게시물 열기",
|
||||
"status.block": "@{name} 차단",
|
||||
"status.cancel_reblog_private": "부스트 취소",
|
||||
"status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다",
|
||||
|
@ -118,8 +118,8 @@
|
||||
"empty_column.community": "De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de bal aan het rollen te krijgen!",
|
||||
"empty_column.direct": "Je hebt nog geen directe berichten. Wanneer je er een verzend of ontvangt, zijn deze hier te zien.",
|
||||
"empty_column.domain_blocks": "Er zijn nog geen genegeerde domeinen.",
|
||||
"empty_column.favourited_statuses": "Jij hebt nog geen favoriete toots. Wanneer je er een als favoriet markeert, valt deze hier te zien.",
|
||||
"empty_column.favourites": "Niemand heeft nog deze toot als favoriet gemarkeerd. Wanneer iemand dit doet, valt dat hier te zien.",
|
||||
"empty_column.favourited_statuses": "Jij hebt nog geen favoriete toots. Wanneer je er een aan jouw favorieten toevoegt, valt deze hier te zien.",
|
||||
"empty_column.favourites": "Niemand heeft deze toot nog aan hun favorieten toegevoegd. Wanneer iemand dit doet, valt dat hier te zien.",
|
||||
"empty_column.follow_requests": "Jij hebt nog enkel volgverzoek ontvangen. Wanneer je er eentje ontvangt, valt dat hier te zien.",
|
||||
"empty_column.hashtag": "Er is nog niks te vinden onder deze hashtag.",
|
||||
"empty_column.home": "Jij volgt nog niemand. Bezoek {public} of gebruik het zoekvenster om andere mensen te ontmoeten.",
|
||||
@ -163,7 +163,7 @@
|
||||
"introduction.federation.local.text": "Openbare toots van mensen die ook op jouw server zitten verschijnen op de lokale tijdlijn.",
|
||||
"introduction.interactions.action": "Introductie beëindigen!",
|
||||
"introduction.interactions.favourite.headline": "Favorieten",
|
||||
"introduction.interactions.favourite.text": "Je kunt door een toot als favoriet te markeren, deze voor later bewaren en de auteur laten weten dat je het leuk vond.",
|
||||
"introduction.interactions.favourite.text": "Je kunt door een toot aan jouw favorieten toe te voegen, deze voor later bewaren en de auteur laten weten dat je de toot leuk vind.",
|
||||
"introduction.interactions.reblog.headline": "Boost",
|
||||
"introduction.interactions.reblog.text": "Je kunt toots van andere mensen met jouw volgers delen door deze te boosten.",
|
||||
"introduction.interactions.reply.headline": "Reageren",
|
||||
@ -180,7 +180,7 @@
|
||||
"keyboard_shortcuts.direct": "om jouw directe berichten te tonen",
|
||||
"keyboard_shortcuts.down": "om naar beneden door de lijst te bewegen",
|
||||
"keyboard_shortcuts.enter": "om toot volledig te tonen",
|
||||
"keyboard_shortcuts.favourite": "om als favoriet te markeren",
|
||||
"keyboard_shortcuts.favourite": "om aan jouw favorieten toe te voegen",
|
||||
"keyboard_shortcuts.favourites": "om jouw lijst met favorieten te tonen",
|
||||
"keyboard_shortcuts.federated": "om de globale tijdlijn te tonen",
|
||||
"keyboard_shortcuts.heading": "Sneltoetsen",
|
||||
@ -239,7 +239,7 @@
|
||||
"navigation_bar.preferences": "Instellingen",
|
||||
"navigation_bar.public_timeline": "Globale tijdlijn",
|
||||
"navigation_bar.security": "Beveiliging",
|
||||
"notification.favourite": "{name} markeerde jouw toot als favoriet",
|
||||
"notification.favourite": "{name} voegde jouw toot als favoriet toe",
|
||||
"notification.follow": "{name} volgt jou nu",
|
||||
"notification.mention": "{name} vermeldde jou",
|
||||
"notification.reblog": "{name} boostte jouw toot",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}",
|
||||
"standalone.public_title": "Een kijkje binnenin...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Moderatie-omgeving van @{name} openen",
|
||||
"status.admin_status": "Deze toot in de moderatie-omgeving openen",
|
||||
"status.block": "Blokkeer @{name}",
|
||||
"status.cancel_reblog_private": "Niet langer boosten",
|
||||
"status.cannot_reblog": "Deze toot kan niet geboost worden",
|
||||
@ -337,7 +337,7 @@
|
||||
"status.show_thread": "Gesprek tonen",
|
||||
"status.unmute_conversation": "Gesprek niet langer negeren",
|
||||
"status.unpin": "Van profielpagina losmaken",
|
||||
"suggestions.dismiss": "Suggestie verwerpen",
|
||||
"suggestions.dismiss": "Voorstel verwerpen",
|
||||
"suggestions.header": "Je bent waarschijnlijk ook geïnteresseerd in…",
|
||||
"tabs_bar.federated_timeline": "Globaal",
|
||||
"tabs_bar.home": "Start",
|
||||
|
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Tuts",
|
||||
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
|
||||
"standalone.public_title": "Una ulhada dedins…",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Dobrir l’interfàcia de moderacion per @{name}",
|
||||
"status.admin_status": "Dobrir aqueste estatut dins l’interfàcia de moderacion",
|
||||
"status.block": "Blocar @{name}",
|
||||
"status.cancel_reblog_private": "Quitar de partejar",
|
||||
"status.cannot_reblog": "Aqueste estatut pòt pas èsser partejat",
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"account.add_or_remove_from_list": "Add or Remove from lists",
|
||||
"account.add_or_remove_from_list": "Dodaj lub usuń z list",
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Blokuj @{name}",
|
||||
"account.block_domain": "Blokuj wszystko z {domain}",
|
||||
@ -113,7 +113,7 @@
|
||||
"emoji_button.search_results": "Wyniki wyszukiwania",
|
||||
"emoji_button.symbols": "Symbole",
|
||||
"emoji_button.travel": "Podróże i miejsca",
|
||||
"empty_column.account_timeline": "No toots here!",
|
||||
"empty_column.account_timeline": "Brak wpisów tutaj!",
|
||||
"empty_column.blocks": "Nie zablokowałeś(-aś) jeszcze żadnego użytkownika.",
|
||||
"empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!",
|
||||
"empty_column.direct": "Nie masz żadnych wiadomości bezpośrednich. Kiedy dostaniesz lub wyślesz jakąś, pojawi się ona tutaj.",
|
||||
@ -137,19 +137,19 @@
|
||||
"follow_request.authorize": "Autoryzuj",
|
||||
"follow_request.reject": "Odrzuć",
|
||||
"getting_started.developers": "Dla programistów",
|
||||
"getting_started.directory": "Profile directory",
|
||||
"getting_started.directory": "Katalog profilów",
|
||||
"getting_started.documentation": "Dokumentacja",
|
||||
"getting_started.heading": "Rozpocznij",
|
||||
"getting_started.invite": "Zaproś znajomych",
|
||||
"getting_started.open_source_notice": "Mastodon jest oprogramowaniem o otwartym źródle. Możesz pomóc w rozwoju lub zgłaszać błędy na GitHubie tutaj: {github}.",
|
||||
"getting_started.security": "Bezpieczeństwo",
|
||||
"getting_started.terms": "Zasady użytkowania",
|
||||
"hashtag.column_header.tag_mode.all": "and {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "or {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "without {additional}",
|
||||
"hashtag.column_settings.tag_mode.all": "All of these",
|
||||
"hashtag.column_settings.tag_mode.any": "Any of these",
|
||||
"hashtag.column_settings.tag_mode.none": "None of these",
|
||||
"hashtag.column_header.tag_mode.all": "i {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "lub {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "bez {additional}",
|
||||
"hashtag.column_settings.tag_mode.all": "Wszystkie",
|
||||
"hashtag.column_settings.tag_mode.any": "Dowolne",
|
||||
"hashtag.column_settings.tag_mode.none": "Żadne",
|
||||
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
|
||||
"home.column_settings.basic": "Podstawowe",
|
||||
"home.column_settings.show_reblogs": "Pokazuj podbicia",
|
||||
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Wpisy",
|
||||
"search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}",
|
||||
"standalone.public_title": "Spojrzenie w głąb…",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Otwórz interfejs moderacyjny dla @{name}",
|
||||
"status.admin_status": "Otwórz ten wpis w interfejsie moderacyjnym",
|
||||
"status.block": "Zablokuj @{name}",
|
||||
"status.cancel_reblog_private": "Cofnij podbicie",
|
||||
"status.cannot_reblog": "Ten wpis nie może zostać podbity",
|
||||
@ -334,11 +334,11 @@
|
||||
"status.show_less_all": "Zwiń wszystkie",
|
||||
"status.show_more": "Rozwiń",
|
||||
"status.show_more_all": "Rozwiń wszystkie",
|
||||
"status.show_thread": "Show thread",
|
||||
"status.show_thread": "Pokaż wątek",
|
||||
"status.unmute_conversation": "Cofnij wyciszenie konwersacji",
|
||||
"status.unpin": "Odepnij z profilu",
|
||||
"suggestions.dismiss": "Dismiss suggestion",
|
||||
"suggestions.header": "You might be interested in…",
|
||||
"suggestions.dismiss": "Odrzuć sugestię",
|
||||
"suggestions.header": "Może Cię zainteresować…",
|
||||
"tabs_bar.federated_timeline": "Globalne",
|
||||
"tabs_bar.home": "Strona główna",
|
||||
"tabs_bar.local_timeline": "Lokalne",
|
||||
@ -349,7 +349,7 @@
|
||||
"upload_area.title": "Przeciągnij i upuść aby wysłać",
|
||||
"upload_button.label": "Dodaj zawartość multimedialną (JPEG, PNG, GIF, WebM, MP4, MOV)",
|
||||
"upload_form.description": "Wprowadź opis dla niewidomych i niedowidzących",
|
||||
"upload_form.focus": "Przytnij",
|
||||
"upload_form.focus": "Dopasuj podgląd",
|
||||
"upload_form.undo": "Usuń",
|
||||
"upload_progress.label": "Wysyłanie...",
|
||||
"video.close": "Zamknij film",
|
||||
|
@ -297,8 +297,8 @@
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
|
||||
"standalone.public_title": "Dê uma espiada...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Abrir interface de moderação para @{name}",
|
||||
"status.admin_status": "Abrir esse status na interface de moderação",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Desfazer compartilhamento",
|
||||
"status.cannot_reblog": "Esta postagem não pode ser compartilhada",
|
||||
|
@ -137,7 +137,7 @@
|
||||
"follow_request.authorize": "Autorizează",
|
||||
"follow_request.reject": "Respinge",
|
||||
"getting_started.developers": "Dezvoltatori",
|
||||
"getting_started.directory": "Directorul profilului",
|
||||
"getting_started.directory": "Explorează",
|
||||
"getting_started.documentation": "Documentație",
|
||||
"getting_started.heading": "Începe",
|
||||
"getting_started.invite": "Invită prieteni",
|
||||
|
@ -24,8 +24,8 @@
|
||||
"account.mute": "Ignorovať @{name}",
|
||||
"account.mute_notifications": "Stĺmiť oboznámenia od @{name}",
|
||||
"account.muted": "Utíšený/á",
|
||||
"account.posts": "Hlášky",
|
||||
"account.posts_with_replies": "Hlášky s odpoveďami",
|
||||
"account.posts": "Príspevky",
|
||||
"account.posts_with_replies": "Príspevky aj s odpoveďami",
|
||||
"account.report": "Nahlás @{name}",
|
||||
"account.requested": "Čaká na schválenie. Kliknite pre zrušenie žiadosti",
|
||||
"account.share": "Zdieľať @{name} profil",
|
||||
@ -56,7 +56,7 @@
|
||||
"column.lists": "Zoznamy",
|
||||
"column.mutes": "Ignorovaní užívatelia",
|
||||
"column.notifications": "Oboznámenia",
|
||||
"column.pins": "Pripnuté hlášky",
|
||||
"column.pins": "Pripnuté príspevky",
|
||||
"column.public": "Federovaná časová os",
|
||||
"column_back_button.label": "Späť",
|
||||
"column_header.hide_settings": "Skryť nastavenia",
|
||||
@ -70,7 +70,7 @@
|
||||
"compose_form.direct_message_warning": "Tento príspevok bude videný výhradne iba spomenutými užívateľmi. Ber ale na vedomie že správci tvojej a všetkých iných zahrnutých instancií majú možnosť skontrolovať túto správu.",
|
||||
"compose_form.direct_message_warning_learn_more": "Zistiť viac",
|
||||
"compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.",
|
||||
"compose_form.lock_disclaimer": "Váš účet nie je zamknutý. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
|
||||
"compose_form.lock_disclaimer": "Váš účet nie je {locked}. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
|
||||
"compose_form.lock_disclaimer.lock": "zamknutý",
|
||||
"compose_form.placeholder": "Čo máš na mysli?",
|
||||
"compose_form.publish": "Pošli",
|
||||
@ -208,8 +208,8 @@
|
||||
"lists.account.add": "Pridať do zoznamu",
|
||||
"lists.account.remove": "Odobrať zo zoznamu",
|
||||
"lists.delete": "Vymazať list",
|
||||
"lists.edit": "Upraviť zoznam",
|
||||
"lists.new.create": "Pridať zoznam",
|
||||
"lists.edit": "Uprav zoznam",
|
||||
"lists.new.create": "Pridaj zoznam",
|
||||
"lists.new.title_placeholder": "Názov nového zoznamu",
|
||||
"lists.search": "Vyhľadávajte medzi užívateľmi ktorých sledujete",
|
||||
"lists.subheading": "Tvoje zoznamy",
|
||||
@ -225,7 +225,7 @@
|
||||
"navigation_bar.direct": "Súkromné správy",
|
||||
"navigation_bar.discover": "Objavuj",
|
||||
"navigation_bar.domain_blocks": "Skryté domény",
|
||||
"navigation_bar.edit_profile": "Upraviť profil",
|
||||
"navigation_bar.edit_profile": "Uprav profil",
|
||||
"navigation_bar.favourites": "Obľúbené",
|
||||
"navigation_bar.filters": "Utĺmené slová",
|
||||
"navigation_bar.follow_requests": "Žiadosti o sledovanie",
|
||||
@ -294,11 +294,11 @@
|
||||
"search_popout.tips.user": "používateľ",
|
||||
"search_results.accounts": "Ľudia",
|
||||
"search_results.hashtags": "Haštagy",
|
||||
"search_results.statuses": "Hlášky",
|
||||
"search_results.statuses": "Príspevky",
|
||||
"search_results.total": "{count, number} {count, plural, one {výsledok} many {výsledkov} other {výsledky}}",
|
||||
"standalone.public_title": "Náhľad dovnútra...",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.admin_account": "Otvor moderovacie rozhranie užívateľa @{name}",
|
||||
"status.admin_status": "Otvor tento príspevok v moderovacom rozhraní",
|
||||
"status.block": "Blokovať @{name}",
|
||||
"status.cancel_reblog_private": "Nezdieľaj",
|
||||
"status.cannot_reblog": "Tento príspevok nemôže byť re-tootnutý",
|
||||
|
@ -92,11 +92,14 @@ const handlePush = (event) => {
|
||||
options.image = notification.status && notification.status.media_attachments.length > 0 && notification.status.media_attachments[0].preview_url || undefined;
|
||||
options.data = { access_token, preferred_locale, id: notification.status ? notification.status.id : notification.account.id, url: notification.status ? `/web/statuses/${notification.status.id}` : `/web/accounts/${notification.account.id}` };
|
||||
|
||||
if (notification.status && notification.status.sensitive) {
|
||||
if (notification.status && notification.status.spoiler_text || notification.status.sensitive) {
|
||||
options.data.hiddenBody = htmlToPlainText(notification.status.content);
|
||||
options.data.hiddenImage = notification.status.media_attachments.length > 0 && notification.status.media_attachments[0].preview_url;
|
||||
|
||||
options.body = notification.status.spoiler_text;
|
||||
if (notification.status.spoiler_text) {
|
||||
options.body = notification.status.spoiler_text;
|
||||
}
|
||||
|
||||
options.image = undefined;
|
||||
options.actions = [actionExpand(preferred_locale)];
|
||||
} else if (notification.type === 'mention') {
|
||||
|
@ -33,6 +33,17 @@ function main() {
|
||||
const Rellax = require('rellax');
|
||||
const createHistory = require('history').createBrowserHistory;
|
||||
|
||||
const scrollToDetailedStatus = () => {
|
||||
const history = createHistory();
|
||||
const detailedStatuses = document.querySelectorAll('.public-layout .detailed-status');
|
||||
const location = history.location;
|
||||
|
||||
if (detailedStatuses.length === 1 && (!location.state || !location.state.scrolledToDetailedStatus)) {
|
||||
detailedStatuses[0].scrollIntoView();
|
||||
history.replace(location.pathname, { ...location.state, scrolledToDetailedStatus: true });
|
||||
}
|
||||
};
|
||||
|
||||
ready(() => {
|
||||
const locale = document.documentElement.lang;
|
||||
|
||||
@ -72,12 +83,24 @@ function main() {
|
||||
if (reactComponents.length > 0) {
|
||||
import(/* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container')
|
||||
.then(({ default: MediaContainer }) => {
|
||||
[].forEach.call(reactComponents, (component) => {
|
||||
[].forEach.call(component.children, (child) => {
|
||||
component.removeChild(child);
|
||||
});
|
||||
});
|
||||
|
||||
const content = document.createElement('div');
|
||||
|
||||
ReactDOM.render(<MediaContainer locale={locale} components={reactComponents} />, content);
|
||||
document.body.appendChild(content);
|
||||
scrollToDetailedStatus();
|
||||
})
|
||||
.catch(error => console.error(error));
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
scrollToDetailedStatus();
|
||||
});
|
||||
} else {
|
||||
scrollToDetailedStatus();
|
||||
}
|
||||
|
||||
const parallaxComponents = document.querySelectorAll('.parallax');
|
||||
@ -86,13 +109,12 @@ function main() {
|
||||
new Rellax('.parallax', { speed: -1 });
|
||||
}
|
||||
|
||||
const history = createHistory();
|
||||
const detailedStatuses = document.querySelectorAll('.public-layout .detailed-status');
|
||||
const location = history.location;
|
||||
|
||||
if (detailedStatuses.length === 1 && (!location.state || !location.state.scrolledToDetailedStatus)) {
|
||||
detailedStatuses[0].scrollIntoView();
|
||||
history.replace(location.pathname, { ...location.state, scrolledToDetailedStatus: true });
|
||||
if (document.body.classList.contains('with-modals')) {
|
||||
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
||||
const scrollbarWidthStyle = document.createElement('style');
|
||||
scrollbarWidthStyle.id = 'scrollbar-width';
|
||||
document.head.appendChild(scrollbarWidthStyle);
|
||||
scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -364,7 +364,7 @@ $small-breakpoint: 960px;
|
||||
|
||||
@media screen and (max-width: $column-breakpoint) {
|
||||
.grid {
|
||||
grid-template-columns: auto;
|
||||
grid-template-columns: 100%;
|
||||
|
||||
.column-0 {
|
||||
display: block;
|
||||
@ -1267,8 +1267,7 @@ $small-breakpoint: 960px;
|
||||
}
|
||||
|
||||
#mastodon-timeline {
|
||||
display: block;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
$no-columns-breakpoint: 600px;
|
||||
$sidebar-width: 240px;
|
||||
$content-width: 840px;
|
||||
|
||||
.admin-wrapper {
|
||||
display: flex;
|
||||
@ -6,7 +8,7 @@ $no-columns-breakpoint: 600px;
|
||||
height: 100%;
|
||||
|
||||
.sidebar-wrapper {
|
||||
flex: 1;
|
||||
flex: 1 1 $sidebar-width;
|
||||
height: 100%;
|
||||
background: $ui-base-color;
|
||||
display: flex;
|
||||
@ -14,7 +16,7 @@ $no-columns-breakpoint: 600px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 240px;
|
||||
width: $sidebar-width;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
@ -95,12 +97,12 @@ $no-columns-breakpoint: 600px;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 2;
|
||||
flex: 2 1 $content-width;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 700px;
|
||||
max-width: $content-width;
|
||||
padding: 20px 15px;
|
||||
padding-top: 60px;
|
||||
padding-left: 25px;
|
||||
|
@ -295,7 +295,7 @@
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
@media screen and (max-width: 550px) {
|
||||
&.optional {
|
||||
display: none;
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ code {
|
||||
background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") no-repeat right 8px center / auto 16px;
|
||||
border: 1px solid darken($ui-base-color, 14%);
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 30px;
|
||||
height: 41px;
|
||||
}
|
||||
|
@ -425,3 +425,93 @@
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
$maximum-width: 1235px;
|
||||
$fluid-breakpoint: $maximum-width + 20px;
|
||||
|
||||
.statuses-grid {
|
||||
min-height: 600px;
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
width: 100% !important; // Masonry layout is unnecessary at this width
|
||||
}
|
||||
|
||||
&__item {
|
||||
width: (960px - 20px) / 3;
|
||||
|
||||
@media screen and (max-width: $fluid-breakpoint) {
|
||||
width: (940px - 20px) / 3;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.detailed-status {
|
||||
border-radius: 4px;
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
border-top: 1px solid lighten($ui-base-color, 16%);
|
||||
}
|
||||
|
||||
&.compact {
|
||||
.detailed-status__meta {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.status__content {
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
|
||||
.emojione {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: -3px 0 0;
|
||||
}
|
||||
|
||||
.status__content__spoiler-link {
|
||||
line-height: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.media-gallery,
|
||||
.status-card,
|
||||
.video-player {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notice-widget {
|
||||
margin-bottom: 10px;
|
||||
color: $darker-text-color;
|
||||
|
||||
p {
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
color: $ui-highlight-color;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
|
||||
uri: @json['id'],
|
||||
created_at: @json['published'],
|
||||
override_timestamps: @options[:override_timestamps],
|
||||
visibility: original_status.visibility
|
||||
visibility: visibility_from_audience
|
||||
)
|
||||
|
||||
distribute(status)
|
||||
@ -26,6 +26,18 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
|
||||
|
||||
private
|
||||
|
||||
def visibility_from_audience
|
||||
if equals_or_includes?(@json['to'], ActivityPub::TagManager::COLLECTIONS[:public])
|
||||
:public
|
||||
elsif equals_or_includes?(@json['cc'], ActivityPub::TagManager::COLLECTIONS[:public])
|
||||
:unlisted
|
||||
elsif equals_or_includes?(@json['to'], @account.followers_url)
|
||||
:private
|
||||
else
|
||||
:direct
|
||||
end
|
||||
end
|
||||
|
||||
def announceable?(status)
|
||||
status.account_id == @account.id || status.public_visibility? || status.unlisted_visibility?
|
||||
end
|
||||
|
@ -5,10 +5,13 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
CONVERTED_TYPES = %w(Image Video Article Page).freeze
|
||||
|
||||
def perform
|
||||
return if delete_arrived_first?(object_uri) || unsupported_object_type? || invalid_origin?(@object['id'])
|
||||
return if unsupported_object_type? || invalid_origin?(@object['id'])
|
||||
return if Tombstone.exists?(uri: @object['id'])
|
||||
|
||||
RedisLock.acquire(lock_options) do |lock|
|
||||
if lock.acquired?
|
||||
return if delete_arrived_first?(object_uri)
|
||||
|
||||
@status = find_existing_status
|
||||
|
||||
if @status.nil?
|
||||
@ -59,7 +62,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
account: @account,
|
||||
text: text_from_content || '',
|
||||
language: detected_language,
|
||||
spoiler_text: text_from_summary || '',
|
||||
spoiler_text: converted_object_type? ? '' : (text_from_summary || ''),
|
||||
created_at: @object['published'],
|
||||
override_timestamps: @options[:override_timestamps],
|
||||
reply: @object['inReplyTo'].present?,
|
||||
@ -254,7 +257,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
end
|
||||
|
||||
def text_from_content
|
||||
return Formatter.instance.linkify([text_from_name, object_url || @object['id']].join(' ')) if converted_object_type?
|
||||
return Formatter.instance.linkify([[text_from_name, text_from_summary.presence].compact.join("\n\n"), object_url || @object['id']].join(' ')) if converted_object_type?
|
||||
|
||||
if @object['content'].present?
|
||||
@object['content']
|
||||
|
@ -21,11 +21,14 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
|
||||
def delete_note
|
||||
return if object_uri.nil?
|
||||
|
||||
unless invalid_origin?(object_uri)
|
||||
RedisLock.acquire(lock_options) { |_lock| delete_later!(object_uri) }
|
||||
Tombstone.find_or_create_by(uri: object_uri, account: @account)
|
||||
end
|
||||
|
||||
@status = Status.find_by(uri: object_uri, account: @account)
|
||||
@status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
|
||||
|
||||
delete_later!(object_uri)
|
||||
|
||||
return if @status.nil?
|
||||
|
||||
if @status.public_visibility? || @status.unlisted_visibility?
|
||||
@ -68,4 +71,17 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
|
||||
def payload
|
||||
@payload ||= Oj.dump(@json)
|
||||
end
|
||||
|
||||
def lock_options
|
||||
{ redis: Redis.current, key: "create:#{object_uri}" }
|
||||
end
|
||||
|
||||
def invalid_origin?(url)
|
||||
return true if unsupported_uri_scheme?(url)
|
||||
|
||||
needle = Addressable::URI.parse(url).host
|
||||
haystack = Addressable::URI.parse(@account.uri).host
|
||||
|
||||
!haystack.casecmp(needle).zero?
|
||||
end
|
||||
end
|
||||
|
@ -490,7 +490,7 @@ class Status < ApplicationRecord
|
||||
return if direct_visibility?
|
||||
|
||||
account&.increment_count!(:statuses_count)
|
||||
reblog&.increment_count!(:reblogs_count) if reblog?
|
||||
reblog&.increment_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
|
||||
thread&.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
|
||||
end
|
||||
|
||||
@ -498,7 +498,7 @@ class Status < ApplicationRecord
|
||||
return if direct_visibility? || marked_for_mass_destruction?
|
||||
|
||||
account&.decrement_count!(:statuses_count)
|
||||
reblog&.decrement_count!(:reblogs_count) if reblog?
|
||||
reblog&.decrement_count!(:reblogs_count) if reblog? && (public_visibility? || unlisted_visibility?)
|
||||
thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?)
|
||||
end
|
||||
|
||||
|
16
app/models/tombstone.rb
Normal file
16
app/models/tombstone.rb
Normal file
@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: tombstones
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# account_id :bigint(8)
|
||||
# uri :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
||||
class Tombstone < ApplicationRecord
|
||||
belongs_to :account
|
||||
end
|
@ -362,7 +362,8 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
def regenerate_feed!
|
||||
Redis.current.setnx("account:#{account_id}:regeneration", true) && Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds)
|
||||
return unless Redis.current.setnx("account:#{account_id}:regeneration", true)
|
||||
Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds)
|
||||
RegenerationWorker.perform_async(account_id)
|
||||
end
|
||||
|
||||
|
@ -33,6 +33,8 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||
|
||||
after_protocol_change! if protocol_changed?
|
||||
after_key_change! if key_changed? && !@options[:signed_with_known_key]
|
||||
clear_tombstones! if key_changed?
|
||||
|
||||
unless @options[:only_key]
|
||||
check_featured_collection! if @account.featured_collection_url.present?
|
||||
check_links! unless @account.fields.empty?
|
||||
@ -209,6 +211,10 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||
!@old_public_key.nil? && @old_public_key != @account.public_key
|
||||
end
|
||||
|
||||
def clear_tombstones!
|
||||
Tombstone.delete_all(account_id: @account.id)
|
||||
end
|
||||
|
||||
def protocol_changed?
|
||||
!@old_protocol.nil? && @old_protocol != @account.protocol
|
||||
end
|
||||
|
@ -43,7 +43,7 @@ class FetchOEmbedService
|
||||
res.code != 200 ? nil : res.body_with_limit
|
||||
end
|
||||
|
||||
validate(parse_for_format(body)) unless body.nil?
|
||||
validate(parse_for_format(body)) if body.present?
|
||||
rescue Oj::ParseError, Ox::ParseError
|
||||
nil
|
||||
end
|
||||
|
@ -49,6 +49,8 @@ class PostStatusService < BaseService
|
||||
@visibility = :unlisted if @visibility == :public && @account.silenced
|
||||
@scheduled_at = @options[:scheduled_at]&.to_datetime
|
||||
@scheduled_at = nil if scheduled_in_the_past?
|
||||
rescue ArgumentError
|
||||
raise ActiveRecord::RecordInvalid
|
||||
end
|
||||
|
||||
def process_status!
|
||||
|
@ -3,6 +3,7 @@
|
||||
class PrecomputeFeedService < BaseService
|
||||
def call(account)
|
||||
FeedManager.instance.populate_feed(account)
|
||||
ensure
|
||||
Redis.current.del("account:#{account.id}:regeneration")
|
||||
end
|
||||
end
|
||||
|
@ -20,6 +20,7 @@ class UnfollowService < BaseService
|
||||
|
||||
follow.destroy!
|
||||
create_notification(follow) unless @target_account.local?
|
||||
create_reject_notification(follow) if @target_account.local? && !@source_account.local?
|
||||
UnmergeWorker.perform_async(@target_account.id, @source_account.id)
|
||||
follow
|
||||
end
|
||||
@ -42,6 +43,12 @@ class UnfollowService < BaseService
|
||||
end
|
||||
end
|
||||
|
||||
def create_reject_notification(follow)
|
||||
# Rejecting an already-existing follow request
|
||||
return unless follow.account.activitypub?
|
||||
ActivityPub::DeliveryWorker.perform_async(build_reject_json(follow), follow.target_account_id, follow.account.inbox_url)
|
||||
end
|
||||
|
||||
def build_json(follow)
|
||||
ActiveModelSerializers::SerializableResource.new(
|
||||
follow,
|
||||
@ -50,6 +57,14 @@ class UnfollowService < BaseService
|
||||
).to_json
|
||||
end
|
||||
|
||||
def build_reject_json(follow)
|
||||
ActiveModelSerializers::SerializableResource.new(
|
||||
follow,
|
||||
serializer: ActivityPub::RejectFollowSerializer,
|
||||
adapter: ActivityPub::Adapter
|
||||
).to_json
|
||||
end
|
||||
|
||||
def build_xml(follow)
|
||||
OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfollow_salmon(follow))
|
||||
end
|
||||
|
@ -41,8 +41,22 @@
|
||||
= paginate @accounts
|
||||
|
||||
.column-1
|
||||
- if @tags.empty?
|
||||
.nothing-here.nothing-here--flexible
|
||||
- if user_signed_in?
|
||||
.box-widget.notice-widget
|
||||
- if current_account.discoverable?
|
||||
- if current_account.followers_count < Account::MIN_FOLLOWERS_DISCOVERY
|
||||
%p= t('directories.enabled_but_waiting', min_followers: Account::MIN_FOLLOWERS_DISCOVERY)
|
||||
- else
|
||||
%p= t('directories.enabled')
|
||||
- else
|
||||
%p= t('directories.how_to_enable')
|
||||
|
||||
= link_to settings_profile_path do
|
||||
= t('settings.edit_profile')
|
||||
= fa_icon 'chevron-right fw'
|
||||
|
||||
- if @tags.empty? && !user_signed_in?
|
||||
.nothing-here
|
||||
- else
|
||||
- @tags.each do |tag|
|
||||
.directory__tag{ class: tag.id == @tag&.id ? 'active' : nil }
|
||||
|
8
app/views/stream_entries/_attachment_list.html.haml
Normal file
8
app/views/stream_entries/_attachment_list.html.haml
Normal file
@ -0,0 +1,8 @@
|
||||
.attachment-list
|
||||
.attachment-list__icon
|
||||
= fa_icon 'link'
|
||||
%ul.attachment-list__list
|
||||
- attachments.each do |media|
|
||||
%li
|
||||
- url = media.remote_url.presence || media.file.url
|
||||
= link_to File.basename(url), url, title: media.description
|
@ -25,9 +25,11 @@
|
||||
- if !status.media_attachments.empty?
|
||||
- if status.media_attachments.first.video?
|
||||
- video = status.media_attachments.first
|
||||
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description
|
||||
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description do
|
||||
= render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
|
||||
- else
|
||||
= react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
|
||||
= react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do
|
||||
= render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
|
||||
- elsif status.preview_card
|
||||
= react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json
|
||||
|
||||
@ -44,7 +46,10 @@
|
||||
= link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener'
|
||||
·
|
||||
= link_to remote_interaction_path(status, type: :reply), class: 'modal-button detailed-status__link' do
|
||||
= fa_icon('reply')
|
||||
- if status.in_reply_to_id.nil?
|
||||
= fa_icon('reply')
|
||||
- else
|
||||
= fa_icon('reply-all')
|
||||
%span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true
|
||||
= " "
|
||||
·
|
||||
|
@ -29,16 +29,21 @@
|
||||
- if !status.media_attachments.empty?
|
||||
- if status.media_attachments.first.video?
|
||||
- video = status.media_attachments.first
|
||||
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description
|
||||
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description do
|
||||
= render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
|
||||
- else
|
||||
= react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
|
||||
= react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do
|
||||
= render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments }
|
||||
- elsif status.preview_card
|
||||
= react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json
|
||||
|
||||
.status__action-bar
|
||||
.status__action-bar__counter
|
||||
= link_to remote_interaction_path(status, type: :reply), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do
|
||||
= fa_icon 'reply fw'
|
||||
- if status.in_reply_to_id.nil?
|
||||
= fa_icon 'reply fw'
|
||||
- else
|
||||
= fa_icon 'reply-all fw'
|
||||
.status__action-bar__counter__label= obscured_counter status.replies_count
|
||||
= link_to remote_interaction_path(status, type: :reblog), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do
|
||||
- if status.public_visibility? || status.unlisted_visibility?
|
||||
|
@ -1,25 +0,0 @@
|
||||
.features-list
|
||||
.features-list__row
|
||||
.text
|
||||
%h6= t 'about.features.real_conversation_title'
|
||||
= t 'about.features.real_conversation_body'
|
||||
.visual
|
||||
= fa_icon 'fw comments'
|
||||
.features-list__row
|
||||
.text
|
||||
%h6= t 'about.features.not_a_product_title'
|
||||
= t 'about.features.not_a_product_body'
|
||||
.visual
|
||||
= fa_icon 'fw users'
|
||||
.features-list__row
|
||||
.text
|
||||
%h6= t 'about.features.within_reach_title'
|
||||
= t 'about.features.within_reach_body'
|
||||
.visual
|
||||
= fa_icon 'fw mobile'
|
||||
.features-list__row
|
||||
.text
|
||||
%h6= t 'about.features.humane_approach_title'
|
||||
= t 'about.features.humane_approach_body'
|
||||
.visual
|
||||
= fa_icon 'fw leaf'
|
@ -8,33 +8,9 @@
|
||||
= javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous'
|
||||
= render 'og'
|
||||
|
||||
.landing-page.tag-page.alternative
|
||||
.features
|
||||
.container
|
||||
.grid
|
||||
.column-1
|
||||
#mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name)) } }
|
||||
|
||||
.column-2
|
||||
.about-mastodon
|
||||
.about-hashtag.landing-page__information
|
||||
.brand
|
||||
= link_to root_url do
|
||||
= image_tag asset_pack_path('logo_full.svg'), alt: 'Mastodon'
|
||||
|
||||
%p= t 'about.about_hashtag_html', hashtag: @tag.name
|
||||
|
||||
.cta
|
||||
- if user_signed_in?
|
||||
= link_to t('settings.back'), root_path, class: 'button button-secondary'
|
||||
- else
|
||||
= link_to t('auth.login'), new_user_session_path, class: 'button button-secondary'
|
||||
= link_to t('about.learn_more'), about_path, class: 'button button-alternative'
|
||||
|
||||
.landing-page__features.landing-page__information
|
||||
%h3= t 'about.what_is_mastodon'
|
||||
%p= t 'about.about_mastodon_html'
|
||||
|
||||
= render 'features'
|
||||
.page-header
|
||||
%h1= "##{@tag.name}"
|
||||
%p= t('about.about_hashtag_html', hashtag: @tag.name)
|
||||
|
||||
#mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name)) }}
|
||||
#modal-container
|
||||
|
@ -3,6 +3,8 @@
|
||||
class PublishScheduledStatusWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options unique: :until_executed
|
||||
|
||||
def perform(scheduled_status_id)
|
||||
scheduled_status = ScheduledStatus.find(scheduled_status_id)
|
||||
scheduled_status.destroy!
|
||||
|
Reference in New Issue
Block a user