Compare commits
7 commits
68105a39bf
...
29278e8802
Author | SHA1 | Date | |
---|---|---|---|
29278e8802 | |||
|
d7088dbd06 | ||
|
8586ff5b53 | ||
|
9762592e51 | ||
|
e0788087c8 | ||
|
a62d84e898 | ||
|
2b4a5956e0 |
74 changed files with 266 additions and 226 deletions
49
.woodpecker.yml
Normal file
49
.woodpecker.yml
Normal file
|
@ -0,0 +1,49 @@
|
|||
pipeline:
|
||||
lint:
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
image: node:16
|
||||
commands:
|
||||
- yarn
|
||||
- yarn test:lint
|
||||
|
||||
test:
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
image: node:16
|
||||
commands:
|
||||
- apt update
|
||||
- apt install firefox-esr -y --no-install-recommends
|
||||
- yarn
|
||||
- yarn test
|
||||
|
||||
build:
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
image: node:16
|
||||
commands:
|
||||
- yarn
|
||||
- TARGET=distribution ./build.sh
|
||||
|
||||
release:
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
image: node:16
|
||||
secrets:
|
||||
- SCW_ACCESS_KEY
|
||||
- SCW_SECRET_KEY
|
||||
- SCW_DEFAULT_ORGANIZATION_ID
|
||||
commands:
|
||||
- apt-get update && apt-get install -y rclone wget zip
|
||||
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64
|
||||
- mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli
|
||||
- chmod +x scaleway-cli
|
||||
- ./scaleway-cli object config install type=rclone
|
||||
- zip mastofe.zip -r distribution
|
||||
- rclone copyto akkoma-fe.zip scaleway:akkoma-updates/frontend/$CI_COMMIT_BRANCH/masto-fe.zip
|
|
@ -1,7 +1,9 @@
|
|||
// This file will be loaded on settings pages, regardless of theme.
|
||||
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
|
||||
const { delegate } = require('@rails/ujs');
|
||||
|
||||
import emojify from '../mastodon/features/emoji/emoji';
|
||||
|
||||
delegate(document, '#account_display_name', 'input', ({ target }) => {
|
||||
|
@ -62,7 +64,7 @@ delegate(document, '.input-copy button', 'click', ({ target }) => {
|
|||
input.blur();
|
||||
target.parentNode.classList.add('copied');
|
||||
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
target.parentNode.classList.remove('copied');
|
||||
}, 700);
|
||||
}
|
||||
|
|
|
@ -760,7 +760,7 @@ export function fetchPinnedAccounts() {
|
|||
return (dispatch, getState) => {
|
||||
dispatch(fetchPinnedAccountsRequest());
|
||||
|
||||
api(getState).get(`/api/v1/endorsements`, { params: { limit: 0 } }).then(response => {
|
||||
api(getState).get('/api/v1/endorsements', { params: { limit: 0 } }).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchPinnedAccountsSuccess(response.data));
|
||||
}).catch(err => dispatch(fetchPinnedAccountsFail(err)));
|
||||
|
@ -822,7 +822,7 @@ export function changePinnedAccountsSuggestions(value) {
|
|||
return {
|
||||
type: PINNED_ACCOUNTS_EDITOR_SUGGESTIONS_CHANGE,
|
||||
value,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export function resetPinnedAccountsEditor() {
|
||||
|
|
|
@ -246,34 +246,34 @@ export function uploadCompose(files) {
|
|||
for (const [i, file] of Array.from(files).entries()) {
|
||||
if (media.size + i > 3) break;
|
||||
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
|
||||
return api(getState).post('/api/v2/media', data, {
|
||||
onUploadProgress: function({ loaded }){
|
||||
progress[i] = loaded;
|
||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||
},
|
||||
}).then(({ status, data }) => {
|
||||
// If server-side processing of the media attachment has not completed yet,
|
||||
// poll the server until it is, before showing the media attachment as uploaded
|
||||
return api(getState).post('/api/v2/media', data, {
|
||||
onUploadProgress: function({ loaded }){
|
||||
progress[i] = loaded;
|
||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||
},
|
||||
}).then(({ status, data }) => {
|
||||
// If server-side processing of the media attachment has not completed yet,
|
||||
// poll the server until it is, before showing the media attachment as uploaded
|
||||
|
||||
if (status === 200) {
|
||||
dispatch(uploadComposeSuccess(data, file));
|
||||
} else if (status === 202) {
|
||||
const poll = () => {
|
||||
api(getState).get(`/api/v1/media/${data.id}`).then(response => {
|
||||
if (response.status === 200) {
|
||||
dispatch(uploadComposeSuccess(response.data, file));
|
||||
} else if (response.status === 206) {
|
||||
setTimeout(() => poll(), 1000);
|
||||
}
|
||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||
};
|
||||
if (status === 200) {
|
||||
dispatch(uploadComposeSuccess(data, file));
|
||||
} else if (status === 202) {
|
||||
const poll = () => {
|
||||
api(getState).get(`/api/v1/media/${data.id}`).then(response => {
|
||||
if (response.status === 200) {
|
||||
dispatch(uploadComposeSuccess(response.data, file));
|
||||
} else if (response.status === 206) {
|
||||
setTimeout(() => poll(), 1000);
|
||||
}
|
||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||
};
|
||||
|
||||
poll();
|
||||
}
|
||||
});
|
||||
poll();
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -36,15 +36,15 @@ export const submitMarkers = () => (dispatch, getState) => {
|
|||
};
|
||||
|
||||
export const fetchMarkers = () => (dispatch, getState) => {
|
||||
const params = { timeline: ['notifications'] };
|
||||
const params = { timeline: ['notifications'] };
|
||||
|
||||
dispatch(fetchMarkersRequest());
|
||||
dispatch(fetchMarkersRequest());
|
||||
|
||||
api(getState).get('/api/v1/markers', { params }).then(response => {
|
||||
dispatch(fetchMarkersSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchMarkersFail(error));
|
||||
});
|
||||
api(getState).get('/api/v1/markers', { params }).then(response => {
|
||||
dispatch(fetchMarkersSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(fetchMarkersFail(error));
|
||||
});
|
||||
};
|
||||
|
||||
export function fetchMarkersRequest() {
|
||||
|
|
|
@ -27,7 +27,7 @@ const debouncedSave = debounce((dispatch, getState) => {
|
|||
|
||||
api(getState).put(
|
||||
'/api/pleroma/notification_settings',
|
||||
{ exclude_types: excludeTypesFromSettings(getState()) }
|
||||
{ exclude_types: excludeTypesFromSettings(getState()) },
|
||||
).catch(error => dispatch(showAlertForError(error)));
|
||||
|
||||
api(getState).put('/api/web/settings', { data })
|
||||
|
|
|
@ -47,7 +47,7 @@ export function updateTimeline(timeline, status, accept) {
|
|||
timeline,
|
||||
status,
|
||||
usePendingItems: preferPendingItems,
|
||||
filtered
|
||||
filtered,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
|
@ -87,7 +87,7 @@ export default class DisplayName extends React.PureComponent {
|
|||
)).reduce((prev, cur) => [prev, ', ', cur]);
|
||||
|
||||
if (others.size - 2 > 0) {
|
||||
displayName.push(` +${others.size - 2}`);
|
||||
displayName.push(` +${others.size - 2}`);
|
||||
}
|
||||
|
||||
suffix = (
|
||||
|
|
|
@ -104,16 +104,17 @@ export default class ErrorBoundary extends React.PureComponent {
|
|||
/>
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
<FormattedMessage
|
||||
<li>
|
||||
<FormattedMessage
|
||||
id='web_app_crash.load_pleromafe'
|
||||
defaultMessage='Load {pleromafe} instead of mastofe'
|
||||
values={{ pleromafe: <a href='/main/all'><FormattedMessage id='web_app_crash.pleromafe' defaultMessage='Pleroma Frontend' /></a> }}
|
||||
/>
|
||||
</li>
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -121,8 +121,9 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
aria-setsize={listLength}
|
||||
data-id={id}
|
||||
tabIndex='0'
|
||||
style={style}>
|
||||
{children && React.cloneElement(children, { hidden: !isIntersecting && (isHidden || !!cachedHeight) })}
|
||||
style={style}
|
||||
>
|
||||
{children && React.cloneElement(children, { hidden: !isIntersecting && (isHidden || !!cachedHeight) })}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -233,14 +233,14 @@ class Item extends React.PureComponent {
|
|||
aria-label={attachment.get('description')}
|
||||
role='application'
|
||||
>
|
||||
<span><p>sound<br/>only</p></span>
|
||||
<span><p>sound<br />only</p></span>
|
||||
<span><p>{attachment.get('description')}</p></span>
|
||||
<audio
|
||||
src={attachment.get('url')}
|
||||
controls
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
} else if (attachment.get('type') === 'gifv') {
|
||||
const autoPlay = !isIOS() && this.getAutoPlay();
|
||||
|
||||
|
@ -367,7 +367,7 @@ class MediaGallery extends React.PureComponent {
|
|||
} else if (width) {
|
||||
style.height = width / (16/9);
|
||||
} else {
|
||||
return (<div className={computedClass} ref={this.handleRef}></div>);
|
||||
return (<div className={computedClass} ref={this.handleRef} />);
|
||||
}
|
||||
|
||||
if (this.isStandaloneEligible()) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'wicg-inert';
|
|||
import { createBrowserHistory } from 'history';
|
||||
|
||||
export default class ModalRoot extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
};
|
||||
|
@ -104,7 +105,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||
|
||||
handleModalOpen () {
|
||||
const history = this.history;
|
||||
const state = {...history.location.state, mastodonModalOpen: true};
|
||||
const state = { ...history.location.state, mastodonModalOpen: true };
|
||||
history.push(history.location.pathname, state);
|
||||
this.unlistenHistory = history.listen(() => {
|
||||
this.props.onClose();
|
||||
|
|
|
@ -24,7 +24,7 @@ export default class Permalink extends React.PureComponent {
|
|||
|
||||
if (this.context.router) {
|
||||
e.preventDefault();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(this.props.to, state);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl';
|
|||
|
||||
export default
|
||||
class Spoilers extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
spoilerText: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
|
@ -21,17 +22,17 @@ class Spoilers extends React.PureComponent {
|
|||
const { spoilerText, children } = this.props;
|
||||
const { hidden } = this.state;
|
||||
|
||||
const toggleText = hidden ?
|
||||
<FormattedMessage
|
||||
id='status.show_more'
|
||||
defaultMessage='Show more'
|
||||
key='0'
|
||||
/> :
|
||||
<FormattedMessage
|
||||
id='status.show_less'
|
||||
defaultMessage='Show less'
|
||||
key='0'
|
||||
/>;
|
||||
const toggleText = hidden ?
|
||||
(<FormattedMessage
|
||||
id='status.show_more'
|
||||
defaultMessage='Show more'
|
||||
key='0'
|
||||
/>) :
|
||||
(<FormattedMessage
|
||||
id='status.show_less'
|
||||
defaultMessage='Show less'
|
||||
key='0'
|
||||
/>);
|
||||
|
||||
return ([
|
||||
<p className='spoiler__text'>
|
||||
|
@ -43,8 +44,9 @@ class Spoilers extends React.PureComponent {
|
|||
</p>,
|
||||
<div className={`status__content__spoiler ${!hidden ? 'status__content__spoiler--visible' : ''}`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ export const defaultMediaVisibility = (status, settings) => {
|
|||
}
|
||||
|
||||
return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all');
|
||||
}
|
||||
};
|
||||
|
||||
export default @injectIntl
|
||||
class Status extends ImmutablePureComponent {
|
||||
|
@ -291,7 +291,9 @@ class Status extends ImmutablePureComponent {
|
|||
if (this.node && this.props.getScrollPosition) {
|
||||
const position = this.props.getScrollPosition();
|
||||
if (position !== null && this.node.offsetTop < position.top) {
|
||||
requestAnimationFrame(() => { this.props.updateScrollBottom(position.height - position.top); });
|
||||
requestAnimationFrame(() => {
|
||||
this.props.updateScrollBottom(position.height - position.top);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +346,7 @@ class Status extends ImmutablePureComponent {
|
|||
status.getIn(['reblog', 'id'], status.get('id'))
|
||||
}`;
|
||||
}
|
||||
let state = {...router.history.location.state};
|
||||
let state = { ...router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
router.history.push(destination, state);
|
||||
}
|
||||
|
@ -360,7 +362,7 @@ class Status extends ImmutablePureComponent {
|
|||
if (this.context.router && e.button === 0) {
|
||||
const id = e.currentTarget.getAttribute('data-id');
|
||||
e.preventDefault();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${id}`, state);
|
||||
}
|
||||
|
@ -415,13 +417,13 @@ class Status extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleHotkeyOpen = () => {
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/statuses/${this.props.status.get('id')}`, state);
|
||||
}
|
||||
|
||||
handleHotkeyOpenProfile = () => {
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state);
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
|
||||
_openInteractionDialog = type => {
|
||||
window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
|
||||
}
|
||||
}
|
||||
|
||||
handleDeleteClick = () => {
|
||||
this.props.onDelete(this.props.status, this.context.router.history);
|
||||
|
@ -153,7 +153,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleOpen = () => {
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
if (state.mastodonModalOpen) {
|
||||
this.context.router.history.replace(`/statuses/${this.props.status.get('id')}`, { mastodonBackSteps: (state.mastodonBackSteps || 0) + 1 });
|
||||
} else {
|
||||
|
|
|
@ -13,7 +13,7 @@ const textMatchesTarget = (text, origin, host) => {
|
|||
return (text === origin || text === host
|
||||
|| text.startsWith(origin + '/') || text.startsWith(host + '/')
|
||||
|| 'www.' + text === host || ('www.' + text).startsWith(host + '/'));
|
||||
}
|
||||
};
|
||||
|
||||
const isLinkMisleading = (link) => {
|
||||
let linkTextParts = [];
|
||||
|
|
|
@ -48,16 +48,16 @@ class StatusIcons extends React.PureComponent {
|
|||
const { intl, mediaIcon } = this.props;
|
||||
|
||||
switch (mediaIcon) {
|
||||
case 'link':
|
||||
return intl.formatMessage(messages.previewCard);
|
||||
case 'picture-o':
|
||||
return intl.formatMessage(messages.pictures);
|
||||
case 'tasks':
|
||||
return intl.formatMessage(messages.poll);
|
||||
case 'video-camera':
|
||||
return intl.formatMessage(messages.video);
|
||||
case 'music':
|
||||
return intl.formatMessage(messages.audio);
|
||||
case 'link':
|
||||
return intl.formatMessage(messages.previewCard);
|
||||
case 'picture-o':
|
||||
return intl.formatMessage(messages.pictures);
|
||||
case 'tasks':
|
||||
return intl.formatMessage(messages.poll);
|
||||
case 'video-camera':
|
||||
return intl.formatMessage(messages.video);
|
||||
case 'music':
|
||||
return intl.formatMessage(messages.audio);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@ const mapDispatchToProps = (dispatch, { status, items }) => ({
|
|||
(item, i) => item ? {
|
||||
...item,
|
||||
name: `${item.text}-${i}`,
|
||||
onClick: item.action ? ((e) => { return onItemClick(i, e) }) : null,
|
||||
} : null
|
||||
onClick: item.action ? ((e) => {
|
||||
return onItemClick(i, e);
|
||||
}) : null,
|
||||
} : null,
|
||||
),
|
||||
}) : openDropdownMenu(id, dropdownPlacement, keyboard));
|
||||
},
|
||||
|
|
|
@ -201,7 +201,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
|||
<Spoilers spoilerText={intl.formatMessage(messages.author)}>
|
||||
<AccountContainer id={status.getIn(['account', 'id'])} />
|
||||
</Spoilers>
|
||||
<Spoilers spoilerText={intl.formatMessage(messages.matchingFilters, {count: matchingFilters.size})}>
|
||||
<Spoilers spoilerText={intl.formatMessage(messages.matchingFilters, { count: matchingFilters.size })}>
|
||||
<ul>
|
||||
{matchingFilters.map(filter => (
|
||||
<li>
|
||||
|
@ -221,7 +221,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
|||
))}
|
||||
</ul>
|
||||
</Spoilers>
|
||||
</div>
|
||||
</div>,
|
||||
],
|
||||
confirm: intl.formatMessage(messages.unfilterConfirm),
|
||||
onConfirm: onConfirm,
|
||||
|
|
|
@ -128,8 +128,7 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
|
||||
info.push(<span className='relationship-tag'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>);
|
||||
}
|
||||
else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
|
||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
|
||||
info.push(<span className='relationship-tag'><FormattedMessage id='account.blocked' defaultMessage='Blocked' /></span>);
|
||||
}
|
||||
|
||||
|
@ -297,7 +296,7 @@ class Header extends ImmutablePureComponent {
|
|||
{fields.map((pair, i) => (
|
||||
<dl key={i}>
|
||||
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
|
||||
|
||||
|
||||
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
|
||||
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
|
||||
</dd>
|
||||
|
@ -308,9 +307,9 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
{account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content' dangerouslySetInnerHTML={content} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class MovedNote extends ImmutablePureComponent {
|
|||
handleAccountClick = e => {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${this.props.to.get('id')}`, state);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from 'flavours/glitch/actions/accounts';
|
||||
import {
|
||||
mentionCompose,
|
||||
directCompose
|
||||
directCompose,
|
||||
} from 'flavours/glitch/actions/compose';
|
||||
import { initMuteModal } from 'flavours/glitch/actions/mutes';
|
||||
import { initBlockModal } from 'flavours/glitch/actions/blocks';
|
||||
|
|
|
@ -12,7 +12,7 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'community']),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
return {
|
||||
onChange (key, checked) {
|
||||
|
|
|
@ -20,9 +20,9 @@ import CharacterCounter from './character_counter';
|
|||
const messages = defineMessages({
|
||||
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
|
||||
missingDescriptionMessage: { id: 'confirmations.missing_media_description.message',
|
||||
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.' },
|
||||
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.' },
|
||||
missingDescriptionConfirm: { id: 'confirmations.missing_media_description.confirm',
|
||||
defaultMessage: 'Send anyway' },
|
||||
defaultMessage: 'Send anyway' },
|
||||
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
|
||||
});
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
|
|||
onChange(name);
|
||||
component.setState({ needsModalUpdate: true });
|
||||
},
|
||||
})
|
||||
}),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
|
|||
const { items } = this.props;
|
||||
const { needsModalUpdate } = this.state;
|
||||
if (needsModalUpdate && items.find(
|
||||
(item, i) => item.on !== prevProps.items[i].on
|
||||
(item, i) => item.on !== prevProps.items[i].on,
|
||||
)) {
|
||||
this.handleUpdate();
|
||||
this.setState({ needsModalUpdate: false });
|
||||
|
|
|
@ -167,7 +167,7 @@ export default class ComposerOptionsDropdownContent extends React.PureComponent
|
|||
if (on !== null && typeof on !== 'undefined') {
|
||||
prefix = <Toggle checked={on} onChange={this.handleClick.bind(this, name)} />;
|
||||
} else if (icon) {
|
||||
prefix = <Icon className='icon' fixedWidth id={icon} />
|
||||
prefix = <Icon className='icon' fixedWidth id={icon} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -47,6 +47,7 @@ const messages = defineMessages({
|
|||
|
||||
export default @injectIntl
|
||||
class Header extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
columns: ImmutablePropTypes.list,
|
||||
unreadNotifications: PropTypes.number,
|
||||
|
@ -71,8 +72,8 @@ class Header extends ImmutablePureComponent {
|
|||
// Only renders the component if the column isn't being shown.
|
||||
const renderForColumn = conditionalRender.bind(null,
|
||||
columnId => !columns || !columns.some(
|
||||
column => column.get('id') === columnId
|
||||
)
|
||||
column => column.get('id') === columnId,
|
||||
),
|
||||
);
|
||||
|
||||
// The result.
|
||||
|
@ -125,10 +126,11 @@ class Header extends ImmutablePureComponent {
|
|||
<a
|
||||
aria-label={intl.formatMessage(messages.logout)}
|
||||
onClick={this.handleLogoutClick}
|
||||
href={ signOutLink }
|
||||
href={signOutLink}
|
||||
title={intl.formatMessage(messages.logout)}
|
||||
><Icon id='sign-out' /></a>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,11 +28,12 @@ export default class NavigationBar extends ImmutablePureComponent {
|
|||
{ profileLink !== undefined && (
|
||||
<a
|
||||
className='edit'
|
||||
href={ profileLink }
|
||||
href={profileLink}
|
||||
><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -115,4 +115,5 @@ class Publisher extends ImmutablePureComponent {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ class SearchResults extends ImmutablePureComponent {
|
|||
<section>
|
||||
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
|
||||
|
||||
{results.get('statuses').map(statusId => <StatusContainer id={statusId} key={statusId}/>)}
|
||||
{results.get('statuses').map(statusId => <StatusContainer id={statusId} key={statusId} />)}
|
||||
|
||||
{results.get('statuses').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
|
||||
</section>
|
||||
|
@ -131,4 +131,5 @@ class SearchResults extends ImmutablePureComponent {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -51,9 +51,10 @@ class TextareaIcons extends ImmutablePureComponent {
|
|||
id={icon}
|
||||
/>
|
||||
</span>
|
||||
) : null
|
||||
) : null,
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export default class Upload extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<div className='composer--upload_form--item' tabIndex='0' role='button'>
|
||||
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12, }) }}>
|
||||
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
||||
{({ scale }) => (
|
||||
<div style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
||||
<div className={classNames('composer--upload_form--actions', { active: true })}>
|
||||
|
|
|
@ -7,6 +7,7 @@ import SensitiveButtonContainer from '../containers/sensitive_button_container';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class UploadForm extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
mediaIds: ImmutablePropTypes.list.isRequired,
|
||||
};
|
||||
|
|
|
@ -30,7 +30,8 @@ export default class UploadProgress extends React.PureComponent {
|
|||
<div className='backdrop'>
|
||||
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(progress) }}>
|
||||
{({ width }) =>
|
||||
(<div className='tracker' style={{ width: `${width}%` }}
|
||||
(<div
|
||||
className='tracker' style={{ width: `${width}%` }}
|
||||
/>)
|
||||
}
|
||||
</Motion>
|
||||
|
|
|
@ -22,11 +22,11 @@ import { privacyPreference } from 'flavours/glitch/util/privacy_preference';
|
|||
|
||||
const messages = defineMessages({
|
||||
missingDescriptionMessage: { id: 'confirmations.missing_media_description.message',
|
||||
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.' },
|
||||
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.' },
|
||||
missingDescriptionConfirm: { id: 'confirmations.missing_media_description.confirm',
|
||||
defaultMessage: 'Send anyway' },
|
||||
defaultMessage: 'Send anyway' },
|
||||
missingDescriptionEdit: { id: 'confirmations.missing_media_description.edit',
|
||||
defaultMessage: 'Edit media' },
|
||||
defaultMessage: 'Edit media' },
|
||||
});
|
||||
|
||||
// State mapping.
|
||||
|
@ -38,12 +38,12 @@ function mapStateToProps (state) {
|
|||
const sideArmRestrictedPrivacy = replyPrivacy ? privacyPreference(replyPrivacy, sideArmBasePrivacy) : null;
|
||||
let sideArmPrivacy = null;
|
||||
switch (state.getIn(['local_settings', 'side_arm_reply_mode'])) {
|
||||
case 'copy':
|
||||
sideArmPrivacy = replyPrivacy;
|
||||
break;
|
||||
case 'restrict':
|
||||
sideArmPrivacy = sideArmRestrictedPrivacy;
|
||||
break;
|
||||
case 'copy':
|
||||
sideArmPrivacy = replyPrivacy;
|
||||
break;
|
||||
case 'restrict':
|
||||
sideArmPrivacy = sideArmRestrictedPrivacy;
|
||||
break;
|
||||
}
|
||||
sideArmPrivacy = sideArmPrivacy || sideArmBasePrivacy;
|
||||
return {
|
||||
|
|
|
@ -34,6 +34,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class Compose extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
multiColumn: PropTypes.bool,
|
||||
showSearch: PropTypes.bool,
|
||||
|
|
|
@ -59,7 +59,7 @@ class Conversation extends ImmutablePureComponent {
|
|||
}
|
||||
destination = `/statuses/${lastStatus.get('id')}`;
|
||||
}
|
||||
let state = {...router.history.location.state};
|
||||
let state = { ...router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
router.history.push(destination, state);
|
||||
e.preventDefault();
|
||||
|
|
|
@ -83,9 +83,9 @@ const badgeDisplay = (number, limit) => {
|
|||
|
||||
const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
|
||||
|
||||
export default @connect(makeMapStateToProps, mapDispatchToProps)
|
||||
export default @connect(makeMapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class GettingStarted extends ImmutablePureComponent {
|
||||
class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object.isRequired,
|
||||
|
@ -172,12 +172,12 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
|
|||
<div key='9'>
|
||||
<ColumnLink key='10' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
|
||||
{lists.map(list =>
|
||||
<ColumnLink key={(11 + Number(list.get('id'))).toString()} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} />
|
||||
<ColumnLink key={(11 + Number(list.get('id'))).toString()} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} />,
|
||||
)}
|
||||
</div>,
|
||||
]);
|
||||
|
||||
const instance_panel = (customPanelEnabled ? <div className='getting-started getting-started__panel' dangerouslySetInnerHTML={{__html: customPanel}} /> : null);
|
||||
const instance_panel = (customPanelEnabled ? <div className='getting-started getting-started__panel' dangerouslySetInnerHTML={{ __html: customPanel }} /> : null);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} name='getting-started' icon='asterisk' heading={intl.formatMessage(messages.heading)} label={intl.formatMessage(messages.menu)} hideHeadingOnMobile>
|
||||
|
|
|
@ -59,7 +59,6 @@ class gettingStartedMisc extends ImmutablePureComponent {
|
|||
<ColumnLink key='{i++}' icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
|
||||
<ColumnLink key='{i++}' icon='minus-circle' text={intl.formatMessage(messages.domain_blocks)} to='/domain_blocks' />
|
||||
<ColumnLink key='{i++}' icon='question' text={intl.formatMessage(messages.keyboard_shortcuts)} to='/keyboard-shortcuts' />
|
||||
<ColumnLink key='{i++}' icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />
|
||||
<ColumnLink key='{i++}' icon='hand-o-right' text={intl.formatMessage(messages.show_me_around)} onClick={this.openOnboardingModal} />
|
||||
</div>
|
||||
</Column>
|
||||
|
|
|
@ -80,7 +80,7 @@ class LocalSettingsNavigation extends React.PureComponent {
|
|||
/>
|
||||
<LocalSettingsNavigationItem
|
||||
active={index === 6}
|
||||
href={ preferencesLink }
|
||||
href={preferencesLink}
|
||||
index={6}
|
||||
icon='cog'
|
||||
title={intl.formatMessage(messages.preferences)}
|
||||
|
|
|
@ -59,7 +59,7 @@ class LocalSettingsPage extends React.PureComponent {
|
|||
onChange={onChange}
|
||||
>
|
||||
<FormattedMessage id='settings.hicolor_privacy_icons' defaultMessage='High color privacy icons' />
|
||||
<span className='hint'><FormattedMessage id='settings.hicolor_privacy_icons.hint' defaultMessage="Display privacy icons in bright and easily distinguishable colors" /></span>
|
||||
<span className='hint'><FormattedMessage id='settings.hicolor_privacy_icons.hint' defaultMessage='Display privacy icons in bright and easily distinguishable colors' /></span>
|
||||
</LocalSettingsPageItem>
|
||||
<LocalSettingsPageItem
|
||||
settings={settings}
|
||||
|
@ -76,7 +76,7 @@ class LocalSettingsPage extends React.PureComponent {
|
|||
onChange={onChange}
|
||||
>
|
||||
<FormattedMessage id='settings.tag_misleading_links' defaultMessage='Tag misleading links' />
|
||||
<span className='hint'><FormattedMessage id='settings.tag_misleading_links.hint' defaultMessage="Add a visual indication with the link target host to every link not mentioning it explicitly" /></span>
|
||||
<span className='hint'><FormattedMessage id='settings.tag_misleading_links.hint' defaultMessage='Add a visual indication with the link target host to every link not mentioning it explicitly' /></span>
|
||||
</LocalSettingsPageItem>
|
||||
<LocalSettingsPageItem
|
||||
settings={settings}
|
||||
|
@ -99,7 +99,7 @@ class LocalSettingsPage extends React.PureComponent {
|
|||
id='mastodon-settings--notifications-tab_badge'
|
||||
onChange={onChange}
|
||||
>
|
||||
<FormattedMessage id='settings.notifications.tab_badge' defaultMessage="Unread notifications badge" />
|
||||
<FormattedMessage id='settings.notifications.tab_badge' defaultMessage='Unread notifications badge' />
|
||||
<span className='hint'><FormattedMessage id='settings.notifications.tab_badge.hint' defaultMessage="Display a badge for unread notifications in the column icons when the notifications column isn't open" /></span>
|
||||
</LocalSettingsPageItem>
|
||||
<LocalSettingsPageItem
|
||||
|
@ -109,7 +109,7 @@ class LocalSettingsPage extends React.PureComponent {
|
|||
onChange={onChange}
|
||||
>
|
||||
<FormattedMessage id='settings.notifications.favicon_badge' defaultMessage='Unread notifications favicon badge' />
|
||||
<span className='hint'><FormattedMessage id='settings.notifications.favicon_badge.hint' defaultMessage="Add a badge for unread notifications to the favicon" /></span>
|
||||
<span className='hint'><FormattedMessage id='settings.notifications.favicon_badge.hint' defaultMessage='Add a badge for unread notifications to the favicon' /></span>
|
||||
</LocalSettingsPageItem>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -272,7 +272,7 @@ class LocalSettingsPage extends React.PureComponent {
|
|||
{ value: 'drop', message: intl.formatMessage(messages.filters_drop) },
|
||||
{ value: 'upstream', message: intl.formatMessage(messages.filters_upstream) },
|
||||
{ value: 'hide', message: intl.formatMessage(messages.filters_hide) },
|
||||
{ value: 'content_warning', message: intl.formatMessage(messages.filters_cw) }
|
||||
{ value: 'content_warning', message: intl.formatMessage(messages.filters_cw) },
|
||||
]}
|
||||
>
|
||||
<FormattedMessage id='settings.filtering_behavior' defaultMessage='Filtering behavior' />
|
||||
|
|
|
@ -53,13 +53,14 @@ export default class LocalSettingsPageItem extends React.PureComponent {
|
|||
let optionId = `${id}--${opt.value}`;
|
||||
return (
|
||||
<label htmlFor={optionId}>
|
||||
<input type='radio'
|
||||
<input
|
||||
type='radio'
|
||||
name={id}
|
||||
id={optionId}
|
||||
value={opt.value}
|
||||
onBlur={handleChange}
|
||||
onChange={handleChange}
|
||||
checked={ currentValue === opt.value }
|
||||
checked={currentValue === opt.value}
|
||||
disabled={!enabled}
|
||||
/>
|
||||
{opt.message}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { injectIntl } from 'react-intl';
|
|||
import {
|
||||
fetchPinnedAccountsSuggestions,
|
||||
clearPinnedAccountsSuggestions,
|
||||
changePinnedAccountsSuggestions
|
||||
changePinnedAccountsSuggestions,
|
||||
} from '../../../actions/accounts';
|
||||
import Search from 'flavours/glitch/features/list_editor/components/search';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { connect } from 'react-redux';
|
|||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||
import { changeColumnParams } from 'flavours/glitch/actions/columns';
|
||||
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
|
|
|
@ -46,7 +46,7 @@ class PublicTimeline extends React.PureComponent {
|
|||
|
||||
dispatch(local ? expandCommunityTimeline() : expandPublicTimeline());
|
||||
}
|
||||
|
||||
|
||||
handleLoadMore = () => {
|
||||
const { dispatch, statusIds, local } = this.props;
|
||||
const maxId = statusIds.last();
|
||||
|
|
|
@ -47,7 +47,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
|||
handleAccountClick = (e) => {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey) && this.context.router) {
|
||||
e.preventDefault();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
|||
parseClick = (e, destination) => {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey) && this.context.router) {
|
||||
e.preventDefault();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(destination, state);
|
||||
}
|
||||
|
|
|
@ -402,7 +402,7 @@ class Status extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleHotkeyOpenProfile = () => {
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class BoostModal extends ImmutablePureComponent {
|
|||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
this.props.onClose();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state);
|
||||
}
|
||||
|
@ -90,9 +90,9 @@ class BoostModal extends ImmutablePureComponent {
|
|||
<div className='boost-modal__action-bar'>
|
||||
<div>
|
||||
{ missingMediaDescription ?
|
||||
<FormattedMessage id='boost_modal.missing_description' defaultMessage='This toot contains some media without description' />
|
||||
<FormattedMessage id='boost_modal.missing_description' defaultMessage='This toot contains some media without description' />
|
||||
:
|
||||
<FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} />
|
||||
<FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} />
|
||||
}
|
||||
</div>
|
||||
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
|
||||
|
|
|
@ -27,7 +27,7 @@ const ColumnLink = ({ icon, text, to, onClick, href, method, badge }) => {
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return onClick(e);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<a href='#' onClick={onClick && handleOnClick} className='column-link' tabIndex='0'>
|
||||
<Icon id={icon} fixedWidth className='column-link__icon' />
|
||||
|
|
|
@ -575,7 +575,7 @@ class DoodleModal extends ImmutablePureComponent {
|
|||
<div>
|
||||
<select aria-label='Canvas size' onInput={this.changeSize} defaultValue={this.size}>
|
||||
{ Object.values(mapValues(DOODLE_SIZES, (val, k) =>
|
||||
<option key={k} value={k}>{val[2]}</option>
|
||||
<option key={k} value={k}>{val[2]}</option>,
|
||||
)) }
|
||||
</select>
|
||||
</div>
|
||||
|
@ -602,7 +602,7 @@ class DoodleModal extends ImmutablePureComponent {
|
|||
'foreground': this.fg === c[0],
|
||||
'background': this.bg === c[0],
|
||||
})}
|
||||
/>
|
||||
/>,
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -41,7 +41,7 @@ class FavouriteModal extends ImmutablePureComponent {
|
|||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
this.props.onClose();
|
||||
let state = {...this.context.router.history.location.state};
|
||||
let state = { ...this.context.router.history.location.state };
|
||||
state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
|
||||
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`, state);
|
||||
}
|
||||
|
|
|
@ -21,11 +21,12 @@ class LinkFooter extends React.PureComponent {
|
|||
mastofe: <a href='https://git.pleroma.social/pleroma/mastofe' rel='noopener noreferrer' target='_blank'>Mastofe</a>,
|
||||
glitchsoc: <a href='https://github.com/glitch-soc/mastodon' rel='noopener noreferrer' target='_blank'>glitch-soc</a>,
|
||||
mastodon: <a href='https://github.com/tootsuite/mastodon' rel='noopener noreferrer' target='_blank'>Mastodon</a>,
|
||||
pleroma: <a href='https://pleroma.social' rel='noopener noreferrer' target='_blank'>Pleroma</a>
|
||||
pleroma: <a href='https://pleroma.social' rel='noopener noreferrer' target='_blank'>Pleroma</a>,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -29,8 +29,8 @@ const PageOne = ({ acct, domain }) => (
|
|||
|
||||
<div>
|
||||
<h1><FormattedMessage id='onboarding.page_one.welcome' defaultMessage='Welcome to {domain}!' values={{ domain }} /></h1>
|
||||
<p><FormattedMessage id='onboarding.page_one.federation' defaultMessage='{domain} is an "instance" of Mastodon. Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.' values={{ domain }} /></p>
|
||||
<p><FormattedMessage id='onboarding.page_one.handle' defaultMessage='You are on {domain}, so your full handle is {handle}' values={{ domain, handle: <strong>@{acct}@{domain}</strong> }} /></p>
|
||||
<p><FormattedMessage id='onboarding.page_one.fediverse' defaultMessage='{domain} is a Fediverse node, running Pleroma. The Fediverse is decentralized federated network made of many independent nodes, like email.' values={{ domain, handle: <strong>{acct}@{domain}</strong> }} /></p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -49,7 +49,7 @@ const PageTwo = ({ intl, myAccount }) => (
|
|||
privacy='public'
|
||||
text='Awoo! #introductions'
|
||||
spoilerText=''
|
||||
suggestions={ [] }
|
||||
suggestions={[]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -131,8 +131,6 @@ const PageSix = ({ admin, domain }) => {
|
|||
adminSection = (
|
||||
<p>
|
||||
<FormattedMessage id='onboarding.page_six.admin' defaultMessage="Your instance's admin is {admin}." values={{ admin: <Permalink href={admin.get('url')} to={`/accounts/${admin.get('id')}`}>@{admin.get('acct')}</Permalink> }} />
|
||||
<br />
|
||||
<FormattedMessage id='onboarding.page_six.read_guidelines' defaultMessage="Please read {domain}'s {guidelines}!" values={{ domain, guidelines: <a href='/about/more' target='_blank'><FormattedMessage id='onboarding.page_six.guidelines' defaultMessage='community guidelines' /></a> }} />
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
@ -141,9 +139,8 @@ const PageSix = ({ admin, domain }) => {
|
|||
<div className='onboarding-modal__page onboarding-modal__page-six'>
|
||||
<h1><FormattedMessage id='onboarding.page_six.almost_done' defaultMessage='Almost done...' /></h1>
|
||||
{adminSection}
|
||||
<p><FormattedMessage id='onboarding.page_six.github' defaultMessage='{domain} runs on Glitchsoc. Glitchsoc is a friendly {fork} of {Mastodon}. Glitchsoc is fully compatible with all Mastodon apps and instances. Glitchsoc is free open-source software. You can report bugs, request features, or contribute to the code on {github}.' values={{ domain, fork: <a href='https://en.wikipedia.org/wiki/Fork_(software_development)' target='_blank' rel='noopener'>fork</a>, Mastodon: <a href='https://github.com/tootsuite/mastodon' target='_blank' rel='noopener'>Mastodon</a>, github: <a href='https://github.com/glitch-soc/mastodon' target='_blank' rel='noopener'>GitHub</a> }} /></p>
|
||||
<p><FormattedMessage id='onboarding.page_six.apps_available' defaultMessage='There are {apps} available for iOS, Android and other platforms.' values={{ domain, apps: <a href='https://joinmastodon.org/apps' target='_blank' rel='noopener'><FormattedMessage id='onboarding.page_six.various_app' defaultMessage='mobile apps' /></a> }} /></p>
|
||||
<p><em><FormattedMessage id='onboarding.page_six.appetoot' defaultMessage='Bon Appetoot!' /></em></p>
|
||||
<p><FormattedMessage id='onboarding.page_six.github' defaultMessage='{domain} runs on Pleroma. Pleroma is a free, federated social networking server built on open protocols. It is compatible with GNU Social, Mastodon, and many other ActivityPub implementations. You can report bugs, request features, or contribute to the code on {gitlab}.' values={{ domain, gitlab: <a href='https://git.pleroma.social/pleroma/' target='_blank' rel='noopener'>Pleroma's Gitlab</a> }} /></p>
|
||||
<p><FormattedMessage id='onboarding.page_six.apps_available' defaultMessage='There are {apps} available for iOS, Android, SailfishOS and other platforms.' values={{ domain, apps: <a href='https://docs.pleroma.social/backend/clients/' target='_blank' rel='noopener'><FormattedMessage id='onboarding.page_six.various_app' defaultMessage='mobile apps' /></a> }} /></p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -386,7 +386,7 @@ class UI extends React.Component {
|
|||
navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);
|
||||
}
|
||||
|
||||
this.favicon = new Favico({ animation:"none" });
|
||||
this.favicon = new Favico({ animation:'none' });
|
||||
|
||||
this.props.dispatch(fetchMarkers());
|
||||
this.props.dispatch(expandHomeTimeline());
|
||||
|
@ -596,7 +596,7 @@ class UI extends React.Component {
|
|||
<PermaLink href={moved.get('url')} to={`/accounts/${moved.get('id')}`}>
|
||||
@{moved.get('acct')}
|
||||
</PermaLink>
|
||||
)}}
|
||||
) }}
|
||||
/>
|
||||
</div>)}
|
||||
<SwitchingColumnsArea location={location} layout={layout} navbarUnder={navbarUnder} onLayoutChange={this.handleLayoutChange}>
|
||||
|
|
|
@ -429,7 +429,7 @@ class Video extends React.PureComponent {
|
|||
|
||||
playerStyle.height = height;
|
||||
} else if (inline) {
|
||||
return (<div className={computedClass} ref={this.setPlayerRef} tabindex={0}></div>);
|
||||
return (<div className={computedClass} ref={this.setPlayerRef} tabindex={0} />);
|
||||
}
|
||||
|
||||
let warning;
|
||||
|
|
|
@ -84,7 +84,7 @@ const messages = {
|
|||
|
||||
'navigation_bar.direct': 'ダイレクトメッセージ',
|
||||
'navigation_bar.bookmarks': 'ブックマーク',
|
||||
'column.bookmarks': 'ブックマーク'
|
||||
'column.bookmarks': 'ブックマーク',
|
||||
};
|
||||
|
||||
export default Object.assign({}, inherited, messages);
|
|
@ -67,13 +67,13 @@ const messages = {
|
|||
'advanced_options.threaded_mode.short': 'Tryb wątków',
|
||||
'advanced_options.threaded_mode.long': 'Przechodzi do tworzenia odpowiedzi po publikacji wpisu',
|
||||
'advanced_options.threaded_mode.tooltip': 'Włączono tryb wątków',
|
||||
|
||||
|
||||
'column.bookmarks': 'Zakładki',
|
||||
'compose_form.sensitive': 'Oznacz zawartość multimedialną jako wrażliwą',
|
||||
'compose_form.spoiler': 'Ukryj tekst za ostrzeżeniem',
|
||||
'favourite_modal.combo': 'Możesz nacisnąć {combo}, aby pominąć to następnym razem',
|
||||
'tabs_bar.compose': 'Napisz',
|
||||
|
||||
|
||||
};
|
||||
|
||||
export default Object.assign({}, inherited, messages);
|
||||
|
|
|
@ -128,16 +128,16 @@ function apiStatusToTextMentions (state, status) {
|
|||
}
|
||||
|
||||
return set.union(status.mentions.filter(
|
||||
mention => mention.id !== me
|
||||
mention => mention.id !== me,
|
||||
).map(
|
||||
mention => `@${mention.acct} `
|
||||
mention => `@${mention.acct} `,
|
||||
)).join('');
|
||||
}
|
||||
|
||||
function apiStatusToTextHashtags (state, status) {
|
||||
const text = unescapeHTML(status.content);
|
||||
return ImmutableOrderedSet([]).union(recoverHashtags(status.tags, text).map(
|
||||
(name) => `#${name} `
|
||||
(name) => `#${name} `,
|
||||
)).join('');
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ function clearAll(state) {
|
|||
map.set('in_reply_to', null);
|
||||
map.update(
|
||||
'advanced_options',
|
||||
map => map.mergeWith(overwrite, state.get('default_advanced_options'))
|
||||
map => map.mergeWith(overwrite, state.get('default_advanced_options')),
|
||||
);
|
||||
map.set('privacy', state.get('default_privacy'));
|
||||
map.set('sensitive', false);
|
||||
|
@ -178,7 +178,7 @@ function continueThread (state, status) {
|
|||
map.set('in_reply_to', status.id);
|
||||
map.update(
|
||||
'advanced_options',
|
||||
map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(status.content) }))
|
||||
map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(status.content) })),
|
||||
);
|
||||
map.set('privacy', status.visibility);
|
||||
map.set('sensitive', false);
|
||||
|
@ -377,7 +377,7 @@ export default function compose(state = initialState, action) {
|
|||
map.set('privacy', privacyPreference(action.status.get('visibility'), state.get('default_privacy')));
|
||||
map.update(
|
||||
'advanced_options',
|
||||
map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(action.status.get('content')) }))
|
||||
map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(action.status.get('content')) })),
|
||||
);
|
||||
map.set('focusDate', new Date());
|
||||
map.set('caretPosition', null);
|
||||
|
@ -409,7 +409,7 @@ export default function compose(state = initialState, action) {
|
|||
map.set('poll', null);
|
||||
map.update(
|
||||
'advanced_options',
|
||||
map => map.mergeWith(overwrite, state.get('default_advanced_options'))
|
||||
map => map.mergeWith(overwrite, state.get('default_advanced_options')),
|
||||
);
|
||||
map.set('idempotencyKey', uuid());
|
||||
});
|
||||
|
|
|
@ -67,7 +67,7 @@ const deleteFromContexts = (immutableState, ids) => immutableState.withMutations
|
|||
|
||||
const filterContexts = (state, relationship, statuses) => {
|
||||
const ownedStatusIds = statuses.filter(status => status.get('account') === relationship.id)
|
||||
.map(status => status.get('id'));
|
||||
.map(status => status.get('id'));
|
||||
|
||||
return deleteFromContexts(state, ownedStatusIds);
|
||||
};
|
||||
|
|
|
@ -54,10 +54,10 @@ export default function listEditorReducer(state = initialState, action) {
|
|||
});
|
||||
case LIST_CREATE_REQUEST:
|
||||
case LIST_UPDATE_REQUEST:
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', true);
|
||||
map.set('isChanged', false);
|
||||
});
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', true);
|
||||
map.set('isChanged', false);
|
||||
});
|
||||
case LIST_CREATE_FAIL:
|
||||
case LIST_UPDATE_FAIL:
|
||||
return state.set('isSubmitting', false);
|
||||
|
|
|
@ -127,7 +127,7 @@ const clearUnread = (state) => {
|
|||
state = state.set('unread', state.get('pendingItems').size);
|
||||
const lastNotification = state.get('items').find(item => item !== null);
|
||||
return state.set('lastReadId', lastNotification ? lastNotification.get('id') : '0');
|
||||
}
|
||||
};
|
||||
|
||||
const updateTop = (state, top) => {
|
||||
state = state.set('top', top);
|
||||
|
@ -210,7 +210,7 @@ const recountUnread = (state, last_read_id) => {
|
|||
mutable.set('unread', mutable.get('pendingItems').count(item => item !== null) + mutable.get('items').count(item => item && compareId(item.get('id'), last_read_id) > 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default function notifications(state = initialState, action) {
|
||||
let st;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { PANEL_FETCH_SUCCESS, PLEROMA_CONFIG_FETCH_SUCCESS } from 'mastodon/acti
|
|||
|
||||
const initialPanel = ImmutableMap({
|
||||
enabled: false,
|
||||
panel: ''
|
||||
panel: '',
|
||||
});
|
||||
|
||||
export default function custom_panel(state = initialPanel, action) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export const preferencesLink = '/settings';
|
||||
export const profileLink = '/user-settings';
|
||||
export const preferencesLink = undefined; // '/settings/preferences';
|
||||
export const profileLink = undefined; // '/settings/profile';
|
||||
export const signOutLink = '/auth/sign_out';
|
||||
export const termsLink = '/terms';
|
||||
export const termsLink = undefined; // '/terms';
|
||||
export const accountAdminLink = (id) => `/pleroma/admin/#/users/${id}/`;
|
||||
export const statusAdminLink = (account_id, status_id) => `/pleroma/admin/#/users/${account_id}/`;
|
||||
export const filterEditLink = undefined; // (id) => `/filters/${id}/edit`;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
export function recoverHashtags (recognizedTags, text) {
|
||||
return recognizedTags.map(tag => {
|
||||
const re = new RegExp(`(?:^|[^\/\)\w])#(${tag.name})`, 'i');
|
||||
const matched_hashtag = text.match(re);
|
||||
return matched_hashtag ? matched_hashtag[1] : null;
|
||||
}
|
||||
const re = new RegExp(`(?:^|[^\/\)\w])#(${tag.name})`, 'i');
|
||||
const matched_hashtag = text.match(re);
|
||||
return matched_hashtag ? matched_hashtag[1] : null;
|
||||
},
|
||||
).filter(x => x !== null);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ const maybeSetNotificationsSettings = result => {
|
|||
|
||||
excludeTypes.forEach(x => showTypes[x] = false);
|
||||
set(result, ['settings', 'notifications', 'shows'], showTypes);
|
||||
}
|
||||
};
|
||||
|
||||
const element = document.getElementById('initial-state');
|
||||
const initialState = element && function () {
|
||||
|
|
|
@ -2,33 +2,9 @@ import Rails from '@rails/ujs';
|
|||
import { signOutLink } from 'flavours/glitch/util/backend_links';
|
||||
|
||||
export const logOut = () => {
|
||||
const form = document.createElement('form');
|
||||
|
||||
const methodInput = document.createElement('input');
|
||||
methodInput.setAttribute('name', '_method');
|
||||
methodInput.setAttribute('value', 'delete');
|
||||
methodInput.setAttribute('type', 'hidden');
|
||||
form.appendChild(methodInput);
|
||||
|
||||
const csrfToken = Rails.csrfToken();
|
||||
const csrfParam = Rails.csrfParam();
|
||||
|
||||
if (csrfParam && csrfToken) {
|
||||
const csrfInput = document.createElement('input');
|
||||
csrfInput.setAttribute('name', csrfParam);
|
||||
csrfInput.setAttribute('value', csrfToken);
|
||||
csrfInput.setAttribute('type', 'hidden');
|
||||
form.appendChild(csrfInput);
|
||||
}
|
||||
|
||||
const submitButton = document.createElement('input');
|
||||
submitButton.setAttribute('type', 'submit');
|
||||
form.appendChild(submitButton);
|
||||
|
||||
form.method = 'post';
|
||||
form.action = signOutLink;
|
||||
form.style.display = 'none';
|
||||
|
||||
document.body.appendChild(form);
|
||||
submitButton.click();
|
||||
fetch(signOutLink, {
|
||||
method: 'DELETE',
|
||||
}).then(() => {
|
||||
window.location = '/web/';
|
||||
});
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ export function assignHandlers (target, handlers) {
|
|||
// We just bind each handler to the `target`.
|
||||
const handle = target.handlers = {};
|
||||
Object.keys(handlers).forEach(
|
||||
key => handle[key] = handlers[key].bind(target)
|
||||
key => handle[key] = handlers[key].bind(target),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ store.dispatch(fetchCustomEmojis());
|
|||
|
||||
@connect(mapStateToProps)
|
||||
class MastodonMount extends React.PureComponent {
|
||||
|
||||
shouldUpdateScroll (_, { location }) {
|
||||
return location.state !== previewMediaState && location.state !== previewVideoState;
|
||||
}
|
||||
|
|
16
build.sh
16
build.sh
|
@ -1,20 +1,20 @@
|
|||
#!/bin/sh
|
||||
TARGET="${TARGET:-../pleroma}" # Where pleroma’s repository is sitting
|
||||
static_dir="priv/static" # Set this to instance/static when testing production build
|
||||
TARGET="${TARGET:-./distribution}" # Where pleroma’s repository is sitting
|
||||
mkdir -p $TARGET/emoji
|
||||
|
||||
die() {
|
||||
echo "Die: $@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -d "${TARGET}/priv/static" ] || die "${TARGET}/priv/static directory is missing, are you sure TARGET is set to a pleroma repository? (Info: TARGET=${TARGET} )"
|
||||
[ -d "${TARGET}" ] || die "${TARGET} directory is missing, are you sure TARGET is set to a pleroma repository? (Info: TARGET=${TARGET} )"
|
||||
|
||||
yarn install -D || die "Installing dependencies via yarn failed"
|
||||
|
||||
rm -rf public/packs public/assets
|
||||
env -i "PATH=$PATH" npm run build || die "Building the frontend failed"
|
||||
cp public/assets/sw.js "${TARGET}/${static_dir}/sw.js" || die "installing sw.js (service-worker) failed"
|
||||
rm -rf "${TARGET}/${static_dir}/packs" || die "Removing old assets in priv/static/packs failed"
|
||||
cp -r public/packs "${TARGET}/${static_dir}/packs" || die "Copying new assets in priv/static/packs failed"
|
||||
rm -rf "${TARGET}/${static_dir}/emoji/*.svg" || die "Removing the old emoji assets failed"
|
||||
cp -r public/emoji/* "${TARGET}/${static_dir}/emoji" || die "Installing the new emoji assets failed"
|
||||
cp public/assets/sw.js "${TARGET}/sw.js" || die "installing sw.js (service-worker) failed"
|
||||
rm -rf "${TARGET}/packs" || die "Removing old assets in priv/static/packs failed"
|
||||
cp -r public/packs "${TARGET}/packs" || die "Copying new assets in priv/static/packs failed"
|
||||
rm -rf "${TARGET}/emoji/*.svg" || die "Removing the old emoji assets failed"
|
||||
cp -r public/emoji/* "${TARGET}/emoji" || die "Installing the new emoji assets failed"
|
||||
|
|
|
@ -8,8 +8,8 @@ const glob = require('glob');
|
|||
|
||||
const configPath = resolve('config', 'webpacker.yml');
|
||||
const settings = safeLoad(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env.NODE_ENV];
|
||||
const flavourFiles = glob.sync('app/javascript/flavours/*/theme.yml');
|
||||
const skinFiles = glob.sync('app/javascript/skins/*/*');
|
||||
const flavourFiles = glob.sync('app/javascript/flavours/glitch/theme.yml');
|
||||
const skinFiles = glob.sync('app/javascript/skins/glitch/*');
|
||||
const flavours = {};
|
||||
|
||||
const core = function () {
|
||||
|
|
|
@ -21,7 +21,7 @@ module.exports = Object.keys(flavours).reduce(function (map, entry) {
|
|||
return map;
|
||||
}
|
||||
const locales = readdirSync(flavour.locales).filter(
|
||||
filename => /\.js(?:on)?$/.test(filename) && !/defaultMessages|whitelist|index/.test(filename)
|
||||
filename => /\.js(?:on)?$/.test(filename) && !/defaultMessages|whitelist|index/.test(filename),
|
||||
);
|
||||
const outPath = resolve('tmp', 'locales', entry);
|
||||
|
||||
|
@ -40,9 +40,9 @@ module.exports = Object.keys(flavours).reduce(function (map, entry) {
|
|||
// fall back to English (this is what react-intl does anyway)
|
||||
'node_modules/react-intl/locale-data/en.js',
|
||||
].filter(
|
||||
filename => existsSync(filename)
|
||||
filename => existsSync(filename),
|
||||
).map(
|
||||
filename => filename.replace(/(?:node_modules|app\/javascript)\//, '')
|
||||
filename => filename.replace(/(?:node_modules|app\/javascript)\//, ''),
|
||||
)[0];
|
||||
const localeContent = `//
|
||||
// locales/${entry}/${localeName}.js
|
||||
|
|
|
@ -50,7 +50,7 @@ const entries = Object.assign(
|
|||
{ locales: resolve('app', 'javascript', 'locales') },
|
||||
localePacks,
|
||||
reducePacks(core),
|
||||
Object.keys(flavours).reduce((map, entry) => reducePacks(flavours[entry], map), {})
|
||||
Object.keys(flavours).reduce((map, entry) => reducePacks(flavours[entry], map), {}),
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
"name": "@tootsuite/mastodon",
|
||||
"description": "mastodon",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"engines": {
|
||||
"node": ">=10.13 <13"
|
||||
},
|
||||
"scripts": {
|
||||
"postversion": "git push --tags",
|
||||
"build:development": "cross-env NODE_ENV=development webpack --config config/webpack/development.js",
|
||||
|
|
Loading…
Reference in a new issue