From bc642ac24b49c14dca382e7aabbc16130293d2f4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 16 Jan 2019 19:47:46 +0100 Subject: Redesign public hashtag page to use a masonry layout (#9822) --- app/javascript/mastodon/components/display_name.js | 12 +- app/javascript/mastodon/components/status.js | 2 +- .../features/standalone/hashtag_timeline/index.js | 86 +++++++---- .../features/status/components/detailed_status.js | 107 +++++++++++-- .../status/containers/detailed_status_container.js | 172 +++++++++++++++++++++ app/javascript/styles/mastodon/widgets.scss | 27 ++++ 6 files changed, 359 insertions(+), 47 deletions(-) create mode 100644 app/javascript/mastodon/features/status/containers/detailed_status_container.js (limited to 'app/javascript') diff --git a/app/javascript/mastodon/components/display_name.js b/app/javascript/mastodon/components/display_name.js index c2c40cb3f..acddf77c5 100644 --- a/app/javascript/mastodon/components/display_name.js +++ b/app/javascript/mastodon/components/display_name.js @@ -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 = @{account.get('acct')}; + let acct = account.get('acct'); + + if (acct.indexOf('@') === -1 && localDomain) { + acct = `${acct}@${localDomain}`; + } + + suffix = @{acct}; } return ( diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index fd0780025..20d838500 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -77,7 +77,7 @@ class Status extends ImmutablePureComponent { 'account', 'muted', 'hidden', - ] + ]; handleClick = () => { if (this.props.onClick) { diff --git a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js index 759922638..4e09b1948 100644 --- a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js @@ -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()) ? : undefined; return ( - - - - - + + {statusIds.map(statusId => ( +
+ +
+ )).toArray()} +
); } diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index b0dea8817..3ea8e9e74 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -11,6 +11,7 @@ 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'; export default class DetailedStatus extends ImmutablePureComponent { @@ -23,10 +24,17 @@ 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, + }; + + 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 +50,56 @@ 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: this.node.offsetHeight })); + + 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' }; + + 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,20 +146,51 @@ export default class DetailedStatus extends ImmutablePureComponent { if (status.get('visibility') === 'private') { reblogLink = ; + } else if (this.context.router) { + reblogLink = ( + + + + + + + ); + } else { + reblogLink = ( + + + + + + + ); + } + + if (this.context.router) { + favouriteLink = ( + + + + + + + ); } else { - reblogLink = ( - - - - - ); + favouriteLink = ( + + + + + + + ); } return ( -
+
- +
@@ -118,12 +200,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
- {applicationLink} · {reblogLink} · - - - - - + {applicationLink} · {reblogLink} · {favouriteLink}
); diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js new file mode 100644 index 000000000..2c0db0a6b --- /dev/null +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -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: @{account.get('acct')} }} />, + 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)); diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss index 87e633c70..cabef807e 100644 --- a/app/javascript/styles/mastodon/widgets.scss +++ b/app/javascript/styles/mastodon/widgets.scss @@ -425,3 +425,30 @@ border-radius: 0; } } + +$maximum-width: 1235px; +$fluid-breakpoint: $maximum-width + 20px; + +.statuses-grid { + min-height: 600px; + + &__item { + width: (960px - 20px) / 3; + + @media screen and (max-width: $fluid-breakpoint) { + width: (940px - 20px) / 3; + } + + @media screen and (max-width: $no-gap-breakpoint) { + width: 100vw; + } + } + + .detailed-status { + border-radius: 4px; + + @media screen and (max-width: $no-gap-breakpoint) { + border-bottom: 1px solid lighten($ui-base-color, 12%); + } + } +} -- cgit From 3b3a4d8a1709b8f4a9ffe67d21707117c75f9fe8 Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 16 Jan 2019 20:36:10 +0100 Subject: Fix public hashtag timeline width on mobile, fix scrollbar width compensation (#9824) * Fix hashtag timeline width being potentially larger than window width * Add automatic computation of scrollbar width --- app/javascript/packs/public.js | 8 ++++++++ app/javascript/styles/mastodon/about.scss | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'app/javascript') diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index a86dc7831..4ab27c769 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -108,6 +108,14 @@ function main() { if (parallaxComponents.length > 0 ) { new Rellax('.parallax', { speed: -1 }); } + + if (document.body.classList.contains('with-modals')) { + const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; + const scrollbarWidthStyle = document.createElement('style'); + scrollbarWidthStyle.id = 'scrollbar-width'; + document.head.appendChild(scrollbarWidthStyle); + scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0); + } }); delegate(document, '.webapp-btn', 'click', ({ target, button }) => { diff --git a/app/javascript/styles/mastodon/about.scss b/app/javascript/styles/mastodon/about.scss index 47ac9265b..c6f249fab 100644 --- a/app/javascript/styles/mastodon/about.scss +++ b/app/javascript/styles/mastodon/about.scss @@ -364,7 +364,7 @@ $small-breakpoint: 960px; @media screen and (max-width: $column-breakpoint) { .grid { - grid-template-columns: auto; + grid-template-columns: 100%; .column-0 { display: block; -- cgit From 30af4ee65ff43c17d6f7b1b64d6bf1d8699f37c8 Mon Sep 17 00:00:00 2001 From: tmm576 Date: Thu, 17 Jan 2019 03:22:12 -0500 Subject: Hide floating action button on search and getting started pages (#9826) --- app/javascript/mastodon/features/ui/components/columns_area.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript') diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js index ed338c2eb..b7e350cbc 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.js +++ b/app/javascript/mastodon/features/ui/components/columns_area.js @@ -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 { -- cgit From 8b1990355974543542544e56d2046bc0c9c8716b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 17 Jan 2019 14:06:08 +0100 Subject: Improve the public hashtag page (#9831) - Fix height not updating when clicking show more on public hashtag page - Add header to the public hashtag page - Change text size and margins on the public hashtag page --- app/javascript/mastodon/common.js | 6 +++- .../features/standalone/hashtag_timeline/index.js | 2 +- .../features/status/components/detailed_status.js | 35 ++++++++++++---------- app/javascript/mastodon/features/status/index.js | 5 +++- app/javascript/styles/mastodon/widgets.scss | 28 +++++++++++++++++ app/views/tags/_features.html.haml | 25 ---------------- app/views/tags/show.html.haml | 6 +++- 7 files changed, 63 insertions(+), 44 deletions(-) delete mode 100644 app/views/tags/_features.html.haml (limited to 'app/javascript') diff --git a/app/javascript/mastodon/common.js b/app/javascript/mastodon/common.js index 2b10b8c30..fba21316a 100644 --- a/app/javascript/mastodon/common.js +++ b/app/javascript/mastodon/common.js @@ -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 + } }; diff --git a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js index 4e09b1948..333726f94 100644 --- a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js +++ b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js @@ -80,7 +80,7 @@ class HashtagTimeline extends React.PureComponent {
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 3ea8e9e74..2921a26f9 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -12,6 +12,7 @@ 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 { @@ -27,6 +28,7 @@ export default class DetailedStatus extends ImmutablePureComponent { measureHeight: PropTypes.bool, onHeightChange: PropTypes.func, domain: PropTypes.string.isRequired, + compact: PropTypes.bool, }; state = { @@ -52,7 +54,7 @@ export default class DetailedStatus extends ImmutablePureComponent { _measureHeight (heightJustChanged) { if (this.props.measureHeight && this.node) { - scheduleIdleTask(() => this.node && this.setState({ height: this.node.offsetHeight })); + scheduleIdleTask(() => this.node && this.setState({ height: this.node.scrollHeight })); if (this.props.onHeightChange && heightJustChanged) { this.props.onHeightChange(); @@ -86,6 +88,7 @@ export default class DetailedStatus extends ImmutablePureComponent { 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; @@ -187,20 +190,22 @@ export default class DetailedStatus extends ImmutablePureComponent { } return ( -
- -
- -
- - - - {media} - -
- - - {applicationLink} · {reblogLink} · {favouriteLink} +
+
+ +
+ +
+ + + + {media} + +
+ + + {applicationLink} · {reblogLink} · {favouriteLink} +
); diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index a092f7bb1..d48b682eb 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -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} /> Date: Thu, 17 Jan 2019 17:27:51 -0500 Subject: Allow event defaults on index for text data transfer (#9840) --- app/javascript/mastodon/features/ui/index.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'app/javascript') diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index a59c0a257..f01c2bf24 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -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 }); } -- cgit From b8894c429ae294801ffd59b2d1ee534eeb80dc24 Mon Sep 17 00:00:00 2001 From: "Mélanie Chauvel (ariasuni)" Date: Thu, 17 Jan 2019 23:28:30 +0100 Subject: Fix slightly cropped font on settings page dropdowns when using system font (#9839) --- app/javascript/styles/mastodon/forms.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript') diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index 6132dd1ae..bab982706 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -419,7 +419,7 @@ code { background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,") no-repeat right 8px center / auto 16px; border: 1px solid darken($ui-base-color, 14%); border-radius: 4px; - padding: 10px; + padding-left: 10px; padding-right: 30px; height: 41px; } -- cgit From 90ff2e7608321389e968f512e709a1e0a7bf2657 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 18 Jan 2019 00:48:09 +0100 Subject: Weblate translations (2019-01-17) (#9844) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Welsh) Currently translated at 94.7% (337 of 356 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/cy/ * Translated using Weblate (Czech) Currently translated at 99.9% (751 of 752 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/cs/ * Translated using Weblate (Romanian) Currently translated at 99.2% (353 of 356 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ro/ * Translated using Weblate (Romanian) Currently translated at 11.8% (89 of 752 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ro/ * Translated using Weblate (German) Currently translated at 99.9% (751 of 752 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (German) Currently translated at 100.0% (107 of 107 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/de/ * Translated using Weblate (German) Currently translated at 99.9% (751 of 752 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (Serbian) Currently translated at 96.8% (61 of 63 strings) Translation: Mastodon/Devise Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/sr/ * Translated using Weblate (Slovak) Currently translated at 100.0% (356 of 356 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/sk/ * Translated using Weblate (Serbian) Currently translated at 74.8% (80 of 107 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/sr/ * Translated using Weblate (Serbian) Currently translated at 98.4% (62 of 63 strings) Translation: Mastodon/Devise Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/sr/ нисам сигуран за ово "и не направите нову". слијед ријечи ми је мало чудан? * Translated using Weblate (Serbian) Currently translated at 75.7% (81 of 107 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/sr/ преподешавања за ПРЕСЕТ * Translated using Weblate (Catalan) Currently translated at 100.0% (356 of 356 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ca/ * Translated using Weblate (Serbian) Currently translated at 80.4% (86 of 107 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/sr/ * i18n-tasks normalize * yarn manage:translations --- app/javascript/mastodon/locales/ca.json | 2 +- app/javascript/mastodon/locales/cy.json | 22 +++---- .../mastodon/locales/defaultMessages.json | 37 +++++++++++ app/javascript/mastodon/locales/ro.json | 2 +- app/javascript/mastodon/locales/sk.json | 2 +- config/locales/de.yml | 72 +++++++++++----------- config/locales/devise.sr.yml | 22 +++++++ config/locales/ro.yml | 4 +- config/locales/simple_form.de.yml | 26 ++++---- config/locales/simple_form.sr.yml | 14 +++++ 10 files changed, 139 insertions(+), 64 deletions(-) (limited to 'app/javascript') diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 302ff2573..11c31877c 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -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.", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 471b70439..f35b96244 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -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", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 951081f8d..6ac8160ba 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -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": [ { diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index f213f8ea3..a1a514f49 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -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", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 91ecbbce7..a3467785a 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -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", diff --git a/config/locales/de.yml b/config/locales/de.yml index a5315f9d3..e68448abd 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,7 +1,7 @@ --- de: about: - about_hashtag_html: Dies sind öffentliche Beiträge, die mit #%{hashtag} getaggt wurden. Wenn du ein Konto irgendwo im Fediversum besitzt, kannst du mit ihnen interagieren. + about_hashtag_html: Dies sind öffentliche Beiträge, die mit #%{hashtag} getaggt wurden. Wenn du irgendwo im Fediversum ein Konto besitzt, kannst du mit ihnen interagieren. about_mastodon_html: Mastodon ist ein soziales Netzwerk. Es basiert auf offenen Web-Protokollen und freier, quelloffener Software. Es ist dezentral (so wie E-Mail!). about_this: Über diese Instanz administered_by: 'Administriert von:' @@ -22,7 +22,7 @@ de: not_a_product_title: Du bist ein Mensch und keine Ware real_conversation_body: Mit 500 Zeichen pro Beitrag und Features wie Inhalts- und Bilderwarnungen kannst du dich so ausdrücken, wie du es möchtest. real_conversation_title: Geschaffen für echte Gespräche - within_reach_body: Verschiedene Apps für iOS, Android und andere Plattformen erlauben dir, dank unseres blühenden API-Ökosystems, dich von überall auf dem Laufenden zu halten. + within_reach_body: Verschiedene Apps für iOS, Android und andere Plattformen erlauben es dir, dank unseres blühenden API-Ökosystems, dich von überall auf dem Laufenden zu halten. within_reach_title: Immer für dich da generic_description: "%{domain} ist ein Server im Netzwerk" hosted_on: Mastodon, beherbergt auf %{domain} @@ -44,8 +44,8 @@ de: choices_html: "%{name} empfiehlt:" follow: Folgen followers: - one: Folgende - other: Follower + one: Folgender + other: Folgende following: Folgt joined: Beigetreten am %{date} last_active: zuletzt aktiv @@ -81,7 +81,7 @@ de: accounts: are_you_sure: Bist du sicher? avatar: Profilbild - by_domain: Domäne + by_domain: Domain change_email: changed_msg: E-Mail-Adresse des Kontos erfolgreich geändert! current_email: Aktuelle E-Mail-Adresse @@ -105,7 +105,7 @@ de: enable: Freischalten enabled: Freigegeben feed_url: Feed-URL - followers: Folger + followers: Folgende followers_local: "(%{local} lokal)" followers_url: URL des Folgenden follows: Folgt @@ -194,17 +194,17 @@ de: disable_user: "%{name} hat den Login für Benutzer:in %{target} deaktiviert" enable_custom_emoji: "%{name} hat das %{target} Emoji aktiviert" enable_user: "%{name} hat die Anmeldung für di:en Benutzer:in %{target} aktiviert" - memorialize_account: "%{name} hat %{target}s Profil in eine Gedenkseite umgewandelt" + memorialize_account: "%{name} hat %{target}s Konto in eine Gedenkseite umgewandelt" promote_user: "%{name} hat %{target} befördert" remove_avatar_user: "%{name} hat das Profilbild von %{target} entfernt" reopen_report: "%{name} hat die Meldung %{target} wieder geöffnet" reset_password_user: "%{name} hat das Passwort für di:en Benutzer:in %{target} zurückgesetzt" resolve_report: "%{name} hat die Meldung %{target} bearbeitet" - silence_account: "%{name} hat %{target}s Account stummgeschaltet" - suspend_account: "%{name} hat %{target}s Account gesperrt" + silence_account: "%{name} hat %{target}s Konto stummgeschaltet" + suspend_account: "%{name} hat %{target}s Konto gesperrt" unassigned_report: "%{name} hat die Zuweisung der Meldung %{target} entfernt" - unsilence_account: "%{name} hat die Stummschaltung von %{target}s Account aufgehoben" - unsuspend_account: "%{name} hat die Sperrung von %{target}s Account aufgehoben" + unsilence_account: "%{name} hat die Stummschaltung von %{target}s Konto aufgehoben" + unsuspend_account: "%{name} hat die Sperrung von %{target}s Konto aufgehoben" update_custom_emoji: "%{name} hat das %{target} Emoji aktualisiert" update_status: "%{name} hat den Status von %{target} aktualisiert" deleted_status: "(gelöschter Beitrag)" @@ -300,12 +300,12 @@ de: title: Neue E-Mail-Domain-Blockade title: E-Mail-Domain-Blockade followers: - back_to_account: Zurück zum Account + back_to_account: Zurück zum Konto title: "%{acct}'s Follower" instances: delivery_available: Zustellung ist verfügbar known_accounts: - one: "%{count} bekannter Account" + one: "%{count} bekanntes Konto" other: "%{count} bekannte Accounts" moderation: all: Alle @@ -506,8 +506,8 @@ de: invalid_reset_password_token: Das Token zum Zurücksetzen des Passworts ist ungültig oder abgelaufen. Bitte fordere ein neues an. login: Anmelden logout: Abmelden - migrate_account: Ziehe zu einem anderen Account um - migrate_account_html: Wenn du es wünschst diesen Account zu einem anderen umzuziehen, dann kannst du es hier einstellen. + migrate_account: Ziehe zu einem anderen Konto um + migrate_account_html: Wenn du wünschst, dieses Konto zu einem anderen umzuziehen, kannst du dies hier einstellen. or: oder or_log_in_with: Oder anmelden mit providers: @@ -521,7 +521,7 @@ de: set_new_password: Neues Passwort setzen authorize_follow: already_following: Du folgst diesem Konto bereits - error: Das Profil konnte nicht geladen werden + error: Das Remote-Konto konnte nicht geladen werden follow: Folgen follow_request: 'Du hast eine Folgeanfrage gesendet an:' following: 'Erfolg! Du folgst nun:' @@ -655,7 +655,7 @@ de: table: expires_at: Läuft ab uses: Verwendungen - title: Leute Einladen + title: Leute einladen lists: errors: limit: Du hast die maximale Anzahl an Listen erreicht @@ -664,10 +664,10 @@ de: images_and_video: Es kann kein Video an einen Beitrag, der bereits Bilder enthält, angehängt werden too_many: Es können nicht mehr als 4 Bilder angehängt werden migrations: - acct: benutzername@domain des neuen Accounts + acct: benutzername@domain des neuen Kontos currently_redirecting: 'Deine Profilweiterleitung wurde gesetzt auf:' proceed: Speichern - updated_msg: Deine Account-Migrationseinstellungen wurden erfolgreich aktualisiert! + updated_msg: Deine Konto-Migrationseinstellungen wurden erfolgreich aktualisiert! moderation: title: Moderation notification_mailer: @@ -729,7 +729,7 @@ de: remote_follow: acct: Profilname@Domain, von wo aus du dieser Person folgen möchtest missing_resource: Die erforderliche Weiterleitungs-URL für dein Konto konnte nicht gefunden werden - no_account_html: Noch keinen Account? Du kannst dich hier anmelden + no_account_html: Noch kein Konto? Du kannst dich hier anmelden proceed: Weiter prompt: 'Du wirst dieser Person folgen:' reason_html: "Warum ist dieser Schritt erforderlich?%{instance} ist möglicherweise nicht der Server auf dem du registriert bist, also müssen wir dich erst auf deinen Heimserver weiterleiten." @@ -774,7 +774,7 @@ de: weibo: Weibo current_session: Aktuelle Sitzung description: "%{browser} auf %{platform}" - explanation: Dies sind die Webbrowser, die derzeit in dein Mastodon-Konto eingeloggt sind. + explanation: Dies sind die Webbrowser, die derzeit in deinem Mastodon-Konto eingeloggt sind. ip: IP-Adresse platforms: adobe_air: Adobe Air @@ -801,7 +801,7 @@ de: export: Datenexport followers: Autorisierte Folgende import: Datenimport - migrate: Account-Umzug + migrate: Konto-Umzug notifications: Benachrichtigungen preferences: Einstellungen settings: Einstellungen @@ -842,7 +842,7 @@ de: stream_entries: pinned: Angehefteter Beitrag reblogged: teilte - sensitive_content: Heikle Inhalte + sensitive_content: Sensible Inhalte terms: body_html: |

Datenschutzerklärung

@@ -949,33 +949,33 @@ de: manual_instructions: 'Wenn du den QR-Code nicht einlesen kannst und ihn manuell eingeben musst, ist hier das Klartext-Geheimnis:' recovery_codes: Wiederherstellungs-Codes sichern recovery_codes_regenerated: Wiederherstellungscodes erfolgreich neu generiert - recovery_instructions_html: Wenn du den Zugang zu deinem Telefon verlieren solltest, kannst du einen untenstehenden Wiederherstellungscodes benutzen, um wieder auf dein Konto zugreifen zu können. Bewahre die Wiederherstellungscodes gut auf. Du könntest sie beispielsweise ausdrucken und bei deinen restlichen wichtigen Dokumenten aufbewahren. + recovery_instructions_html: Wenn du den Zugang zu deinem Telefon verlieren solltest, kannst du einen untenstehenden Wiederherstellungscode benutzen, um wieder auf dein Konto zugreifen zu können. Bewahre die Wiederherstellungscodes gut auf. Du könntest sie beispielsweise ausdrucken und bei deinen restlichen wichtigen Dokumenten aufbewahren. setup: Einrichten wrong_code: Der eingegebene Code war ungültig! Stimmen Serverzeit und Gerätezeit? user_mailer: backup_ready: - explanation: Du hast ein vollständiges Backup von deinem Mastodon-Account angefragt. Es kann jetzt heruntergeladen werden! + explanation: Du hast ein vollständiges Backup von deinem Mastodon-Konto angefragt. Es kann jetzt heruntergeladen werden! subject: Dein Archiv ist bereit zum Download title: Archiv-Download warning: explanation: - disable: Solange dein Account eingefroren ist sind deine Benutzerdaten intakt, aber du kannst nichts tun bis dein Account entsperrt wurde. - silence: Solange dein Account limitiert ist können nur Leute, die dir bereits folgen deine Beiträge auf dem Server sehen und es könnte sein, dass du von verschiedenen öffentlichen Listungen ausgeschlossen wirst. Andererseits können andere dir manuell folgen. - suspend: Dein Account wurde gesperrt und alle deine Beiträge und hochgeladenen Medien wurden unwiderruflich vom Server und anderen Servern wo du Follower hattest gelöscht. + disable: Solange dein Konto eingefroren ist, sind deine Benutzerdaten intakt; aber du kannst nichts tun, bis dein Konto entsperrt wurde. + silence: Solange dein Konto limitiert ist, können nur die Leute, die dir bereits folgen, deine Beiträge auf dem Server sehen und es könnte sein, dass du von verschiedenen öffentlichen Listungen ausgeschlossen wirst. Andererseits können andere dir manuell folgen. + suspend: Dein Konto wurde gesperrt und alle deine Beiträge und hochgeladenen Medien wurden unwiderruflich vom Server und anderen Servern, bei denen du Folgende hattest, gelöscht. review_server_policies: Serverrichtlinien ansehen subject: - disable: Dein Account %{acct} wurde eingefroren + disable: Dein Konto %{acct} wurde eingefroren none: Warnung für %{acct} - silence: Dein Account %{acct} wurde limitiert - suspend: Dein Account %{acct} wurde gesperrt + silence: Dein Konto %{acct} wurde limitiert + suspend: Dein Konto %{acct} wurde gesperrt title: - disable: Account eingefroren + disable: Konto eingefroren none: Warnung - silence: Account limitiert - suspend: Account gesperrt + silence: Konto limitiert + suspend: Konto gesperrt welcome: edit_profile_action: Profil einstellen - edit_profile_step: Du kannst dein Profil anpassen, indem du einen Avatar oder ein Titelbild hochlädst oder deinen Anzeigenamen änderst und mehr. Wenn du deine Follower vorher überprüfen möchtest, bevor sie dir folgen können, dann kannst du dein Profil sperren. + edit_profile_step: Du kannst dein Profil anpassen, indem du einen Avatar oder ein Titelbild hochlädst oder deinen Anzeigenamen änderst und mehr. Wenn du deine Folgenden vorher überprüfen möchtest, bevor sie dir folgen können, dann kannst du dein Profil sperren. explanation: Hier sind ein paar Tipps, um loszulegen final_action: Fang an zu posten final_step: 'Fang an zu posten! Selbst ohne Follower werden deine öffentlichen Beitrage von anderen gesehen, zum Beispiel auf der lokalen Zeitleiste oder in Hashtags. Vielleicht möchtest du dich vorstellen mit dem #introductions-Hashtag.' @@ -998,5 +998,5 @@ de: seamless_external_login: Du bist angemeldet über einen Drittanbieter-Dienst, weswegen Passwort- und E-Maileinstellungen nicht verfügbar sind. signed_in_as: 'Angemeldet als:' verification: - explanation_html: 'Du kannst bestätigen, dass die Links in deinen Profil-Metadaten dir gehören. Dafür muss die verlinkte Website einen Link zurück auf dein Mastodon-Profil enthalten. Dieser Link muss ein rel="me"-Attribut enthalten. Der Linktext is dabei egal. Hier ist ein Beispiel:' + explanation_html: 'Du kannst bestätigen, dass die Links in deinen Profil-Metadaten dir gehören. Dafür muss die verlinkte Website einen Link zurück auf dein Mastodon-Profil enthalten. Dieser Link muss ein rel="me"-Attribut enthalten. Der Linktext ist dabei egal. Hier ist ein Beispiel:' verification: Verifizierung diff --git a/config/locales/devise.sr.yml b/config/locales/devise.sr.yml index 9d1359695..9061e01d4 100644 --- a/config/locales/devise.sr.yml +++ b/config/locales/devise.sr.yml @@ -17,11 +17,33 @@ sr: unconfirmed: Пре наставка морате потврдити свој налог. mailer: confirmation_instructions: + action: Потврдите адресу е-поште + action_with_app: Потврди и врати се на %{app} + explanation: Направили сте налог на %{host} са адресом ове е-поште. На један клик сте удаљени од активирања. Ако ово нисте ви, молимо игноришите ову е-пошту. + extra_html: Молимо да такође проверите правила ове инстанце и наше услове коришћења. subject: 'Мастодонт: Упутство за потврду корисничког налога на инстанци %{instance}' + title: Потврдите адресу е-поште + email_changed: + explanation: 'Адреса ове е-поште за ваш налог ће бити промењена у:' + extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога. + subject: 'Мастодон: Е-пошта промењена' + title: Нова адреса е-поште password_change: + explanation: Лозинка вашег налога је промењена. + extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога. subject: 'Мастодонт: Лозинка промењена' + title: Лозинка промењена + reconfirmation_instructions: + explanation: Потврдите нову адресу да бисте променили е-пошту. + extra: Ако ова промена није иницирана са ваше стране, молимо игноришите ову е-пошту. Адреса е-пошта за овај Мастодон налог неће бити промењена док не приступите повезници/линку изнад. + subject: 'Мастодон: Потврдите е-пошту за %{instance}' + title: Потврдите адресу е-поште reset_password_instructions: + action: Лозинка промењена + explanation: Затражили сте нову лозинку за ваш налог. + extra: Ако нисте затражили ово, молимо игноришите ову е-пошту. Ваша лозинка неће бити промењена док не приступите повезници/линку изнад и не направите нову. subject: 'Мастодонт: Упутство за ресетовање лозинке' + title: Лозинка ресетована unlock_instructions: subject: 'Мастодонт: Упутство за откључавање корисничког налога' omniauth_callbacks: diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 60a38b7c6..aa4d3c967 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -1,6 +1,8 @@ --- ro: about: + features: + not_a_product_title: Ești o persoană, nu un produs hosted_on: Mastodon găzduit de %{domain} accounts: posts: @@ -64,7 +66,7 @@ ro: success_msg: Contul tău a fost șterg. Nu mai poate fi recuperat :D warning_html: Doar ștergerea conținutului de pe acest server este garantată. Conținutul tău care a fost redistribuit în alte instațe e posibil să lase urme. Serverele deconecate sau care nu mai sunt abonate la actualizările contului tău nu își vor mai actualiza baza de date. directories: - explanation: Descoperă utilizatori în funcție de interesele lor + explanation: Descoperă oameni și companii în funcție de interesele lor explore_mastodon: Explorează %{title} people: few: "%{count} persoană" diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index d6e7942b3..3958e315f 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -10,14 +10,14 @@ de: type_html: Wähle aus, was du mit %{acct} machen möchtest warning_preset_id: Optional. Du kannst immer noch eigenen Text an das Ende der Vorlage hinzufügen defaults: - autofollow: Leute die sich über deine Einladung registrieren werden dir automatisch folgen + autofollow: Leute, die sich über deine Einladung registrieren, werden dir automatisch folgen avatar: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert bot: Dieses Konto führt lediglich automatisierte Aktionen durch und wird möglicherweise nicht überwacht context: Ein oder mehrere Aspekte, wo der Filter greifen soll digest: Wenn du lange Zeit inaktiv bist, wird dir eine Zusammenfassung von Erwähnungen in deiner Abwesenheit zugeschickt - discoverable_html: Das Verzeichnis lässt dich neue Benutzerkonten finden basierend auf Interessen und Aktivitäten. Dies benötigt mindestens %{min_followers} Follower - email: Du wirst ein Bestätigungs-E-Mail erhalten - fields: Du kannst bis zu 4 Elemente als Tabelle dargestellt auf deinem Profil anzeigen lassen + discoverable_html: Das Verzeichnis lässt dich basierend auf Interessen und Aktivitäten neue Benutzerkonten finden. Dies benötigt mindestens %{min_followers} Follower + email: Du wirst eine Bestätigungs-E-Mail erhalten + fields: Du kannst bis zu 4 Elemente auf deinem Profil anzeigen lassen, die als Tabelle dargestellt werden header: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert inbox_url: Kopiere die URL von der Startseite des gewünschten Relays irreversible: Gefilterte Beiträge werden unwiderruflich gefiltert, selbst wenn der Filter später entfernt wurde @@ -31,11 +31,11 @@ de: setting_display_media_default: Verstecke Medien, die als sensibel markiert sind setting_display_media_hide_all: Alle Medien immer verstecken setting_display_media_show_all: Medien, die als sensibel markiert sind, immer anzeigen - setting_hide_network: Wem du folgst und wer dir folgt wird in deinem Profil nicht angezeigt + setting_hide_network: Wem du folgst und wer dir folgt, wird in deinem Profil nicht angezeigt setting_noindex: Betrifft dein öffentliches Profil und deine Beiträge setting_theme: Wirkt sich darauf aus, wie Mastodon aussieht, egal auf welchem Gerät du eingeloggt bist. username: Dein Benutzer:innen-Name wird auf %{domain} nur einmal vorkommen - whole_word: Wenn das Schlüsselwort oder -phrase nur Buchstaben und Zahlen enthält, wird es nur angewendet werden, wenn es dem ganzen Wort entspricht + whole_word: Wenn das Schlagwort oder die Phrase nur Buchstaben und Zahlen enthält, wird es nur angewendet, wenn es dem ganzen Wort entspricht imports: data: CSV-Datei, die aus einer anderen Mastodon-Instanz exportiert wurde sessions: @@ -60,7 +60,7 @@ de: suspend: Deaktivieren und unwiderruflich Benutzerdaten löschen warning_preset_id: Benutze eine Warnungsvorlage defaults: - autofollow: Einladen, um deinen Account zu folgen + autofollow: Einladen, um deinem Account zu folgen avatar: Profilbild bot: Dieser Benutzer ist ein Bot chosen_languages: Sprachen filtern @@ -76,7 +76,7 @@ de: fields: Profil-Metadaten header: Kopfbild inbox_url: Inbox-URL des Relays - irreversible: Fallen lassen anstatt es zu verstecken + irreversible: Verwerfen statt verstecken locale: Sprache der Benutzeroberfläche locked: Gesperrtes Profil max_uses: Maximale Verwendungen @@ -90,28 +90,28 @@ de: setting_boost_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag geteilt wird setting_default_language: Beitragssprache setting_default_privacy: Beitragssichtbarkeit - setting_default_sensitive: Medien immer als heikel markieren + setting_default_sensitive: Medien immer als sensibel markieren setting_delete_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag gelöscht wird setting_display_media: Medien-Anzeige setting_display_media_default: Standard setting_display_media_hide_all: Alle verstecken setting_display_media_show_all: Alle anzeigen - setting_expand_spoilers: Toots mit Inhaltswarnungen immer ausklappen + setting_expand_spoilers: Beiträge mit Inhaltswarnungen immer ausklappen setting_hide_network: Blende dein Netzwerk aus setting_noindex: Suchmaschinen-Indexierung verhindern setting_reduce_motion: Bewegung in Animationen verringern setting_system_font_ui: Standardschriftart des Systems verwenden setting_theme: Theme der Website - setting_unfollow_modal: Bestätigungsdialog anzeigen, bevor jemand entfolgt wird + setting_unfollow_modal: Bestätigungsdialog anzeigen, bevor jemandem entfolgt wird severity: Schweregrad type: Importtyp username: Profilname - username_or_email: Profilname oder Email + username_or_email: Profilname oder E-Mail whole_word: Ganzes Wort interactions: must_be_follower: Benachrichtigungen von Nicht-Folgenden blockieren must_be_following: Benachrichtigungen von Profilen blockieren, denen ich nicht folge - must_be_following_dm: Private Nachrichten von Profilen denen ich nicht folge blockieren + must_be_following_dm: Private Nachrichten von Profilen, denen ich nicht folge, blockieren notification_emails: digest: Schicke Übersichts-E-Mails favourite: E-Mail senden, wenn jemand meinen Beitrag favorisiert diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index c6294d4ba..d88c40323 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -2,12 +2,21 @@ sr: simple_form: hints: + account_warning_preset: + text: Можете користити синтаксу труба, као што су нпр. УРЛ-ова, тарабе и помињања + admin_account_action: + send_email_notification: Корисник ће добити објашњење тога шта му се десило са налога + text_html: Опционално. Можете користити синтаксу труба. Можете додати упозоравајућа преподешавање да сачувате време + type_html: Изаберите шта да радите са %{acct} + warning_preset_id: Опционално. Можете и даље додати прилагођени текст на крај пресета defaults: autofollow: Особе које се пријаве кроз позивнице ће вас аутоматски запратити avatar: PNG, GIF или JPG. Највише %{size}. Биће смањена на %{dimensions}px bot: Овај налог углавном врши аутоматизоване радње и можда се не надгледа context: Један или више контекста у којима треба да се примени филтер digest: Послато после дужег периода неактивности са прегледом свих битних ствари које сте добили док сте били одсутни + discoverable_html: Директоријум омогућава људима да пронађу налоге засноване на интересима и активности. Захтева бар %{min_followers} пратиоца + email: Биће вам послата е-пошта са потврдом fields: Можете имати до 4 ставке приказане као табела на вашем профилу header: PNG, GIF или JPG. Највише %{size}. Биће смањена на %{dimensions}px inbox_url: Копирајте URL са насловне стране релеја који желите користити @@ -17,6 +26,7 @@ sr: password: Користите најмање 8 знакова phrase: Биће упарена без обзира на велико или мало слово у тексту или упозорења о садржају трубе scopes: Којим API-јима ће апликација дозволити приступ. Ако изаберете опсег највишег нивоа, не морате одабрати појединачне. + setting_aggregate_reblogs: Не показуј нова дељења за трубе које су недавно подељене (утиче само на недавно примљена дељења) setting_default_language: Језик ваших труба може бити аутоматски откривен, али није увек прецизан setting_hide_network: Кога пратите и ко вас прати неће бити приказано на вашем профилу setting_noindex: Утиче на Ваш јавни профил и статусне стране @@ -33,6 +43,10 @@ sr: fields: name: Етикета value: Садржај + account_warning_preset: + text: Текст пресета + admin_account_action: + warning_preset_id: Користи упозоравајући пресет defaults: autofollow: Позовите да прати ваш налог avatar: Аватар -- cgit From a492a9bcd355d4f0998990905177ac4f9699cc3c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 18 Jan 2019 10:25:44 +0100 Subject: Add information about how to opt-in to the directory on the directory (#9834) Fix #9833 --- app/javascript/styles/mastodon/widgets.scss | 27 +++++++++++++++++++++++++++ app/views/directories/index.html.haml | 18 ++++++++++++++++-- config/locales/en.yml | 3 +++ 3 files changed, 46 insertions(+), 2 deletions(-) (limited to 'app/javascript') diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss index d44a1ef06..0699900dc 100644 --- a/app/javascript/styles/mastodon/widgets.scss +++ b/app/javascript/styles/mastodon/widgets.scss @@ -480,3 +480,30 @@ $fluid-breakpoint: $maximum-width + 20px; } } } + +.notice-widget { + margin-bottom: 10px; + color: $darker-text-color; + + p { + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + } + + a { + font-size: 14px; + line-height: 20px; + text-decoration: none; + font-weight: 500; + color: $ui-highlight-color; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } +} diff --git a/app/views/directories/index.html.haml b/app/views/directories/index.html.haml index 88706def7..a8aa68cc4 100644 --- a/app/views/directories/index.html.haml +++ b/app/views/directories/index.html.haml @@ -41,8 +41,22 @@ = paginate @accounts .column-1 - - if @tags.empty? - .nothing-here.nothing-here--flexible + - if user_signed_in? + .box-widget.notice-widget + - if current_account.discoverable? + - if current_account.followers_count < Account::MIN_FOLLOWERS_DISCOVERY + %p= t('directories.enabled_but_waiting', min_followers: Account::MIN_FOLLOWERS_DISCOVERY) + - else + %p= t('directories.enabled') + - else + %p= t('directories.how_to_enable') + + = link_to settings_profile_path do + = t('settings.edit_profile') + = fa_icon 'chevron-right fw' + + - if @tags.empty? && !user_signed_in? + .nothing-here - else - @tags.each do |tag| .directory__tag{ class: tag.id == @tag&.id ? 'active' : nil } diff --git a/config/locales/en.yml b/config/locales/en.yml index 8ad5ecb06..10749b21b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -553,8 +553,11 @@ en: warning_title: Disseminated content availability directories: directory: Profile directory + enabled: You are currently listed in the directory. + enabled_but_waiting: You have opted-in to be listed in the directory, but you do not have the minimum number of followers (%{min_followers}) to be listed yet. explanation: Discover users based on their interests explore_mastodon: Explore %{title} + how_to_enable: You are not currently opted-in to the directory. You can opt-in below. Use hashtags in your bio text to be listed under specific hashtags! people: one: "%{count} person" other: "%{count} people" -- cgit From b506ce119766bb3308f934e2d3de143b3ac6f5ad Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 18 Jan 2019 20:58:11 +0100 Subject: Fix new hashtag page's items not being full-width on mobile (#9852) Fix #9845 --- .../mastodon/features/status/components/detailed_status.js | 2 +- app/javascript/styles/mastodon/containers.scss | 2 +- app/javascript/styles/mastodon/widgets.scss | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'app/javascript') diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 2921a26f9..0630387d2 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -54,7 +54,7 @@ export default class DetailedStatus extends ImmutablePureComponent { _measureHeight (heightJustChanged) { if (this.props.measureHeight && this.node) { - scheduleIdleTask(() => this.node && this.setState({ height: this.node.scrollHeight })); + scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 })); if (this.props.onHeightChange && heightJustChanged) { this.props.onHeightChange(); diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss index 8de53ca98..a98fa52c4 100644 --- a/app/javascript/styles/mastodon/containers.scss +++ b/app/javascript/styles/mastodon/containers.scss @@ -295,7 +295,7 @@ color: $primary-text-color; } - @media screen and (max-width: $no-gap-breakpoint) { + @media screen and (max-width: 550px) { &.optional { display: none; } diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss index 0699900dc..c97337e4e 100644 --- a/app/javascript/styles/mastodon/widgets.scss +++ b/app/javascript/styles/mastodon/widgets.scss @@ -432,6 +432,10 @@ $fluid-breakpoint: $maximum-width + 20px; .statuses-grid { min-height: 600px; + @media screen and (max-width: 640px) { + width: 100% !important; // Masonry layout is unnecessary at this width + } + &__item { width: (960px - 20px) / 3; @@ -439,6 +443,10 @@ $fluid-breakpoint: $maximum-width + 20px; width: (940px - 20px) / 3; } + @media screen and (max-width: 640px) { + width: 100%; + } + @media screen and (max-width: $no-gap-breakpoint) { width: 100vw; } @@ -448,7 +456,7 @@ $fluid-breakpoint: $maximum-width + 20px; border-radius: 4px; @media screen and (max-width: $no-gap-breakpoint) { - border-bottom: 1px solid lighten($ui-base-color, 12%); + border-top: 1px solid lighten($ui-base-color, 16%); } &.compact { -- cgit From 3e8b6239751673a0672b1a51c6c7f0a7d5e1eab8 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 19 Jan 2019 18:55:27 +0100 Subject: [Glitch] Redesign public hashtag page to use a masonry layout Port bc642ac24b49c14dca382e7aabbc16130293d2f4 to glitch flavour --- .../flavours/glitch/components/display_name.js | 11 +- .../features/standalone/hashtag_timeline/index.js | 88 +++++++---- .../features/status/components/detailed_status.js | 109 +++++++++++-- .../status/containers/detailed_status_container.js | 173 +++++++++++++++++++++ app/javascript/flavours/glitch/styles/widgets.scss | 27 ++++ 5 files changed, 361 insertions(+), 47 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js index d6ac4907d..a26cff049 100644 --- a/app/javascript/flavours/glitch/components/display_name.js +++ b/app/javascript/flavours/glitch/components/display_name.js @@ -9,15 +9,23 @@ export default function DisplayName ({ account, className, inline, + localDomain, }) { const computedClass = classNames('display-name', { inline }, className); + if (!account) return null; + + let acct = account.get('acct'); + if (acct.indexOf('@') === -1 && localDomain) { + acct = `${acct}@${localDomain}`; + } + // The result. return account ? ( {inline ? ' ' : null} - @{account.get('acct')} + @{acct} ) : null; } @@ -27,4 +35,5 @@ DisplayName.propTypes = { account: ImmutablePropTypes.map, className: PropTypes.string, inline: PropTypes.bool, + localDomain: PropTypes.string, }; diff --git a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js index 44ba8db92..e45088771 100644 --- a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js @@ -1,28 +1,32 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; +import ImmutablePropTypes from 'react-immutable-proptypes'; import { expandHashtagTimeline } from 'flavours/glitch/actions/timelines'; -import Column from 'flavours/glitch/components/column'; -import ColumnHeader from 'flavours/glitch/components/column_header'; import { connectHashtagStream } from 'flavours/glitch/actions/streaming'; +import Masonry from 'react-masonry-infinite'; +import { List as ImmutableList } from 'immutable'; +import DetailedStatusContainer from 'flavours/glitch/features/status/containers/detailed_status_container'; +import { debounce } from 'lodash'; +import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -@connect() -export default class HashtagTimeline extends React.PureComponent { +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 @@ export default 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()) ? : undefined; return ( - - - - - + + {statusIds.map(statusId => ( +
+ +
+ )).toArray()} +
); } diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 6302f11af..ba44ad3de 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -12,6 +12,7 @@ import Card from './card'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Video from 'flavours/glitch/features/video'; import VisibilityIcon from 'flavours/glitch/components/status_visibility_icon'; +import scheduleIdleTask from 'flavours/glitch/util/schedule_idle_task'; export default class DetailedStatus extends ImmutablePureComponent { @@ -26,10 +27,17 @@ export default class DetailedStatus extends ImmutablePureComponent { onOpenVideo: PropTypes.func.isRequired, onToggleHidden: PropTypes.func.isRequired, expanded: PropTypes.bool, + measureHeight: PropTypes.bool, + onHeightChange: PropTypes.func, + domain: PropTypes.string.isRequired, + }; + + state = { + height: null, }; handleAccountClick = (e) => { - if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) { + if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey) && this.context.router) { e.preventDefault(); this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`); } @@ -38,7 +46,7 @@ export default class DetailedStatus extends ImmutablePureComponent { } parseClick = (e, destination) => { - if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) { + if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey) && this.context.router) { e.preventDefault(); this.context.router.history.push(destination); } @@ -50,15 +58,58 @@ export default class DetailedStatus extends ImmutablePureComponent { this.props.onOpenVideo(media, startTime); } + _measureHeight (heightJustChanged) { + if (this.props.measureHeight && this.node) { + scheduleIdleTask(() => this.node && this.setState({ height: this.node.offsetHeight })); + + 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 { expanded, onToggleHidden, settings } = this.props; + const outerStyle = { boxSizing: 'border-box' }; + + if (!status) { + return null; + } let media = ''; let mediaIcon = null; 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')) { @@ -108,20 +159,51 @@ export default class DetailedStatus extends ImmutablePureComponent { if (status.get('visibility') === 'private') { reblogLink = ; + } else if (this.context.router) { + reblogLink = ( + + + + + + + ); + } else { + reblogLink = ( + + + + + + + ); + } + + if (this.context.router) { + favouriteLink = ( + + + + + + + ); } else { - reblogLink = ( - - - - - ); + favouriteLink = ( + + + + + + + ); } return ( -
+
- +
- {applicationLink} · {reblogLink} · - - - - - · + {applicationLink} · {reblogLink} · {favouriteLink} ·
); diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js new file mode 100644 index 000000000..e41b1dc88 --- /dev/null +++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js @@ -0,0 +1,173 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import DetailedStatus from '../components/detailed_status'; +import { makeGetStatus } from 'flavours/glitch/selectors'; +import { + replyCompose, + mentionCompose, + directCompose, +} from 'flavours/glitch/actions/compose'; +import { + reblog, + favourite, + unreblog, + unfavourite, + pin, + unpin, +} from 'flavours/glitch/actions/interactions'; +import { blockAccount } from 'flavours/glitch/actions/accounts'; +import { + muteStatus, + unmuteStatus, + deleteStatus, + hideStatus, + revealStatus, +} from 'flavours/glitch/actions/statuses'; +import { initMuteModal } from 'flavours/glitch/actions/mutes'; +import { initReport } from 'flavours/glitch/actions/reports'; +import { openModal } from 'flavours/glitch/actions/modal'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state'; +import { showAlertForError } from 'flavours/glitch/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']), + settings: state.get('local_settings'), + }); + + 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: @{account.get('acct')}
}} />, + 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)); diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss index 87e633c70..cabef807e 100644 --- a/app/javascript/flavours/glitch/styles/widgets.scss +++ b/app/javascript/flavours/glitch/styles/widgets.scss @@ -425,3 +425,30 @@ border-radius: 0; } } + +$maximum-width: 1235px; +$fluid-breakpoint: $maximum-width + 20px; + +.statuses-grid { + min-height: 600px; + + &__item { + width: (960px - 20px) / 3; + + @media screen and (max-width: $fluid-breakpoint) { + width: (940px - 20px) / 3; + } + + @media screen and (max-width: $no-gap-breakpoint) { + width: 100vw; + } + } + + .detailed-status { + border-radius: 4px; + + @media screen and (max-width: $no-gap-breakpoint) { + border-bottom: 1px solid lighten($ui-base-color, 12%); + } + } +} -- cgit From 02295257b305371c574d9b4aad1377e7b8acdd69 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 20 Jan 2019 11:47:17 +0100 Subject: [Glitch] Improve the public hashtag page Port 8b1990355974543542544e56d2046bc0c9c8716b to glitch-soc --- .../features/standalone/hashtag_timeline/index.js | 2 +- .../features/status/components/detailed_status.js | 45 ++++++++++++---------- .../flavours/glitch/features/status/index.js | 5 ++- app/javascript/flavours/glitch/styles/widgets.scss | 28 ++++++++++++++ 4 files changed, 58 insertions(+), 22 deletions(-) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js index e45088771..17f064713 100644 --- a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js @@ -80,7 +80,7 @@ class HashtagTimeline extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index ba44ad3de..447247567 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -13,6 +13,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import Video from 'flavours/glitch/features/video'; import VisibilityIcon from 'flavours/glitch/components/status_visibility_icon'; import scheduleIdleTask from 'flavours/glitch/util/schedule_idle_task'; +import classNames from 'classnames'; export default class DetailedStatus extends ImmutablePureComponent { @@ -30,6 +31,7 @@ export default class DetailedStatus extends ImmutablePureComponent { measureHeight: PropTypes.bool, onHeightChange: PropTypes.func, domain: PropTypes.string.isRequired, + compact: PropTypes.bool, }; state = { @@ -60,7 +62,7 @@ export default class DetailedStatus extends ImmutablePureComponent { _measureHeight (heightJustChanged) { if (this.props.measureHeight && this.node) { - scheduleIdleTask(() => this.node && this.setState({ height: this.node.offsetHeight })); + scheduleIdleTask(() => this.node && this.setState({ height: this.node.scrollHeight })); if (this.props.onHeightChange && heightJustChanged) { this.props.onHeightChange(); @@ -95,6 +97,7 @@ export default class DetailedStatus extends ImmutablePureComponent { const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status; const { expanded, onToggleHidden, settings } = this.props; const outerStyle = { boxSizing: 'border-box' }; + const { compact } = this.props; if (!status) { return null; @@ -200,26 +203,28 @@ export default class DetailedStatus extends ImmutablePureComponent { } return ( -
- -
- -
+
+
+ +
+ +
+ + - - -
- - - {applicationLink} · {reblogLink} · {favouriteLink} · +
+ + + {applicationLink} · {reblogLink} · {favouriteLink} · +
); diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index aa508c483..86c4db283 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -100,6 +100,7 @@ const makeMapStateToProps = () => { descendantsIds, settings: state.get('local_settings'), askReplyConfirmation: state.getIn(['local_settings', 'confirm_before_clearing_draft']) && state.getIn(['compose', 'text']).trim().length !== 0, + domain: state.getIn(['meta', 'domain']), }; }; @@ -123,6 +124,7 @@ export default class Status extends ImmutablePureComponent { descendantsIds: ImmutablePropTypes.list, intl: PropTypes.object.isRequired, askReplyConfirmation: PropTypes.bool, + domain: PropTypes.string.isRequired, }; state = { @@ -417,7 +419,7 @@ export default class Status extends ImmutablePureComponent { render () { let ancestors, descendants; const { setExpansion } = this; - const { status, settings, ancestorsIds, descendantsIds, intl } = this.props; + const { status, settings, ancestorsIds, descendantsIds, intl, domain } = this.props; const { fullscreen, isExpanded } = this.state; if (status === null) { @@ -470,6 +472,7 @@ export default class Status extends ImmutablePureComponent { onOpenMedia={this.handleOpenMedia} expanded={isExpanded} onToggleHidden={this.handleExpandedToggle} + domain={domain} /> Date: Thu, 17 Jan 2019 23:28:30 +0100 Subject: Fix slightly cropped font on settings page dropdowns when using system font (#9839) --- app/javascript/flavours/glitch/styles/forms.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index 6132dd1ae..bab982706 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -419,7 +419,7 @@ code { background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,") no-repeat right 8px center / auto 16px; border: 1px solid darken($ui-base-color, 14%); border-radius: 4px; - padding: 10px; + padding-left: 10px; padding-right: 30px; height: 41px; } -- cgit From 8001a9b97bded0329f91397f2316328a8ba0d97a Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 20 Jan 2019 11:50:19 +0100 Subject: [Glitch] Add information about how to opt-in to the directory on the directory Port SCSS changes from a492a9bcd355d4f0998990905177ac4f9699cc3c to glitch-soc --- app/javascript/flavours/glitch/styles/widgets.scss | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss index d44a1ef06..0699900dc 100644 --- a/app/javascript/flavours/glitch/styles/widgets.scss +++ b/app/javascript/flavours/glitch/styles/widgets.scss @@ -480,3 +480,30 @@ $fluid-breakpoint: $maximum-width + 20px; } } } + +.notice-widget { + margin-bottom: 10px; + color: $darker-text-color; + + p { + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + } + + a { + font-size: 14px; + line-height: 20px; + text-decoration: none; + font-weight: 500; + color: $ui-highlight-color; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } +} -- cgit From a93cb340bd1f7ce6f42943024a4a3431f5671b14 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 20 Jan 2019 11:52:06 +0100 Subject: [Glitch] Fix new hashtag page's items not being full-width on mobile Port b506ce119766bb3308f934e2d3de143b3ac6f5ad to glitch-soc --- .../glitch/features/status/components/detailed_status.js | 2 +- app/javascript/flavours/glitch/styles/containers.scss | 2 +- app/javascript/flavours/glitch/styles/widgets.scss | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js index 447247567..02f02efea 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js @@ -62,7 +62,7 @@ export default class DetailedStatus extends ImmutablePureComponent { _measureHeight (heightJustChanged) { if (this.props.measureHeight && this.node) { - scheduleIdleTask(() => this.node && this.setState({ height: this.node.scrollHeight })); + scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 })); if (this.props.onHeightChange && heightJustChanged) { this.props.onHeightChange(); diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index 82d4050d7..fd334f869 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -297,7 +297,7 @@ color: $primary-text-color; } - @media screen and (max-width: $no-gap-breakpoint) { + @media screen and (max-width: 550px) { &.optional { display: none; } diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss index 0699900dc..c97337e4e 100644 --- a/app/javascript/flavours/glitch/styles/widgets.scss +++ b/app/javascript/flavours/glitch/styles/widgets.scss @@ -432,6 +432,10 @@ $fluid-breakpoint: $maximum-width + 20px; .statuses-grid { min-height: 600px; + @media screen and (max-width: 640px) { + width: 100% !important; // Masonry layout is unnecessary at this width + } + &__item { width: (960px - 20px) / 3; @@ -439,6 +443,10 @@ $fluid-breakpoint: $maximum-width + 20px; width: (940px - 20px) / 3; } + @media screen and (max-width: 640px) { + width: 100%; + } + @media screen and (max-width: $no-gap-breakpoint) { width: 100vw; } @@ -448,7 +456,7 @@ $fluid-breakpoint: $maximum-width + 20px; border-radius: 4px; @media screen and (max-width: $no-gap-breakpoint) { - border-bottom: 1px solid lighten($ui-base-color, 12%); + border-top: 1px solid lighten($ui-base-color, 16%); } &.compact { -- cgit From 9b5810b3e9fd67290c16de810ac5e995925d618e Mon Sep 17 00:00:00 2001 From: tmm576 Date: Thu, 17 Jan 2019 17:27:51 -0500 Subject: Allow event defaults on index for text data transfer (#9840) --- app/javascript/flavours/glitch/features/ui/index.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 7928dfe6c..602d93832 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -166,6 +166,7 @@ export default class UI extends React.Component { } handleDragOver = (e) => { + if (this.dataTransferIsText(e.dataTransfer)) return false; e.preventDefault(); e.stopPropagation(); @@ -179,6 +180,7 @@ export default class UI extends React.Component { } handleDrop = (e) => { + if (this.dataTransferIsText(e.dataTransfer)) return; e.preventDefault(); this.setState({ draggingOver: false }); @@ -202,6 +204,10 @@ export default class UI extends React.Component { this.setState({ draggingOver: false }); } + dataTransferIsText = (dataTransfer) => { + return (dataTransfer && Array.from(dataTransfer.types).includes('text/plain') && dataTransfer.items.length === 1); + } + closeUploadModal = () => { this.setState({ draggingOver: false }); } -- cgit From e9060b04d477defe0bc7748b444336d1af572ab9 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 20 Jan 2019 11:54:38 +0100 Subject: [Glitch] Hide floating action button on search and getting started pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port 30af4ee65ff43c17d6f7b1b64d6bf1d8699f37c8 to glitch-soc --- app/javascript/flavours/glitch/features/ui/components/columns_area.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js index 61f6c0fed..83b797305 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -30,7 +30,7 @@ const componentMap = { 'LIST': ListTimeline, }; -const shouldHideFAB = path => path.match(/^\/statuses\//); +const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/); const messages = defineMessages({ publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }, -- cgit From 5145c81620efbd5cf8dc911858d17d1fa888c996 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 20 Jan 2019 11:56:21 +0100 Subject: [Glitch] Fix public hashtag timeline width on mobile, fix scrollbar width compensation Port 3b3a4d8a1709b8f4a9ffe67d21707117c75f9fe8 to glitch-soc --- app/javascript/flavours/glitch/packs/public.js | 8 ++++++++ app/javascript/flavours/glitch/styles/about.scss | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'app/javascript') diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js index 56012ba78..da0b4c8e0 100644 --- a/app/javascript/flavours/glitch/packs/public.js +++ b/app/javascript/flavours/glitch/packs/public.js @@ -86,6 +86,14 @@ function main() { if (parallaxComponents.length > 0 ) { new Rellax('.parallax', { speed: -1 }); } + + if (document.body.classList.contains('with-modals')) { + const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; + const scrollbarWidthStyle = document.createElement('style'); + scrollbarWidthStyle.id = 'scrollbar-width'; + document.head.appendChild(scrollbarWidthStyle); + scrollbarWidthStyle.sheet.insertRule(`body.with-modals--active { margin-right: ${scrollbarWidth}px; }`, 0); + } }); } diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss index c8d144e5b..e8f46766a 100644 --- a/app/javascript/flavours/glitch/styles/about.scss +++ b/app/javascript/flavours/glitch/styles/about.scss @@ -366,7 +366,7 @@ $small-breakpoint: 960px; @media screen and (max-width: $column-breakpoint) { .grid { - grid-template-columns: auto; + grid-template-columns: 100%; .column-0 { display: block; -- cgit