Merge tag 'v1.0.5+3.2.0' into hometown-v1.0.5+3.3.0

This commit is contained in:
Darius Kazemi
2021-04-22 16:37:11 -07:00
126 changed files with 2708 additions and 366 deletions

View File

@ -38,7 +38,7 @@ const messages = defineMessages({
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' },
disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },

View File

@ -123,8 +123,8 @@ export default class Header extends ImmutablePureComponent {
{!hideTabs && (
<div className='account__section-headline'>
<NavLink exact to={`/accounts/${account.get('id')}`}><FormattedMessage id='account.posts' defaultMessage='Toots' /></NavLink>
<NavLink exact to={`/accounts/${account.get('id')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Toots and replies' /></NavLink>
<NavLink exact to={`/accounts/${account.get('id')}`}><FormattedMessage id='account.posts' defaultMessage='Posts' /></NavLink>
<NavLink exact to={`/accounts/${account.get('id')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Posts and replies' /></NavLink>
<NavLink exact to={`/accounts/${account.get('id')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>
</div>
)}

View File

@ -37,7 +37,7 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
};
const RemoteHint = ({ url }) => (
<TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.statuses' defaultMessage='Older toots' />} />
<TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.statuses' defaultMessage='Older posts' />} />
);
RemoteHint.propTypes = {
@ -143,7 +143,7 @@ class AccountTimeline extends ImmutablePureComponent {
} else if (remote && statusIds.isEmpty()) {
emptyMessage = <RemoteHint url={remoteUrl} />;
} else {
emptyMessage = <FormattedMessage id='empty_column.account_timeline' defaultMessage='No toots here!' />;
emptyMessage = <FormattedMessage id='empty_column.account_timeline' defaultMessage='No posts here!' />;
}
const remoteMessage = remote ? <RemoteHint url={remoteUrl} /> : null;

View File

@ -6,7 +6,7 @@ import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },

View File

@ -21,13 +21,14 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz';
import { countableText } from '../util/counter';
import Icon from 'mastodon/components/icon';
import { maxChars } from '../../../initial_state';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
const messages = defineMessages({
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
publish: { id: 'compose_form.publish', defaultMessage: 'Post' },
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
});
@ -88,7 +89,7 @@ class ComposeForm extends ImmutablePureComponent {
const fulltext = this.getFulltextForCharacterCounting();
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia));
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxChars || (isOnlyWhitespace && !anyMedia));
}
handleSubmit = () => {
@ -252,7 +253,7 @@ class ComposeForm extends ImmutablePureComponent {
<SpoilerButtonContainer />
<FederationDropdownContainer />
</div>
<div className='character-counter__wrapper'><CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} /></div>
<div className='character-counter__wrapper'><CharacterCounter max={maxChars} text={this.getFulltextForCharacterCounting()} /></div>
</div>
<div className='compose-form__publish'>

View File

@ -359,11 +359,11 @@ class EmojiPickerDropdown extends React.PureComponent {
return (
<div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
{button || <img
<img
className={classNames('emojione', { 'pulse-loading': active && loading })}
alt='🙂'
src={`${assetHost}/emoji/1f602.svg`}
/>}
src={`${assetHost}/emoji/1f600.svg`}
/>
</div>
<Overlay show={active} placement={placement} target={this.findTarget}>

View File

@ -10,9 +10,9 @@ import classNames from 'classnames';
const messages = defineMessages({
federate_short: { id: 'federation.federated.short', defaultMessage: 'Federated' },
federate_long: { id: 'federation.federated.long', defaultMessage: 'Allow toot to reach other instances' },
federate_long: { id: 'federation.federated.long', defaultMessage: 'Allow post to reach other instances' },
local_only_short: { id: 'federation.local_only.short', defaultMessage: 'Local-only' },
local_only_long: { id: 'federation.local_only.long', defaultMessage: 'Restrict this toot only to my instance' },
local_only_long: { id: 'federation.local_only.long', defaultMessage: 'Restrict this post only to my instance' },
change_federation: { id: 'federation.change', defaultMessage: 'Adjust status federation' },
});

View File

@ -85,7 +85,7 @@ class SearchResults extends ImmutablePureComponent {
count += results.get('statuses').size;
statuses = (
<div className='search-results__section'>
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></h5>
{results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}
@ -95,10 +95,10 @@ class SearchResults extends ImmutablePureComponent {
} else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
statuses = (
<div className='search-results__section'>
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></h5>
<div className='search-results__info'>
<FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching toots by their content is not enabled on this Mastodon server.' />
<FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching posts by their content is not enabled on this server.' />
</div>
</div>
);

View File

@ -42,7 +42,7 @@ const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning
}
if (hashtagWarning) {
return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag." />} />;
return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag." />} />;
}
if (directMessageWarning) {

View File

@ -26,7 +26,7 @@ const messages = defineMessages({
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new post' },
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
});
@ -36,6 +36,25 @@ const mapStateToProps = (state, ownProps) => ({
showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage,
});
let instanceMascot;
if (mascot) {
instanceMascot = <img alt='' draggable='false' src={mascot} />;
} else {
instanceMascot = <svg id='hometownlogo' width="2400" height="460" viewBox="0 0 2400 460" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
<g>
<g>
<path d="m326.20431,287.85649l-302.73044,0c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436s8.81738,19.10436 19.10436,19.10436l302.73044,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436s-8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m326.20431,351.04783l-302.73044,0c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436s8.81738,19.10436 19.10436,19.10436l302.73044,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436s-8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m326.20431,415.70867l-302.73044,0c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436s8.81738,19.10436 19.10436,19.10436l302.73044,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436s-8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m456.99565,287.85649c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436l0,129.32173c0,10.28698 8.81738,19.10436 19.10436,19.10436s19.10436,-8.81738 19.10436,-19.10436l0,-129.32173c-1.46955,-11.75653 -10.28698,-19.10436 -19.10436,-19.10436z"/>
<path d="m392.33476,287.85649c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436l0,129.32173c0,10.28698 8.81738,19.10436 19.10436,19.10436s19.10436,-8.81738 19.10436,-19.10436l0,-129.32173c-1.46955,-11.75653 -8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m440.83045,205.56085c19.10436,-10.28698 29.39129,-36.73911 29.39129,-82.29564c0,-52.90436 -13.22609,-114.62609 -48.49564,-114.62609s-48.49564,61.72173 -48.49564,114.62609c0,45.55653 10.28698,72.00871 29.39129,82.29564l0,35.26955c0,10.28698 8.81738,19.10436 19.10436,19.10436s19.10436,-8.81738 19.10436,-19.10436l0,-35.26955l-0.00002,0zm-19.10436,-154.30436c5.87827,11.75653 11.75653,36.73911 11.75653,72.00871c0,36.73911 -7.34782,49.9652 -11.75653,49.9652s-11.75653,-13.22609 -11.75653,-49.9652c1.46955,-35.26955 7.34782,-60.25218 11.75653,-72.00871z"/>
<path d="m342.36956,123.26521c0,-1.46955 -1.46955,-1.46955 -1.46955,-2.93911l-47.02609,-60.25218c-2.93911,-4.40871 -8.81738,-7.34782 -14.69564,-7.34782l-23.51307,0l0,-27.92173c0,-10.28698 -8.81738,-19.10436 -19.10436,-19.10436s-19.10436,8.81738 -19.10436,19.10436l0,29.39129l-57.31307,0l-16.1652,0l-76.41738,0c-5.87827,0 -10.28698,2.93911 -14.69564,7.34782l-47.02609,60.25218c0,1.46955 -1.46955,1.46955 -1.46955,2.93911c0,0 -1.46955,1.46955 -1.46955,1.46955c1.46955,1.46955 1.46955,4.40871 1.46955,5.87827l0,108.74782c0,10.28698 8.81738,19.10436 19.10436,19.10436l76.41738,0l108.74782,0l117.56525,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436l0,-108.74782c0,-2.93911 0,-4.40871 -1.46955,-5.87827c-1.46955,-1.46955 -1.46955,-1.46955 -1.46955,-2.93911l-0.00005,0l-0.00002,0zm-224.84351,99.93045l-76.41738,0l0,-72.00871l149.89564,0l0,72.00871l-73.47827,0l0.00001,0zm99.93045,-108.74782l-17.6348,-23.51307l70.53916,0l17.6348,23.51307l-70.53916,0zm-64.66089,-23.51307l17.6348,23.51307l-110.21738,0l17.6348,-23.51307l74.94782,0l-0.00005,0l0.00001,0zm74.94782,60.25218l80.82609,0l0,72.00871l-80.82609,0l0,-72.00871z"/>
</g>
</g>
</svg>;
}
export default @connect(mapStateToProps)
@injectIntl
class Compose extends React.PureComponent {
@ -129,7 +148,7 @@ class Compose extends React.PureComponent {
<ComposeFormContainer />
<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
{instanceMascot}
</div>
</div>}

View File

@ -71,7 +71,7 @@ class Favourites extends ImmutablePureComponent {
const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;
const pinned = !!columnId;
const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite toots yet. When you favourite one, it will show up here." />;
const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite posts yet. When you favourite one, it will show up here." />;
return (
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>

View File

@ -60,7 +60,7 @@ class Favourites extends ImmutablePureComponent {
);
}
const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />;
const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this post yet. When someone does, they will show up here.' />;
return (
<Column bindToDocument={!multiColumn}>

View File

@ -29,7 +29,7 @@ const messages = defineMessages({
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },
personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },

View File

@ -75,22 +75,22 @@ const FrameInteractions = ({ onNext }) => (
<div className='introduction__text introduction__text--columnized'>
<div>
<h3><FormattedMessage id='introduction.interactions.reply.headline' defaultMessage='Reply' /></h3>
<p><FormattedMessage id='introduction.interactions.reply.text' defaultMessage="You can reply to other people's and your own toots, which will chain them together in a conversation." /></p>
<p><FormattedMessage id='introduction.interactions.reply.text' defaultMessage="You can reply to other people's and your own posts, which will chain them together in a conversation." /></p>
</div>
<div>
<h3><FormattedMessage id='introduction.interactions.reblog.headline' defaultMessage='Boost' /></h3>
<p><FormattedMessage id='introduction.interactions.reblog.text' defaultMessage="You can share other people's toots with your followers by boosting them." /></p>
<p><FormattedMessage id='introduction.interactions.reblog.text' defaultMessage="You can share other people's posts with your followers by boosting them." /></p>
</div>
<div>
<h3><FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favourite' /></h3>
<p><FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a toot for later, and let the author know that you liked it, by favouriting it.' /></p>
<p><FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a post for later, and let the author know that you liked it, by favouriting it.' /></p>
</div>
</div>
<div className='introduction__action'>
<button className='button' onClick={onNext}><FormattedMessage id='introduction.interactions.action' defaultMessage='Finish toot-orial!' /></button>
<button className='button' onClick={onNext}><FormattedMessage id='introduction.interactions.action' defaultMessage='Finish tutorial!' /></button>
</div>
</div>
);

View File

@ -86,7 +86,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
</tr>
<tr>
<td><kbd>alt</kbd>+<kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new toot' /></td>
<td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new post' /></td>
</tr>
<tr>
<td><kbd>alt</kbd>+<kbd>x</kbd></td>
@ -134,7 +134,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>p</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.pinned' defaultMessage='to open pinned toots list' /></td>
<td><FormattedMessage id='keyboard_shortcuts.pinned' defaultMessage='to open pinned posts list' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>u</kbd></td>

View File

@ -1,9 +1,10 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
import { changeListEditorTitle, changeListEditorIsExclusive, submitListEditor } from '../../../actions/lists';
import IconButton from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import Toggle from 'react-toggle';
const messages = defineMessages({
title: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
@ -17,6 +18,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({
onChange: value => dispatch(changeListEditorTitle(value)),
onSubmit: () => dispatch(submitListEditor(false)),
onToggle: value => dispatch(changeListEditorIsExclusive(value)),
});
export default @connect(mapStateToProps, mapDispatchToProps)
@ -26,6 +28,7 @@ class ListForm extends React.PureComponent {
static propTypes = {
value: PropTypes.string.isRequired,
disabled: PropTypes.bool,
isExclusive: PropTypes.bool,
intl: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
@ -44,8 +47,12 @@ class ListForm extends React.PureComponent {
this.props.onSubmit();
}
handleToggle = e => {
this.props.onToggle(e.target.checked);
}
render () {
const { value, disabled, intl } = this.props;
const { value, disabled, intl, isExclusive, hello } = this.props;
const title = intl.formatMessage(messages.title);
@ -57,6 +64,11 @@ class ListForm extends React.PureComponent {
onChange={this.handleChange}
/>
<label htmlFor='is-exclusive-checkbox'>
<Toggle className='is-exclusive-checkbox' defaultChecked={isExclusive} onChange={this.handleToggle}/>
<FormattedMessage id='lists.is-exclusive' defaultMessage='Exclusive?' />
</label>
<IconButton
disabled={disabled}
icon='check'

View File

@ -28,6 +28,7 @@ class ListEditor extends ImmutablePureComponent {
static propTypes = {
listId: PropTypes.string.isRequired,
isExclusive: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
onInitialize: PropTypes.func.isRequired,
@ -53,7 +54,7 @@ class ListEditor extends ImmutablePureComponent {
return (
<div className='modal-root__modal list-editor'>
<EditListForm />
<EditListForm isExclusive={this.props.isExclusive} />
<Search />

View File

@ -113,7 +113,7 @@ class ListTimeline extends React.PureComponent {
}
handleEditClick = () => {
this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id }));
this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id, isExclusive: this.props.list.get('is_exclusive') }));
}
handleDeleteClick = () => {

View File

@ -10,7 +10,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
const messages = defineMessages({
heading: { id: 'column.pins', defaultMessage: 'Pinned toot' },
heading: { id: 'column.pins', defaultMessage: 'Pinned post' },
});
const mapStateToProps = state => ({

View File

@ -60,7 +60,7 @@ class Reblogs extends ImmutablePureComponent {
);
}
const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has boosted this toot yet. When someone does, they will show up here.' />;
const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has boosted this post yet. When someone does, they will show up here.' />;
return (
<Column bindToDocument={!multiColumn}>

View File

@ -18,6 +18,7 @@ const messages = defineMessages({
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' },
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
local_only: { id: 'status.local_only', defaultMessage: 'This post is only visible by other users of your instance' },
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
more: { id: 'status.more', defaultMessage: 'More' },
@ -189,6 +190,7 @@ class ActionBar extends React.PureComponent {
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const mutingConversation = status.get('muted');
const federated = !status.get('local_only');
const account = status.get('account');
let menu = [];
@ -247,7 +249,7 @@ class ActionBar extends React.PureComponent {
}
}
const shareButton = ('share' in navigator) && publicStatus && (
const shareButton = ('share' in navigator) && publicStatus && federated && (
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShare} /></div>
);

View File

@ -251,7 +251,7 @@ class DetailedStatus extends ImmutablePureComponent {
<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('activity_pub_type') === 'Article' || !status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
{media}

View File

@ -50,7 +50,7 @@ const componentMap = {
};
const messages = defineMessages({
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
publish: { id: 'compose_form.publish', defaultMessage: 'Post' },
});
const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/);

View File

@ -64,6 +64,11 @@ class LinkFooter extends React.PureComponent {
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
values={{ github: <span><a href={source_url} rel='noopener noreferrer' target='_blank'>{repository}</a> (v{version})</span> }}
/>
<FormattedMessage
id='getting_started.hometown_open_source_notice'
defaultMessage='Hometown is also open source, at {hometown} (v1.0.5).'
values={{ hometown: <span><a href='https://github.com/hometown-fork/hometown' rel='noopener' target='_blank'>hometown-fork/hometown</a></span> }}
/>
</p>
</div>
);

View File

@ -61,7 +61,7 @@ import { previewState as previewVideoState } from './components/video_modal';
import '../../components/status';
const messages = defineMessages({
beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' },
beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave.' },
});
const mapStateToProps = state => ({