diff options
author | ThibG <thib@sitedethib.com> | 2020-09-01 17:36:30 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-01 17:36:30 +0200 |
commit | d967251fdc3826ad27d30e55258cfa4cdfd7c871 (patch) | |
tree | 91926ccaedf470bfef058cc7156f9f362d46186a /app/javascript | |
parent | d95dd3883e0c7d1626f5e3b88d24af2627a641e2 (diff) | |
parent | 787a629b8f1df4cce53a9de7f3aa668cc9ef632f (diff) |
Merge pull request #1417 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
Diffstat (limited to 'app/javascript')
8 files changed, 129 insertions, 71 deletions
diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js index c8b0e4bd7..b790b29a0 100644 --- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js +++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js @@ -18,6 +18,8 @@ import { length } from 'stringz'; import { Tesseract as fetchTesseract } from 'flavours/glitch/util/async-components'; import GIFV from 'flavours/glitch/components/gifv'; import { me } from 'flavours/glitch/util/initial_state'; +import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js'; +import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -104,6 +106,7 @@ class FocalPointModal extends ImmutablePureComponent { dirty: false, progress: 0, loading: true, + ocrStatus: '', }; componentWillMount () { @@ -219,11 +222,18 @@ class FocalPointModal extends ImmutablePureComponent { this.setState({ detecting: true }); - fetchTesseract().then(({ TesseractWorker }) => { - const worker = new TesseractWorker({ - workerPath: `${assetHost}/packs/ocr/worker.min.js`, - corePath: `${assetHost}/packs/ocr/tesseract-core.wasm.js`, - langPath: `${assetHost}/ocr/lang-data`, + fetchTesseract().then(({ createWorker }) => { + const worker = createWorker({ + workerPath: tesseractWorkerPath, + corePath: tesseractCorePath, + langPath: assetHost, + logger: ({ status, progress }) => { + if (status === 'recognizing text') { + this.setState({ ocrStatus: 'detecting', progress }); + } else { + this.setState({ ocrStatus: 'preparing', progress }); + } + }, }); let media_url = media.get('url'); @@ -236,12 +246,18 @@ class FocalPointModal extends ImmutablePureComponent { } } - worker.recognize(media_url) - .progress(({ progress }) => this.setState({ progress })) - .finally(() => worker.terminate()) - .then(({ text }) => this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false })) - .catch(() => this.setState({ detecting: false })); - }).catch(() => this.setState({ detecting: false })); + (async () => { + await worker.load(); + await worker.loadLanguage('eng'); + await worker.initialize('eng'); + const { data: { text } } = await worker.recognize(media_url); + this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false }); + await worker.terminate(); + })(); + }).catch((e) => { + console.error(e); + this.setState({ detecting: false }); + }); } handleThumbnailChange = e => { @@ -261,7 +277,7 @@ class FocalPointModal extends ImmutablePureComponent { render () { const { media, intl, account, onClose, isUploadingThumbnail } = this.props; - const { x, y, dragging, description, dirty, detecting, progress } = this.state; + const { x, y, dragging, description, dirty, detecting, progress, ocrStatus } = this.state; const width = media.getIn(['meta', 'original', 'width']) || null; const height = media.getIn(['meta', 'original', 'height']) || null; @@ -282,6 +298,13 @@ class FocalPointModal extends ImmutablePureComponent { descriptionLabel = <FormattedMessage id='upload_form.description' defaultMessage='Describe for the visually impaired' />; } + let ocrMessage = ''; + if (ocrStatus === 'detecting') { + ocrMessage = <FormattedMessage id='upload_modal.analyzing_picture' defaultMessage='Analyzing picture…' />; + } else { + ocrMessage = <FormattedMessage id='upload_modal.preparing_ocr' defaultMessage='Preparing OCR…' />; + } + return ( <div className='modal-root__modal report-modal' style={{ maxWidth: 960 }}> <div className='report-modal__target'> @@ -333,7 +356,7 @@ class FocalPointModal extends ImmutablePureComponent { /> <div className='setting-text__modifiers'> - <UploadProgress progress={progress * 100} active={detecting} icon='file-text-o' message={<FormattedMessage id='upload_modal.analyzing_picture' defaultMessage='Analyzing picture…' />} /> + <UploadProgress progress={progress * 100} active={detecting} icon='file-text-o' message={ocrMessage} /> </div> </div> diff --git a/app/javascript/flavours/glitch/util/emoji/index.js b/app/javascript/flavours/glitch/util/emoji/index.js index 61f211c92..a59e17ddb 100644 --- a/app/javascript/flavours/glitch/util/emoji/index.js +++ b/app/javascript/flavours/glitch/util/emoji/index.js @@ -12,7 +12,7 @@ const emojiFilenames = (emojis) => { }; // Emoji requiring extra borders depending on theme -const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴']); +const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴', '🐞']); const lightEmoji = emojiFilenames(['👽', '⚾', '🐔', '☁️', '💨', '🕊️', '👀', '🍥', '👻', '🐐', '❕', '❔', '⛸️', '🌩️', '🔊', '🔇', '📃', '🌧️', '🐏', '🍚', '🍙', '🐓', '🐑', '💀', '☠️', '🌨️', '🔉', '🔈', '💬', '💭', '🏐', '🏳️', '⚪', '⬜', '◽', '◻️', '▫️']); const emojiFilename = (filename) => { diff --git a/app/javascript/mastodon/actions/lists.js b/app/javascript/mastodon/actions/lists.js index d736bacef..5ab922436 100644 --- a/app/javascript/mastodon/actions/lists.js +++ b/app/javascript/mastodon/actions/lists.js @@ -150,10 +150,10 @@ export const createListFail = error => ({ error, }); -export const updateList = (id, title, shouldReset) => (dispatch, getState) => { +export const updateList = (id, title, shouldReset, replies_policy) => (dispatch, getState) => { dispatch(updateListRequest(id)); - api(getState).put(`/api/v1/lists/${id}`, { title }).then(({ data }) => { + api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy }).then(({ data }) => { dispatch(updateListSuccess(data)); if (shouldReset) { diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js index f7d3cfd08..5237b25f0 100644 --- a/app/javascript/mastodon/features/emoji/emoji.js +++ b/app/javascript/mastodon/features/emoji/emoji.js @@ -12,7 +12,7 @@ const emojiFilenames = (emojis) => { }; // Emoji requiring extra borders depending on theme -const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴']); +const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴', '🐞']); const lightEmoji = emojiFilenames(['👽', '⚾', '🐔', '☁️', '💨', '🕊️', '👀', '🍥', '👻', '🐐', '❕', '❔', '⛸️', '🌩️', '🔊', '🔇', '📃', '🌧️', '🐏', '🍚', '🍙', '🐓', '🐑', '💀', '☠️', '🌨️', '🔉', '🔈', '💬', '💭', '🏐', '🏳️', '⚪', '⬜', '◽', '◻️', '▫️']); const emojiFilename = (filename) => { diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index d9838e1c7..02e1bbba5 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -40,6 +40,7 @@ const messages = defineMessages({ const mapStateToProps = state => ({ myAccount: state.getIn(['accounts', me]), + columns: state.getIn(['settings', 'columns']), unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size, }); @@ -89,60 +90,66 @@ class GettingStarted extends ImmutablePureComponent { } render () { - const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props; + const { intl, myAccount, columns, multiColumn, unreadFollowRequests } = this.props; const navItems = []; - let i = 1; let height = (multiColumn) ? 0 : 60; if (multiColumn) { navItems.push( - <ColumnSubheading key={i++} text={intl.formatMessage(messages.discover)} />, - <ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />, - <ColumnLink key={i++} icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />, + <ColumnSubheading key='header-discover' text={intl.formatMessage(messages.discover)} />, + <ColumnLink key='community_timeline' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />, + <ColumnLink key='public_timeline' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />, ); height += 34 + 48*2; if (profile_directory) { navItems.push( - <ColumnLink key={i++} icon='address-book' text={intl.formatMessage(messages.profile_directory)} to='/directory' />, + <ColumnLink key='directory' icon='address-book' text={intl.formatMessage(messages.profile_directory)} to='/directory' />, ); height += 48; } navItems.push( - <ColumnSubheading key={i++} text={intl.formatMessage(messages.personal)} />, + <ColumnSubheading key='header-personal' text={intl.formatMessage(messages.personal)} />, ); height += 34; } else if (profile_directory) { navItems.push( - <ColumnLink key={i++} icon='address-book' text={intl.formatMessage(messages.profile_directory)} to='/directory' />, + <ColumnLink key='directory' icon='address-book' text={intl.formatMessage(messages.profile_directory)} to='/directory' />, ); height += 48; } + if (multiColumn && !columns.find(item => item.get('id') === 'HOME')) { + navItems.push( + <ColumnLink key='home' icon='home' text={intl.formatMessage(messages.home_timeline)} to='/timelines/home' />, + ); + height += 48; + } + navItems.push( - <ColumnLink key={i++} icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />, - <ColumnLink key={i++} icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />, - <ColumnLink key={i++} icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, - <ColumnLink key={i++} icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />, + <ColumnLink key='direct' icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />, + <ColumnLink key='bookmark' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />, + <ColumnLink key='favourites' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, + <ColumnLink key='lists' icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />, ); height += 48*4; if (myAccount.get('locked') || unreadFollowRequests > 0) { - navItems.push(<ColumnLink key={i++} icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />); + navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />); height += 48; } if (!multiColumn) { navItems.push( - <ColumnSubheading key={i++} text={intl.formatMessage(messages.settings_subheading)} />, - <ColumnLink key={i++} icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />, + <ColumnSubheading key='header-settings' text={intl.formatMessage(messages.settings_subheading)} />, + <ColumnLink key='preferences' icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />, ); height += 34 + 48; diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js index f3205b2bf..a3be8fbea 100644 --- a/app/javascript/mastodon/features/list_timeline/index.js +++ b/app/javascript/mastodon/features/list_timeline/index.js @@ -10,15 +10,19 @@ import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { connectListStream } from '../../actions/streaming'; import { expandListTimeline } from '../../actions/timelines'; -import { fetchList, deleteList } from '../../actions/lists'; +import { fetchList, deleteList, updateList } from '../../actions/lists'; import { openModal } from '../../actions/modal'; import MissingIndicator from '../../components/missing_indicator'; import LoadingIndicator from '../../components/loading_indicator'; import Icon from 'mastodon/components/icon'; +import RadioButton from 'mastodon/components/radio_button'; const messages = defineMessages({ deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' }, deleteConfirm: { id: 'confirmations.delete_list.confirm', defaultMessage: 'Delete' }, + all_replies: { id: 'lists.replies_policy.all_replies', defaultMessage: 'Any followed user' }, + no_replies: { id: 'lists.replies_policy.no_replies', defaultMessage: 'No one' }, + list_replies: { id: 'lists.replies_policy.list_replies', defaultMessage: 'Members of the list' }, }); const mapStateToProps = (state, props) => ({ @@ -131,11 +135,18 @@ class ListTimeline extends React.PureComponent { })); } + handleRepliesPolicyChange = ({ target }) => { + const { dispatch } = this.props; + const { id } = this.props.params; + dispatch(updateList(id, undefined, false, target.value)); + } + render () { - const { shouldUpdateScroll, hasUnread, columnId, multiColumn, list } = this.props; + const { shouldUpdateScroll, hasUnread, columnId, multiColumn, list, intl } = this.props; const { id } = this.props.params; const pinned = !!columnId; const title = list ? list.get('title') : id; + const replies_policy = list ? list.get('replies_policy') : undefined; if (typeof list === 'undefined') { return ( @@ -166,7 +177,7 @@ class ListTimeline extends React.PureComponent { pinned={pinned} multiColumn={multiColumn} > - <div className='column-header__links'> + <div className='column-settings__row column-header__links'> <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}> <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' /> </button> @@ -175,6 +186,19 @@ class ListTimeline extends React.PureComponent { <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' /> </button> </div> + + { replies_policy !== undefined && ( + <div role='group' aria-labelledby={`list-${id}-replies-policy`}> + <span id={`list-${id}-replies-policy`} className='column-settings__section'> + <FormattedMessage id='lists.replies_policy.title' defaultMessage='Show replies to:' /> + </span> + <div className='column-settings__row'> + { ['no_replies', 'list_replies', 'all_replies'].map(policy => ( + <RadioButton name='order' value={policy} label={intl.formatMessage(messages[policy])} checked={replies_policy === policy} onChange={this.handleRepliesPolicyChange} /> + ))} + </div> + </div> + )} </ColumnHeader> <StatusListContainer diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js index 7348d9599..926a495d1 100644 --- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js +++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js @@ -18,6 +18,8 @@ import { length } from 'stringz'; import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components'; import GIFV from 'mastodon/components/gifv'; import { me } from 'mastodon/initial_state'; +import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js'; +import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -104,6 +106,7 @@ class FocalPointModal extends ImmutablePureComponent { dirty: false, progress: 0, loading: true, + ocrStatus: '', }; componentWillMount () { @@ -219,11 +222,18 @@ class FocalPointModal extends ImmutablePureComponent { this.setState({ detecting: true }); - fetchTesseract().then(({ TesseractWorker }) => { - const worker = new TesseractWorker({ - workerPath: `${assetHost}/packs/ocr/worker.min.js`, - corePath: `${assetHost}/packs/ocr/tesseract-core.wasm.js`, - langPath: `${assetHost}/ocr/lang-data`, + fetchTesseract().then(({ createWorker }) => { + const worker = createWorker({ + workerPath: tesseractWorkerPath, + corePath: tesseractCorePath, + langPath: assetHost, + logger: ({ status, progress }) => { + if (status === 'recognizing text') { + this.setState({ ocrStatus: 'detecting', progress }); + } else { + this.setState({ ocrStatus: 'preparing', progress }); + } + }, }); let media_url = media.get('url'); @@ -236,12 +246,18 @@ class FocalPointModal extends ImmutablePureComponent { } } - worker.recognize(media_url) - .progress(({ progress }) => this.setState({ progress })) - .finally(() => worker.terminate()) - .then(({ text }) => this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false })) - .catch(() => this.setState({ detecting: false })); - }).catch(() => this.setState({ detecting: false })); + (async () => { + await worker.load(); + await worker.loadLanguage('eng'); + await worker.initialize('eng'); + const { data: { text } } = await worker.recognize(media_url); + this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false }); + await worker.terminate(); + })(); + }).catch((e) => { + console.error(e); + this.setState({ detecting: false }); + }); } handleThumbnailChange = e => { @@ -261,7 +277,7 @@ class FocalPointModal extends ImmutablePureComponent { render () { const { media, intl, account, onClose, isUploadingThumbnail } = this.props; - const { x, y, dragging, description, dirty, detecting, progress } = this.state; + const { x, y, dragging, description, dirty, detecting, progress, ocrStatus } = this.state; const width = media.getIn(['meta', 'original', 'width']) || null; const height = media.getIn(['meta', 'original', 'height']) || null; @@ -282,6 +298,13 @@ class FocalPointModal extends ImmutablePureComponent { descriptionLabel = <FormattedMessage id='upload_form.description' defaultMessage='Describe for the visually impaired' />; } + let ocrMessage = ''; + if (ocrStatus === 'detecting') { + ocrMessage = <FormattedMessage id='upload_modal.analyzing_picture' defaultMessage='Analyzing picture…' />; + } else { + ocrMessage = <FormattedMessage id='upload_modal.preparing_ocr' defaultMessage='Preparing OCR…' />; + } + return ( <div className='modal-root__modal report-modal' style={{ maxWidth: 960 }}> <div className='report-modal__target'> @@ -333,7 +356,7 @@ class FocalPointModal extends ImmutablePureComponent { /> <div className='setting-text__modifiers'> - <UploadProgress progress={progress * 100} active={detecting} icon='file-text-o' message={<FormattedMessage id='upload_modal.analyzing_picture' defaultMessage='Analyzing picture…' />} /> + <UploadProgress progress={progress * 100} active={detecting} icon='file-text-o' message={ocrMessage} /> </div> </div> diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index f6deadffa..4f4507b37 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -980,14 +980,6 @@ outline: 0; background: lighten($ui-base-color, 4%); - .status.status-direct { - background: lighten($ui-base-color, 12%); - - &.muted { - background: transparent; - } - } - .detailed-status, .detailed-status__action-bar { background: lighten($ui-base-color, 8%); @@ -1022,11 +1014,6 @@ margin-top: 8px; } - &.status-direct:not(.read) { - background: lighten($ui-base-color, 8%); - border-bottom-color: lighten($ui-base-color, 12%); - } - &.light { .status__relative-time, .status__visibility-icon { @@ -1064,16 +1051,6 @@ } } -.notification-favourite { - .status.status-direct { - background: transparent; - - .icon-button.disabled { - color: lighten($action-button-color, 13%); - } - } -} - .status__relative-time, .status__visibility-icon, .notification__relative_time { @@ -5957,6 +5934,10 @@ a.status-card.compact:hover { } } +.column-settings__row .radio-button { + display: block; +} + .radio-button { font-size: 14px; position: relative; |