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/flavours/glitch') 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/flavours/glitch') 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/flavours/glitch') 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/flavours/glitch') 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/flavours/glitch') 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/flavours/glitch') 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/flavours/glitch') 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/flavours/glitch') 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