From 23f7afa562c49b24e979505680463bc712b11d94 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 14 Aug 2019 04:07:32 +0200 Subject: Add media editing modal (#11563) Move media description input to a modal and unite that modal with the focal point modal. Add a hint about choosing focal points, as well as a preview of a 16:9 thumbnail. Enable the user to watch the video next to the media description input. Fix #8320 Fix #6713 --- app/javascript/styles/mastodon/components.scss | 56 +++++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'app/javascript/styles') diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 8de72d72e..f2967a398 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4567,6 +4567,14 @@ a.status-card.compact:hover { } } + .setting-text-label { + display: block; + color: $inverted-text-color; + font-size: 14px; + font-weight: 500; + margin-bottom: 10px; + } + .setting-toggle { margin-top: 20px; margin-bottom: 24px; @@ -4960,6 +4968,10 @@ a.status-card.compact:hover { max-width: 100%; border-radius: 4px; + &.editable { + border-radius: 0; + } + &:focus { outline: 0; } @@ -5688,27 +5700,20 @@ noscript { } } -.focal-point-modal { - max-width: 80vw; - max-height: 80vh; - position: relative; -} - .focal-point { position: relative; - cursor: pointer; + cursor: move; overflow: hidden; - &.dragging { - cursor: move; - } - - img { - max-width: 80vw; + img, + video { + display: block; max-height: 80vh; - width: auto; + width: 100%; height: auto; - margin: auto; + margin: 0; + object-fit: contain; + background: $base-shadow-color; } &__reticle { @@ -5728,6 +5733,27 @@ noscript { top: 0; left: 0; } + + &__preview { + position: absolute; + bottom: 10px; + right: 10px; + z-index: 2; + cursor: default; + + strong { + color: $primary-text-color; + font-size: 14px; + font-weight: 500; + display: block; + margin-bottom: 5px; + } + + div { + border-radius: 4px; + box-shadow: 0 0 14px rgba($base-shadow-color, 0.2); + } + } } .account__header__content { -- cgit From 28636f43e4b0c04befa243b847c38e81c90f1289 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 15 Aug 2019 15:13:26 +0200 Subject: Add OCR tool to media editing modal (#11566) --- .../features/compose/components/upload_form.js | 3 +- .../features/compose/components/upload_progress.js | 9 +- .../features/ui/components/focal_point_modal.js | 60 +++++++-- app/javascript/styles/mastodon/components.scss | 81 +++++++++--- config/initializers/content_security_policy.rb | 8 +- config/webpack/development.js | 1 + config/webpack/shared.js | 5 + package.json | 2 + public/ocr/lang-data/eng.traineddata.gz | Bin 0 -> 10923060 bytes yarn.lock | 140 ++++++++++++++++++++- 10 files changed, 275 insertions(+), 34 deletions(-) create mode 100644 public/ocr/lang-data/eng.traineddata.gz (limited to 'app/javascript/styles') diff --git a/app/javascript/mastodon/features/compose/components/upload_form.js b/app/javascript/mastodon/features/compose/components/upload_form.js index 9ff2aa0fa..c6eac554e 100644 --- a/app/javascript/mastodon/features/compose/components/upload_form.js +++ b/app/javascript/mastodon/features/compose/components/upload_form.js @@ -4,6 +4,7 @@ import UploadProgressContainer from '../containers/upload_progress_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; import UploadContainer from '../containers/upload_container'; import SensitiveButtonContainer from '../containers/sensitive_button_container'; +import { FormattedMessage } from 'react-intl'; export default class UploadForm extends ImmutablePureComponent { @@ -16,7 +17,7 @@ export default class UploadForm extends ImmutablePureComponent { return (
- + } />
{mediaIds.map(id => ( diff --git a/app/javascript/mastodon/features/compose/components/upload_progress.js b/app/javascript/mastodon/features/compose/components/upload_progress.js index cbe58f573..b0bfe0c9a 100644 --- a/app/javascript/mastodon/features/compose/components/upload_progress.js +++ b/app/javascript/mastodon/features/compose/components/upload_progress.js @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; -import { FormattedMessage } from 'react-intl'; import Icon from 'mastodon/components/icon'; export default class UploadProgress extends React.PureComponent { @@ -10,10 +9,12 @@ export default class UploadProgress extends React.PureComponent { static propTypes = { active: PropTypes.bool, progress: PropTypes.number, + icon: PropTypes.string.isRequired, + message: PropTypes.node.isRequired, }; render () { - const { active, progress } = this.props; + const { active, progress, icon, message } = this.props; if (!active) { return null; @@ -22,11 +23,11 @@ export default class UploadProgress extends React.PureComponent { return (
- +
- + {message}
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 e15bf69d6..b21d5c9d4 100644 --- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js +++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js @@ -10,6 +10,11 @@ import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import IconButton from 'mastodon/components/icon_button'; import Button from 'mastodon/components/button'; import Video from 'mastodon/features/video'; +import { TesseractWorker } from 'tesseract.js'; +import Textarea from 'react-textarea-autosize'; +import UploadProgress from 'mastodon/features/compose/components/upload_progress'; +import CharacterCounter from 'mastodon/features/compose/components/character_counter'; +import { length } from 'stringz'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -29,6 +34,12 @@ const mapDispatchToProps = (dispatch, { id }) => ({ }); +const removeExtraLineBreaks = str => str.replace(/\n\n/g, '******') + .replace(/\n/g, ' ') + .replace(/\*\*\*\*\*\*/g, '\n\n'); + +const assetHost = process.env.CDN_HOST || ''; + export default @connect(mapStateToProps, mapDispatchToProps) @injectIntl class FocalPointModal extends ImmutablePureComponent { @@ -47,6 +58,7 @@ class FocalPointModal extends ImmutablePureComponent { dragging: false, description: '', dirty: false, + progress: 0, }; componentWillMount () { @@ -133,9 +145,27 @@ class FocalPointModal extends ImmutablePureComponent { this.node = c; } + handleTextDetection = () => { + const { media } = this.props; + + const worker = new TesseractWorker({ + workerPath: `${assetHost}/packs/ocr/worker.min.js`, + corePath: `${assetHost}/packs/ocr/tesseract-core.wasm.js`, + langPath: `${assetHost}/ocr/lang-data`, + }); + + this.setState({ detecting: true }); + + worker.recognize(media.get('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 })); + } + render () { const { media, intl, onClose } = this.props; - const { x, y, dragging, description, dirty } = this.state; + const { x, y, dragging, description, dirty, detecting, progress } = this.state; const width = media.getIn(['meta', 'original', 'width']) || null; const height = media.getIn(['meta', 'original', 'height']) || null; @@ -158,15 +188,27 @@ class FocalPointModal extends ImmutablePureComponent { -