Merge branch 'master' into glitch-soc/merge-upstream
No conflicts.
This commit is contained in:
@ -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 (
|
||||
|
@ -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 { FormattedDate, FormattedNumber } from 'react-intl';
|
||||
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';
|
||||
|
||||
export default class DetailedStatus extends ImmutablePureComponent {
|
||||
|
||||
@ -23,10 +25,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'])}`);
|
||||
}
|
||||
@ -42,13 +52,57 @@ 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 outerStyle = { boxSizing: 'border-box' };
|
||||
const { compact } = this.props;
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let media = '';
|
||||
let applicationLink = '';
|
||||
let reblogLink = '';
|
||||
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')) {
|
||||
@ -95,35 +149,63 @@ 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 (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>
|
||||
);
|
||||
}
|
||||
|
||||
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')} />
|
||||
</a>
|
||||
<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>
|
||||
|
||||
<StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
|
||||
<StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
|
||||
|
||||
{media}
|
||||
{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} · <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>
|
||||
<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}
|
||||
</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,6 +257,7 @@ class UI extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleDrop = (e) => {
|
||||
if (this.dataTransferIsText(e.dataTransfer)) return;
|
||||
e.preventDefault();
|
||||
|
||||
this.setState({ draggingOver: false });
|
||||
@ -279,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 });
|
||||
}
|
||||
|
@ -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.",
|
||||
|
@ -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",
|
||||
@ -169,12 +169,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",
|
||||
@ -234,10 +234,10 @@
|
||||
"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",
|
||||
@ -257,7 +257,7 @@
|
||||
"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",
|
||||
@ -284,7 +284,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",
|
||||
@ -293,7 +293,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",
|
||||
@ -309,7 +309,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",
|
||||
|
@ -1950,6 +1950,43 @@
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/status/components/action_bar.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": [
|
||||
{
|
||||
|
@ -132,7 +132,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",
|
||||
|
@ -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",
|
||||
|
Reference in New Issue
Block a user