feat: add video preview widget to settings modal
This commit is contained in:
committed by
Ken Clary
parent
c7c0d5e100
commit
b4fb88c73c
@@ -105,9 +105,11 @@ export const fileInput = ({ setThumbnailSrc, imgRef, fileSizeError }) => {
|
||||
const [resampledUrl, resampledFile] = module.resampleImage({ image, filename: file.name });
|
||||
setThumbnailSrc(resampledUrl);
|
||||
dispatch(thunkActions.video.uploadThumbnail({ thumbnail: resampledFile }));
|
||||
dispatch(actions.video.updateField({ thumbnail: resampledUrl }));
|
||||
return;
|
||||
}
|
||||
dispatch(thunkActions.video.uploadThumbnail({ thumbnail: file }));
|
||||
dispatch(actions.video.updateField({ thumbnail: reader.result }));
|
||||
};
|
||||
};
|
||||
dispatch(actions.video.updateField({ thumbnail: ' ' }));
|
||||
|
||||
@@ -59,7 +59,6 @@ export const LanguageSelector = ({
|
||||
const onLanguageChange = module.hooks.onSelectLanguage({
|
||||
dispatch: useDispatch(), languageBeforeChange: localLang, setLocalLang, triggerupload: input.click,
|
||||
});
|
||||
console.log({ localLang, language, openLanguages });
|
||||
|
||||
const getTitle = () => {
|
||||
if (Object.prototype.hasOwnProperty.call(videoTranscriptLanguages, language)) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Icon } from '@edx/paragon';
|
||||
import { ClosedCaptionOff, ClosedCaption } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import messages from '../messages';
|
||||
import { hooks as transcriptHooks } from '../TranscriptWidget';
|
||||
|
||||
export const LanguageNamesWidget = ({ transcripts, intl }) => {
|
||||
let icon = ClosedCaptionOff;
|
||||
const hasTranscripts = transcriptHooks.hasTranscripts(transcripts);
|
||||
let message = intl.formatMessage(messages.noTranscriptsAdded);
|
||||
let fontClass = 'text-gray';
|
||||
|
||||
if (hasTranscripts) {
|
||||
message = transcriptHooks.transcriptLanguages(transcripts, intl);
|
||||
fontClass = 'text-primary';
|
||||
icon = ClosedCaption;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-row align-items-center x-small">
|
||||
<Icon className="mr-1" src={icon} />
|
||||
<span className={fontClass}>{message}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
LanguageNamesWidget.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
transcripts: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(LanguageNamesWidget);
|
||||
@@ -0,0 +1,18 @@
|
||||
import messages from '../messages';
|
||||
|
||||
// https://stackoverflow.com/a/28735961/479084
|
||||
const youtubeRegex = /^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
|
||||
function isYoutubeUrl(url) {
|
||||
return url.match(youtubeRegex) !== null;
|
||||
}
|
||||
|
||||
function getVideoType(videoSource) {
|
||||
if (isYoutubeUrl(videoSource)) {
|
||||
return messages.videoTypeYoutube;
|
||||
}
|
||||
return messages.videoTypeOther;
|
||||
}
|
||||
|
||||
export default {
|
||||
getVideoType,
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Collapsible, Icon, Image, Stack,
|
||||
} from '@edx/paragon';
|
||||
import { Launch } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectors } from '../../../../../../data/redux';
|
||||
import thumbnailMessages from '../ThumbnailWidget/messages';
|
||||
import hooks from './hooks';
|
||||
import LanguageNamesWidget from './LanguageNamesWidget';
|
||||
|
||||
export const VideoPreviewWidget = ({
|
||||
thumbnail,
|
||||
videoSource,
|
||||
transcripts,
|
||||
blockTitle,
|
||||
intl,
|
||||
}) => {
|
||||
const imgRef = React.useRef();
|
||||
const videoType = intl.formatMessage(hooks.getVideoType(videoSource));
|
||||
|
||||
return (
|
||||
<Collapsible.Advanced
|
||||
className="collapsible-card rounded mx-4 my-3 px-4"
|
||||
defaultOpen
|
||||
open
|
||||
>
|
||||
<Collapsible.Body className="collapsible-body rounded px-0 py-4">
|
||||
<div className="d-flex flex-row">
|
||||
<Image
|
||||
thumbnail
|
||||
className="mr-3"
|
||||
ref={imgRef}
|
||||
src={thumbnail}
|
||||
alt={intl.formatMessage(thumbnailMessages.thumbnailAltText)}
|
||||
style={{
|
||||
maxWidth: '200px',
|
||||
minWidth: '200px',
|
||||
minHeight: '112px',
|
||||
maxHeight: '112px',
|
||||
}}
|
||||
/>
|
||||
<Stack gap={1} className="justify-content-center">
|
||||
<h4 className="text-primary mb-0">{blockTitle}</h4>
|
||||
<LanguageNamesWidget transcripts={transcripts} />
|
||||
{videoType && (
|
||||
<a
|
||||
className="text-primary x-small"
|
||||
href={videoSource}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{videoType}
|
||||
<Icon
|
||||
className="d-inline-block align-text-bottom pgn__icon__sm"
|
||||
src={Launch}
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
</Stack>
|
||||
</div>
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
);
|
||||
};
|
||||
|
||||
VideoPreviewWidget.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
videoSource: PropTypes.string.isRequired,
|
||||
thumbnail: PropTypes.string.isRequired,
|
||||
transcripts: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
blockTitle: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
transcripts: selectors.video.transcripts(state),
|
||||
videoSource: selectors.video.videoSource(state),
|
||||
thumbnail: selectors.video.thumbnail(state),
|
||||
blockTitle: selectors.app.blockTitle(state),
|
||||
});
|
||||
|
||||
export default injectIntl(connect(mapStateToProps)(VideoPreviewWidget));
|
||||
@@ -61,6 +61,20 @@ export const messages = {
|
||||
id: 'authoring.videoeditor.duration.custom',
|
||||
defaultMessage: 'Custom: {total}',
|
||||
description: 'Text describing a video with custom start time and custom stop time, or just a custom stop time for a collapsed widget',
|
||||
noTranscriptsAdded: {
|
||||
id: 'authoring.videoeditor.transcripts.empty',
|
||||
defaultMessage: 'No transcripts added',
|
||||
description: 'Message shown when the user has not selected any transcripts for the video.',
|
||||
},
|
||||
videoTypeYoutube: {
|
||||
id: 'authoring.videoeditor.videotype.youtube',
|
||||
defaultMessage: 'Youtube video',
|
||||
description: 'Shown on the preview card if the video is from youtube.com.',
|
||||
},
|
||||
videoTypeOther: {
|
||||
id: 'authoring.videoeditor.videotype.other',
|
||||
defaultMessage: 'Other video',
|
||||
description: 'Shown on the preview card if the video source could not be identified.',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@ import LicenseWidget from './components/LicenseWidget';
|
||||
import ThumbnailWidget from './components/ThumbnailWidget';
|
||||
import TranscriptWidget from './components/TranscriptWidget';
|
||||
import VideoSourceWidget from './components/VideoSourceWidget';
|
||||
import VideoPreviewWidget from './components/VideoPreviewWidget';
|
||||
import './index.scss';
|
||||
|
||||
export const VideoSettingsModal = () => (
|
||||
<>
|
||||
<ErrorSummary />
|
||||
<VideoPreviewWidget />
|
||||
<VideoSourceWidget />
|
||||
<ThumbnailWidget />
|
||||
<TranscriptWidget />
|
||||
|
||||
Reference in New Issue
Block a user