diff options
author | Reverite <github@reverite.sh> | 2019-10-05 12:13:22 -0700 |
---|---|---|
committer | Reverite <github@reverite.sh> | 2019-10-05 12:13:22 -0700 |
commit | 46ada47e09af0da9c776ef83c0ff034c720a83d6 (patch) | |
tree | 54fd4b1d5fba6d592f328955ef5968608bbe716f /app/javascript/flavours/glitch/features | |
parent | 333b5e25f0a615a9518d402ef10dceb70190a52f (diff) | |
parent | 3921125e5578fb3871fdcae0e8e8a77179f1ad72 (diff) |
Merge branch 'glitch' into production
Diffstat (limited to 'app/javascript/flavours/glitch/features')
11 files changed, 143 insertions, 17 deletions
diff --git a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js index bd3baa5c3..6d07ec48c 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js +++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js @@ -118,6 +118,7 @@ export default class MediaItem extends ImmutablePureComponent { ); } else if (['gifv', 'video'].indexOf(attachment.get('type')) !== -1) { const autoPlay = !isIOS() && autoPlayGif; + const label = attachment.get('type') === 'video' ? <Icon id='play' /> : 'GIF'; thumbnail = ( <div className={classNames('media-gallery__gifv', { autoplay: autoPlay })}> @@ -133,7 +134,8 @@ export default class MediaItem extends ImmutablePureComponent { loop muted /> - <span className='media-gallery__gifv__label'>GIF</span> + + <span className='media-gallery__gifv__label'>{label}</span> </div> ); } diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js index 597196567..ff39764bb 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/index.js +++ b/app/javascript/flavours/glitch/features/account_gallery/index.js @@ -111,8 +111,10 @@ class AccountGallery extends ImmutablePureComponent { } handleOpenMedia = attachment => { - if (['video', 'audio'].includes(attachment.get('type'))) { + if (attachment.get('type') === 'video') { this.props.dispatch(openModal('VIDEO', { media: attachment, status: attachment.get('status') })); + } else if (attachment.get('type') === 'audio') { + this.props.dispatch(openModal('AUDIO', { media: attachment, status: attachment.get('status') })); } else { const media = attachment.getIn(['status', 'media_attachments']); const index = media.findIndex(x => x.get('id') === attachment.get('id')); diff --git a/app/javascript/flavours/glitch/features/compose/components/search.js b/app/javascript/flavours/glitch/features/compose/components/search.js index 29d195ecd..12d839637 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search.js +++ b/app/javascript/flavours/glitch/features/compose/components/search.js @@ -73,12 +73,17 @@ class Search extends React.PureComponent { onShow: PropTypes.func.isRequired, openInRoute: PropTypes.bool, intl: PropTypes.object.isRequired, + singleColumn: PropTypes.bool, }; state = { expanded: false, }; + setRef = c => { + this.searchForm = c; + } + handleChange = (e) => { const { onChange } = this.props; if (onChange) { @@ -103,10 +108,14 @@ class Search extends React.PureComponent { } handleFocus = () => { - const { onShow } = this.props; this.setState({ expanded: true }); - if (onShow) { - onShow(); + this.props.onShow(); + + if (this.searchForm && !this.props.singleColumn) { + const { left, right } = this.searchForm.getBoundingClientRect(); + if (left < 0 || right > (window.innerWidth || document.documentElement.clientWidth)) { + this.searchForm.scrollIntoView(); + } } } @@ -135,6 +144,7 @@ class Search extends React.PureComponent { <label> <span style={{ display: 'none' }}>{intl.formatMessage(messages.placeholder)}</span> <input + ref={this.setRef} className='search__input' type='text' placeholder={intl.formatMessage(messages.placeholder)} diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js index 17487b202..a80fa824b 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js @@ -11,6 +11,7 @@ import Permalink from 'flavours/glitch/components/permalink'; import IconButton from 'flavours/glitch/components/icon_button'; import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp'; import { HotKeys } from 'react-hotkeys'; +import { autoPlayGif } from 'flavours/glitch/util/initial_state'; const messages = defineMessages({ more: { id: 'status.more', defaultMessage: 'More' }, @@ -37,6 +38,7 @@ class Conversation extends ImmutablePureComponent { onMoveUp: PropTypes.func, onMoveDown: PropTypes.func, markRead: PropTypes.func.isRequired, + delete: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; @@ -63,6 +65,43 @@ class Conversation extends ImmutablePureComponent { } } + _updateEmojis () { + const node = this.namesNode; + + if (!node || autoPlayGif) { + return; + } + + const emojis = node.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + if (emoji.classList.contains('status-emoji')) { + continue; + } + emoji.classList.add('status-emoji'); + + emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); + emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + } + } + + componentDidMount () { + this._updateEmojis(); + } + + componentDidUpdate () { + this._updateEmojis(); + } + + handleEmojiMouseEnter = ({ target }) => { + target.src = target.getAttribute('data-original'); + } + + handleEmojiMouseLeave = ({ target }) => { + target.src = target.getAttribute('data-static'); + } + handleClick = () => { if (!this.context.router) { return; @@ -111,6 +150,10 @@ class Conversation extends ImmutablePureComponent { this.setState({ isExpanded: value }); } + setNamesRef = (c) => { + this.namesNode = c; + } + render () { const { accounts, lastStatus, unread, intl } = this.props; const { isExpanded } = this.state; @@ -161,7 +204,7 @@ class Conversation extends ImmutablePureComponent { <RelativeTimestamp timestamp={lastStatus.get('created_at')} /> </div> - <div className='conversation__content__names'> + <div className='conversation__content__names' ref={this.setNamesRef}> <FormattedMessage id='conversation.with' defaultMessage='With {names}' values={{ names: <span>{names}</span> }} /> </div> </div> diff --git a/app/javascript/flavours/glitch/features/ui/components/audio_modal.js b/app/javascript/flavours/glitch/features/ui/components/audio_modal.js new file mode 100644 index 000000000..08fbddc91 --- /dev/null +++ b/app/javascript/flavours/glitch/features/ui/components/audio_modal.js @@ -0,0 +1,53 @@ +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import PropTypes from 'prop-types'; +import Audio from 'flavours/glitch/features/audio'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { FormattedMessage } from 'react-intl'; +import classNames from 'classnames'; +import Icon from 'flavours/glitch/components/icon'; + +export default class AudioModal extends ImmutablePureComponent { + + static propTypes = { + media: ImmutablePropTypes.map.isRequired, + status: ImmutablePropTypes.map, + onClose: PropTypes.func.isRequired, + }; + + static contextTypes = { + router: PropTypes.object, + }; + + handleStatusClick = e => { + if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { + e.preventDefault(); + this.context.router.history.push(`/statuses/${this.props.status.get('id')}`); + } + } + + render () { + const { media, status } = this.props; + + return ( + <div className='modal-root__modal audio-modal'> + <div className='audio-modal__container'> + <Audio + src={media.get('url')} + alt={media.get('description')} + duration={media.getIn(['meta', 'original', 'duration'], 0)} + height={135} + preload + /> + </div> + + {status && ( + <div className={classNames('media-modal__meta')}> + <a href={status.get('url')} onClick={this.handleStatusClick}><Icon id='comments' /> <FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a> + </div> + )} + </div> + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js index 47c1c7925..b6f5e628d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js @@ -1,8 +1,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { FormattedMessage, injectIntl } from 'react-intl'; +import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import api from 'flavours/glitch/util/api'; +import IconButton from 'flavours/glitch/components/icon_button'; + +const messages = defineMessages({ + close: { id: 'lightbox.close', defaultMessage: 'Close' }, +}); export default @injectIntl class EmbedModal extends ImmutablePureComponent { @@ -50,13 +55,17 @@ class EmbedModal extends ImmutablePureComponent { } render () { + const { intl, onClose } = this.props; const { oembed } = this.state; return ( - <div className='modal-root__modal embed-modal'> - <h4><FormattedMessage id='status.embed' defaultMessage='Embed' /></h4> + <div className='modal-root__modal report-modal embed-modal'> + <div className='report-modal__target'> + <IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} /> + <FormattedMessage id='status.embed' defaultMessage='Embed' /> + </div> - <div className='embed-modal__container'> + <div className='report-modal__container embed-modal__container' style={{ display: 'block' }}> <p className='hint'> <FormattedMessage id='embed.instructions' defaultMessage='Embed this status on your website by copying the code below.' /> </p> diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js index 5d60c8a08..d61c69f69 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js @@ -208,7 +208,7 @@ class MediaModal extends ImmutablePureComponent { {status && ( <div className={classNames('media-modal__meta', { 'media-modal__meta--shifted': media.size > 1 })}> - <a href={status.get('url')} onClick={this.handleStatusClick}><FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a> + <a href={status.get('url')} onClick={this.handleStatusClick}><Icon id='comments' /> <FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a> </div> )} diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index 0941ce9c8..117ce4c55 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -9,6 +9,7 @@ import MediaModal from './media_modal'; import VideoModal from './video_modal'; import BoostModal from './boost_modal'; import FavouriteModal from './favourite_modal'; +import AudioModal from './audio_modal'; import DoodleModal from './doodle_modal'; import ConfirmationModal from './confirmation_modal'; import FocalPointModal from './focal_point_modal'; @@ -28,6 +29,7 @@ const MODAL_COMPONENTS = { 'MEDIA': () => Promise.resolve({ default: MediaModal }), 'ONBOARDING': OnboardingModal, 'VIDEO': () => Promise.resolve({ default: VideoModal }), + 'AUDIO': () => Promise.resolve({ default: AudioModal }), 'BOOST': () => Promise.resolve({ default: BoostModal }), 'FAVOURITE': () => Promise.resolve({ default: FavouriteModal }), 'DOODLE': () => Promise.resolve({ default: DoodleModal }), diff --git a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js index dec6413c3..2aab82751 100644 --- a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js @@ -82,7 +82,7 @@ class MuteModal extends React.PureComponent { <p className='mute-modal__explanation'> <FormattedMessage id='confirmations.mute.explanation' - defaultMessage='This will hide posts from them and posts mentioning them, but it will still allow them to see your posts follow you.' + defaultMessage='This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.' /> </p> <div className='setting-toggle'> diff --git a/app/javascript/flavours/glitch/features/ui/components/video_modal.js b/app/javascript/flavours/glitch/features/ui/components/video_modal.js index 3f742c260..ef69f60f4 100644 --- a/app/javascript/flavours/glitch/features/ui/components/video_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/video_modal.js @@ -4,6 +4,8 @@ import PropTypes from 'prop-types'; import Video from 'flavours/glitch/features/video'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { FormattedMessage } from 'react-intl'; +import classNames from 'classnames'; +import Icon from 'mastodon/components/icon'; export default class VideoModal extends ImmutablePureComponent { @@ -28,22 +30,25 @@ export default class VideoModal extends ImmutablePureComponent { render () { const { media, status, time, onClose } = this.props; - const link = status && <a href={status.get('url')} onClick={this.handleStatusClick}><FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a>; - return ( <div className='modal-root__modal video-modal'> - <div> + <div className='video-modal__container'> <Video preview={media.get('preview_url')} blurhash={media.get('blurhash')} src={media.get('url')} startTime={time} onCloseVideo={onClose} - link={link} detailed alt={media.get('description')} /> </div> + + {status && ( + <div className={classNames('media-modal__meta')}> + <a href={status.get('url')} onClick={this.handleStatusClick}><Icon id='comments' /> <FormattedMessage id='lightbox.view_context' defaultMessage='View context' /></a> + </div> + )} </div> ); } diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 6cc1b1cde..c201cd93d 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -320,7 +320,7 @@ class UI extends React.Component { } dataTransferIsText = (dataTransfer) => { - return (dataTransfer && Array.from(dataTransfer.types).includes('text/plain') && dataTransfer.items.length === 1); + return (dataTransfer && Array.from(dataTransfer.types).filter((type) => type === 'text/plain').length === 1); } closeUploadModal = () => { |