From 08f8e1c54608026eefccd7af8aaaa8e7a23ef511 Mon Sep 17 00:00:00 2001 From: Ben Wheeler <wheeler.benjamin@gmail.com> Date: Thu, 2 May 2019 17:18:13 -0400 Subject: [PATCH] simplified embed modal to remove social links --- src/components/modal/social/container.jsx | 41 +++-- src/components/modal/social/modal.scss | 41 +++-- src/components/modal/social/presentation.jsx | 169 +++++++------------ src/l10n.json | 2 +- src/lib/social.js | 2 +- src/views/preview/presentation.jsx | 4 - src/views/preview/project-view.jsx | 8 - src/views/preview/subactions.jsx | 1 - src/views/preview/subactions.scss | 5 +- static/svgs/project/embed-icon.svg | 1 + 10 files changed, 121 insertions(+), 153 deletions(-) create mode 100644 static/svgs/project/embed-icon.svg diff --git a/src/components/modal/social/container.jsx b/src/components/modal/social/container.jsx index 3125bf513..767415a7e 100644 --- a/src/components/modal/social/container.jsx +++ b/src/components/modal/social/container.jsx @@ -11,6 +11,7 @@ class SocialModal extends React.Component { this.embedTextarea = {}; this.embedCopyTimeoutId = null; this.linkCopyTimeoutId = null; + this.linkTextarea = {}; this.showCopyResultTimeout = 2000; this.state = { showEmbedResult: false, @@ -21,11 +22,14 @@ class SocialModal extends React.Component { 'handleCopyProjectLink', 'hideEmbedResult', 'hideLinkResult', - 'setEmbedTextarea' + 'linkUrl', + 'setEmbedTextarea', + 'setLinkTextarea' ]); } componentWillUnmount () { this.clearEmbedCopyResultTimeout(); + this.clearLinkCopyResultTimeout(); } handleCopyEmbed () { if (this.embedTextarea) { @@ -42,14 +46,17 @@ class SocialModal extends React.Component { } } handleCopyProjectLink () { - this.props.onCopyProjectLink(); - if (this.state.showLinkResult === false && this.linkCopyTimeoutId === null) { - this.setState({showLinkResult: true}, () => { - this.linkCopyTimeoutId = setTimeout( - this.hideLinkResult, - this.showCopyResultTimeout - ); - }); + if (this.linkTextarea) { + this.linkTextarea.select(); + clipboardCopy(this.linkTextarea.value); + if (this.state.showLinkResult === false && this.linkCopyTimeoutId === null) { + this.setState({showLinkResult: true}, () => { + this.linkCopyTimeoutId = setTimeout( + this.hideLinkResult, + this.showCopyResultTimeout + ); + }); + } } } hideEmbedResult () { @@ -60,16 +67,29 @@ class SocialModal extends React.Component { this.setState({showLinkResult: false}); this.linkCopyTimeoutId = null; } + linkUrl () { + return `${window.location.origin}${window.location.pathname}`; + } setEmbedTextarea (textarea) { this.embedTextarea = textarea; return textarea; } + setLinkTextarea (textarea) { + this.linkTextarea = textarea; + return textarea; + } clearEmbedCopyResultTimeout () { if (this.embedCopyTimeoutId !== null) { clearTimeout(this.embedCopyTimeoutId); this.embedCopyTimeoutId = null; } } + clearLinkCopyResultTimeout () { + if (this.linkCopyTimeoutId !== null) { + clearTimeout(this.linkCopyTimeoutId); + this.linkCopyTimeoutId = null; + } + } render () { const projectId = this.props.projectId; return ( @@ -78,7 +98,9 @@ class SocialModal extends React.Component { fbUrl={social.facebookIntentLink(projectId)} googleClassroomUrl={social.googleClassroomIntentLink(projectId)} isOpen={this.props.isOpen} + linkUrl={this.linkUrl()} setEmbedTextarea={this.setEmbedTextarea} + setLinkTextarea={this.setLinkTextarea} showEmbedResult={this.state.showEmbedResult} showLinkResult={this.state.showLinkResult} twitterUrl={social.twitterIntentLink(projectId)} @@ -93,7 +115,6 @@ class SocialModal extends React.Component { SocialModal.propTypes = { isOpen: PropTypes.bool, - onCopyProjectLink: PropTypes.func, onRequestClose: PropTypes.func, projectId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) }; diff --git a/src/components/modal/social/modal.scss b/src/components/modal/social/modal.scss index bc03a61da..ec1ce57ed 100644 --- a/src/components/modal/social/modal.scss +++ b/src/components/modal/social/modal.scss @@ -30,28 +30,39 @@ } .social-spaced-row { - width: 100%; + // width: 100%; justify-content: space-between; - align-items: start; + align-items: flex-end; +} + +.social-row-right { + margin-left: auto; } .social-label-row { + width: 100%; font-weight: bold; margin-bottom: .5rem; - justify-content: start; - align-items: start; + justify-content: space-between; + align-items: flex-end; } -.social-label { +.social-label-title { + font-size: 1rem; margin-right: 1.5rem; } +.social-label-item { + margin-left: 1.5rem; + margin-right: .25rem; +} + .social-label-result { color: $type-gray-75percent; transition: opacity 100ms linear; } -.embed-section { +.embed-section, .link-section { margin-top: 2rem; } @@ -115,7 +126,7 @@ // NOTE: copied from inplace-input.scss. We should refactor to put this style in // only one place. -.social-embed-textarea { +.social-embed-textarea, .social-link-textarea { transition: all .2s ease; border: 2px dashed $ui-blue-25percent; border-radius: 8px; @@ -128,6 +139,13 @@ resize: none; overflow: hidden; + width: 100%; + height: 6rem; + + textarea { + min-height: 4rem; + } + &:focus { transition: all .2s ease; outline: none; @@ -136,15 +154,6 @@ } } -.social-embed-textarea { - width: 100%; - height: 6rem; - - textarea { - min-height: 4rem; - } -} - // NOTE: should probably be put in a shared css location .social-hidden { opacity: 0.0; diff --git a/src/components/modal/social/presentation.jsx b/src/components/modal/social/presentation.jsx index e327fd6b8..1595a1b3d 100644 --- a/src/components/modal/social/presentation.jsx +++ b/src/components/modal/social/presentation.jsx @@ -14,18 +14,17 @@ require('./modal.scss'); const SocialModalPresentation = ({ embedHtml, - fbUrl, - googleClassroomUrl, intl, isOpen, + linkUrl, + onClickEmbedText, onCopyEmbed, onCopyProjectLink, onRequestClose, setEmbedTextarea, + setLinkTextarea, showEmbedResult, - showLinkResult, - twitterUrl, - weChatUrl + showLinkResult }) => { const title = intl.formatMessage({id: 'social.title'}); @@ -44,117 +43,68 @@ const SocialModalPresentation = ({ </div> <div className="modal-content social-modal-content"> - {/* top row: social links and copy link button */} - <FlexRow className="social-row social-spaced-row"> - - {/* social links */} - <div> + {/* top row: link */} + <div className="link-section"> + <FlexRow className="social-row social-spaced-row"> <FlexRow className="social-label-row"> - {intl.formatMessage({id: 'social.socialMediaLabel'})} - </FlexRow> - <FlexRow className="social-spaced-row"> - <a - alt="Google Classroom" - href={googleClassroomUrl} - target="_blank" - > - <div - className={classNames( - 'social-social-icon', - 'social-google-classroom-icon' - )} - /> - </a> - <a - alt="WeChat" - href={weChatUrl} - target="_blank" - > - <div - className={classNames( - 'social-social-icon', - 'social-wechat-icon' - )} - /> - </a> - <a - alt="Facebook" - href={fbUrl} - target="_blank" - > - <div - className={classNames( - 'social-social-icon', - 'social-facebook-icon' - )} - /> - </a> - <a - alt="Twitter" - href={twitterUrl} - target="_blank" - > - <div - className={classNames( - 'social-social-icon', - 'social-twitter-icon' - )} - /> - </a> - </FlexRow> - </div> - - {/* copy link button */} - <div> - <FlexRow className="social-label-row"> - <div className="social-label"> + <div className="social-label-title"> {intl.formatMessage({id: 'social.linkLabel'})} </div> - <div - className={classNames( - 'social-label', - 'social-label-result', - {'social-hidden': !showLinkResult} - )} - > - {intl.formatMessage({id: 'social.embedCopiedResultText'})} - </div> + <FlexRow className="social-spaced-row social-row-right"> + <div + className={classNames( + 'social-label-item', + 'social-label-result', + {'social-hidden': !showLinkResult} + )} + > + {intl.formatMessage({id: 'social.embedCopiedResultText'})} + </div> + <div className="social-label-item"> + <a + onClick={onCopyProjectLink} + > + {intl.formatMessage({id: 'general.copyLink'})} + </a> + </div> + </FlexRow> </FlexRow> - <FlexRow className="social-spaced-row"> - <Button - className="social-copy-link-button social-copy-link-button-large" - onClick={onCopyProjectLink} - > - <FormattedMessage id="general.copyLink" /> - </Button> - </FlexRow> - </div> - - </FlexRow> + <textarea + readOnly + className="social-link-textarea" + name="link" + ref={textarea => setLinkTextarea(textarea)} + value={linkUrl} + onClick={onClickProjectLinkText} + /> + </FlexRow> + </div> {/* bottom row: embed */} <div className="embed-section"> <FlexRow className="social-row social-spaced-row"> <FlexRow className="social-label-row"> - <div className="social-label"> + <div className="social-label-title"> {intl.formatMessage({id: 'social.embedHtmlLabel'})} </div> - <div className="social-label"> - <a - onClick={onCopyEmbed} + <FlexRow className="social-spaced-row social-row-right"> + <div + className={classNames( + 'social-label-item', + 'social-label-result', + {'social-hidden': !showEmbedResult} + )} > - {intl.formatMessage({id: 'social.copyEmbedLinkText'})} - </a> - </div> - <div - className={classNames( - 'social-label', - 'social-label-result', - {'social-hidden': !showEmbedResult} - )} - > - {intl.formatMessage({id: 'social.embedCopiedResultText'})} - </div> + {intl.formatMessage({id: 'social.embedCopiedResultText'})} + </div> + <div className="social-label-item"> + <a + onClick={onCopyEmbed} + > + {intl.formatMessage({id: 'social.copyEmbedLinkText'})} + </a> + </div> + </FlexRow> </FlexRow> <textarea readOnly @@ -162,7 +112,7 @@ const SocialModalPresentation = ({ name="embed" ref={textarea => setEmbedTextarea(textarea)} value={embedHtml} - onClick={onCopyEmbed} + onClick={onClickEmbedText} /> </FlexRow> </div> @@ -174,18 +124,17 @@ const SocialModalPresentation = ({ SocialModalPresentation.propTypes = { embedHtml: PropTypes.string, - fbUrl: PropTypes.string, - googleClassroomUrl: PropTypes.string, intl: intlShape, isOpen: PropTypes.bool, + linkUrl: PropTypes.string, + onClickEmbedText: PropTypes.func, onCopyEmbed: PropTypes.func, onCopyProjectLink: PropTypes.func, onRequestClose: PropTypes.func, setEmbedTextarea: PropTypes.func, + setLinkTextarea: PropTypes.func, showEmbedResult: PropTypes.bool, - showLinkResult: PropTypes.bool, - twitterUrl: PropTypes.string, - weChatUrl: PropTypes.string + showLinkResult: PropTypes.bool }; module.exports = injectIntl(SocialModalPresentation); diff --git a/src/l10n.json b/src/l10n.json index 8d085798f..710f984c7 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -258,7 +258,7 @@ "comments.status.deleted": "Deleted", "comments.status.reported": "Reported", - "social.title": "Social", + "social.title": "Embed", "social.embedHtmlLabel": "Embed", "social.copyEmbedLinkText": "Copy embed", "social.linkLabel": "Link", diff --git a/src/lib/social.js b/src/lib/social.js index cb4d4f0f9..a23da86ba 100644 --- a/src/lib/social.js +++ b/src/lib/social.js @@ -2,7 +2,7 @@ module.exports = {}; module.exports.embedHtml = projectId => { if (projectId) { - return `<iframe src="https://scratch.mit.edu/projects/${projectId}/embed?autostart=false" ` + + return `<iframe src="https://scratch.mit.edu/projects/${projectId}/embed" ` + 'allowtransparency="true" width="485" height="402" ' + 'frameborder="0" scrolling="no" allowfullscreen></iframe>'; } diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx index 20ca303d7..0e764a868 100644 --- a/src/views/preview/presentation.jsx +++ b/src/views/preview/presentation.jsx @@ -88,7 +88,6 @@ const PreviewPresentation = ({ onAddToStudioClicked, onAddToStudioClosed, onCloseAdminPanel, - onCopyProjectLink, onDeleteComment, onFavoriteClicked, onGreenFlag, @@ -375,7 +374,6 @@ const PreviewPresentation = ({ userOwnsProject={userOwnsProject} onAddToStudioClicked={onAddToStudioClicked} onAddToStudioClosed={onAddToStudioClosed} - onCopyProjectLink={onCopyProjectLink} onReportClicked={onReportClicked} onReportClose={onReportClose} onReportSubmit={onReportSubmit} @@ -524,7 +522,6 @@ const PreviewPresentation = ({ userOwnsProject={userOwnsProject} onAddToStudioClicked={onAddToStudioClicked} onAddToStudioClosed={onAddToStudioClosed} - onCopyProjectLink={onCopyProjectLink} onReportClicked={onReportClicked} onReportClose={onReportClose} onReportSubmit={onReportSubmit} @@ -702,7 +699,6 @@ PreviewPresentation.propTypes = { onAddToStudioClicked: PropTypes.func, onAddToStudioClosed: PropTypes.func, onCloseAdminPanel: PropTypes.func, - onCopyProjectLink: PropTypes.func, onDeleteComment: PropTypes.func, onFavoriteClicked: PropTypes.func, onGreenFlag: PropTypes.func, diff --git a/src/views/preview/project-view.jsx b/src/views/preview/project-view.jsx index 4cfb2d3ac..5b943d3c6 100644 --- a/src/views/preview/project-view.jsx +++ b/src/views/preview/project-view.jsx @@ -8,7 +8,6 @@ const PropTypes = require('prop-types'); const connect = require('react-redux').connect; const injectIntl = require('react-intl').injectIntl; const parser = require('scratch-parser'); -const copy = require('clipboard-copy'); const Page = require('../../components/page/www/page.jsx'); const storage = require('../../lib/storage.js').default; @@ -55,7 +54,6 @@ class Preview extends React.Component { 'fetchCommunityData', 'handleAddComment', 'handleClickLogo', - 'handleCopyProjectLink', 'handleDeleteComment', 'handleSocialClick', 'handleSocialClose', @@ -582,11 +580,6 @@ class Preview extends React.Component { this.props.user.token ); } - handleCopyProjectLink () { - // Use the pathname so we do not have to update this if path changes - // Also do not include hash or query params - copy(`${window.location.origin}${window.location.pathname}`); - } handleSocialClick () { this.setState({socialOpen: true}); } @@ -694,7 +687,6 @@ class Preview extends React.Component { onAddToStudioClicked={this.handleAddToStudioClick} onAddToStudioClosed={this.handleAddToStudioClose} onCloseAdminPanel={this.handleCloseAdminPanel} - onCopyProjectLink={this.handleCopyProjectLink} onDeleteComment={this.handleDeleteComment} onFavoriteClicked={this.handleFavoriteToggle} onGreenFlag={this.handleGreenFlag} diff --git a/src/views/preview/subactions.jsx b/src/views/preview/subactions.jsx index 373f8cef9..f834e5798 100644 --- a/src/views/preview/subactions.jsx +++ b/src/views/preview/subactions.jsx @@ -61,7 +61,6 @@ const Subactions = props => ( isOpen key="social-modal" projectId={props.projectInfo && props.projectInfo.id} - onCopyProjectLink={props.onCopyProjectLink} onRequestClose={props.onSocialClosed} /> )} diff --git a/src/views/preview/subactions.scss b/src/views/preview/subactions.scss index 8d478c3d8..05837a75c 100644 --- a/src/views/preview/subactions.scss +++ b/src/views/preview/subactions.scss @@ -61,7 +61,8 @@ } &.studio-button, &.copy-link-button, - &.report-button { + &.report-button, + &.social-button { &:before { display: inline-block; margin-right: .25rem; @@ -89,7 +90,7 @@ &.social-button { &:before { - background-image: url("/svgs/project/copy-link-white.svg"); + background-image: url("/svgs/project/embed-icon.svg"); } } diff --git a/static/svgs/project/embed-icon.svg b/static/svgs/project/embed-icon.svg new file mode 100644 index 000000000..6eeb28a56 --- /dev/null +++ b/static/svgs/project/embed-icon.svg @@ -0,0 +1 @@ +<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M10.049 6.474a7.627 7.627 0 0 1 3.35 1.485 7.743 7.743 0 0 1 .89.826c.244.27.504.614.717.941a6.65 6.65 0 0 1 .872 2.11 6.32 6.32 0 0 1 .11 1.911c-.056.554-.165.98-.271 1.313-.05.163-.091.238-.118.314l-.042.106a.81.81 0 0 1-.834.492c-.443-.043-.765-.423-.72-.848l.013-.111c.003-.066.027-.196.024-.3a4.307 4.307 0 0 0-.51-2.145 4.2 4.2 0 0 0-.886-1.107 5.127 5.127 0 0 0-.581-.427c-.138-.092-.166-.089-.283-.151-.098-.052-.2-.092-.296-.134a3.93 3.93 0 0 0-1.095-.257 4.049 4.049 0 0 0-.34-.011v1.307c0 .522-.325.99-.828 1.19a1.38 1.38 0 0 1-1.463-.279L4.383 9.457a1.253 1.253 0 0 1 0-1.821l3.375-3.242c.385-.37.96-.48 1.463-.279.503.2.828.668.828 1.19v1.17z" id="a"/></defs><g transform="matrix(-1 0 0 1 20 0)" fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><use fill="#4C97FF" xlink:href="#a"/><g mask="url(#b)" fill="#FFF"><path d="M0 0h20v20H0z"/></g></g></svg> \ No newline at end of file