simplified embed modal to remove social links

This commit is contained in:
Ben Wheeler 2019-05-02 17:18:13 -04:00
parent fdfa61649f
commit 08f8e1c546
10 changed files with 121 additions and 153 deletions

View file

@ -11,6 +11,7 @@ class SocialModal extends React.Component {
this.embedTextarea = {}; this.embedTextarea = {};
this.embedCopyTimeoutId = null; this.embedCopyTimeoutId = null;
this.linkCopyTimeoutId = null; this.linkCopyTimeoutId = null;
this.linkTextarea = {};
this.showCopyResultTimeout = 2000; this.showCopyResultTimeout = 2000;
this.state = { this.state = {
showEmbedResult: false, showEmbedResult: false,
@ -21,11 +22,14 @@ class SocialModal extends React.Component {
'handleCopyProjectLink', 'handleCopyProjectLink',
'hideEmbedResult', 'hideEmbedResult',
'hideLinkResult', 'hideLinkResult',
'setEmbedTextarea' 'linkUrl',
'setEmbedTextarea',
'setLinkTextarea'
]); ]);
} }
componentWillUnmount () { componentWillUnmount () {
this.clearEmbedCopyResultTimeout(); this.clearEmbedCopyResultTimeout();
this.clearLinkCopyResultTimeout();
} }
handleCopyEmbed () { handleCopyEmbed () {
if (this.embedTextarea) { if (this.embedTextarea) {
@ -42,14 +46,17 @@ class SocialModal extends React.Component {
} }
} }
handleCopyProjectLink () { handleCopyProjectLink () {
this.props.onCopyProjectLink(); if (this.linkTextarea) {
if (this.state.showLinkResult === false && this.linkCopyTimeoutId === null) { this.linkTextarea.select();
this.setState({showLinkResult: true}, () => { clipboardCopy(this.linkTextarea.value);
this.linkCopyTimeoutId = setTimeout( if (this.state.showLinkResult === false && this.linkCopyTimeoutId === null) {
this.hideLinkResult, this.setState({showLinkResult: true}, () => {
this.showCopyResultTimeout this.linkCopyTimeoutId = setTimeout(
); this.hideLinkResult,
}); this.showCopyResultTimeout
);
});
}
} }
} }
hideEmbedResult () { hideEmbedResult () {
@ -60,16 +67,29 @@ class SocialModal extends React.Component {
this.setState({showLinkResult: false}); this.setState({showLinkResult: false});
this.linkCopyTimeoutId = null; this.linkCopyTimeoutId = null;
} }
linkUrl () {
return `${window.location.origin}${window.location.pathname}`;
}
setEmbedTextarea (textarea) { setEmbedTextarea (textarea) {
this.embedTextarea = textarea; this.embedTextarea = textarea;
return textarea; return textarea;
} }
setLinkTextarea (textarea) {
this.linkTextarea = textarea;
return textarea;
}
clearEmbedCopyResultTimeout () { clearEmbedCopyResultTimeout () {
if (this.embedCopyTimeoutId !== null) { if (this.embedCopyTimeoutId !== null) {
clearTimeout(this.embedCopyTimeoutId); clearTimeout(this.embedCopyTimeoutId);
this.embedCopyTimeoutId = null; this.embedCopyTimeoutId = null;
} }
} }
clearLinkCopyResultTimeout () {
if (this.linkCopyTimeoutId !== null) {
clearTimeout(this.linkCopyTimeoutId);
this.linkCopyTimeoutId = null;
}
}
render () { render () {
const projectId = this.props.projectId; const projectId = this.props.projectId;
return ( return (
@ -78,7 +98,9 @@ class SocialModal extends React.Component {
fbUrl={social.facebookIntentLink(projectId)} fbUrl={social.facebookIntentLink(projectId)}
googleClassroomUrl={social.googleClassroomIntentLink(projectId)} googleClassroomUrl={social.googleClassroomIntentLink(projectId)}
isOpen={this.props.isOpen} isOpen={this.props.isOpen}
linkUrl={this.linkUrl()}
setEmbedTextarea={this.setEmbedTextarea} setEmbedTextarea={this.setEmbedTextarea}
setLinkTextarea={this.setLinkTextarea}
showEmbedResult={this.state.showEmbedResult} showEmbedResult={this.state.showEmbedResult}
showLinkResult={this.state.showLinkResult} showLinkResult={this.state.showLinkResult}
twitterUrl={social.twitterIntentLink(projectId)} twitterUrl={social.twitterIntentLink(projectId)}
@ -93,7 +115,6 @@ class SocialModal extends React.Component {
SocialModal.propTypes = { SocialModal.propTypes = {
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
onCopyProjectLink: PropTypes.func,
onRequestClose: PropTypes.func, onRequestClose: PropTypes.func,
projectId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) projectId: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
}; };

View file

@ -30,28 +30,39 @@
} }
.social-spaced-row { .social-spaced-row {
width: 100%; // width: 100%;
justify-content: space-between; justify-content: space-between;
align-items: start; align-items: flex-end;
}
.social-row-right {
margin-left: auto;
} }
.social-label-row { .social-label-row {
width: 100%;
font-weight: bold; font-weight: bold;
margin-bottom: .5rem; margin-bottom: .5rem;
justify-content: start; justify-content: space-between;
align-items: start; align-items: flex-end;
} }
.social-label { .social-label-title {
font-size: 1rem;
margin-right: 1.5rem; margin-right: 1.5rem;
} }
.social-label-item {
margin-left: 1.5rem;
margin-right: .25rem;
}
.social-label-result { .social-label-result {
color: $type-gray-75percent; color: $type-gray-75percent;
transition: opacity 100ms linear; transition: opacity 100ms linear;
} }
.embed-section { .embed-section, .link-section {
margin-top: 2rem; margin-top: 2rem;
} }
@ -115,7 +126,7 @@
// NOTE: copied from inplace-input.scss. We should refactor to put this style in // NOTE: copied from inplace-input.scss. We should refactor to put this style in
// only one place. // only one place.
.social-embed-textarea { .social-embed-textarea, .social-link-textarea {
transition: all .2s ease; transition: all .2s ease;
border: 2px dashed $ui-blue-25percent; border: 2px dashed $ui-blue-25percent;
border-radius: 8px; border-radius: 8px;
@ -128,6 +139,13 @@
resize: none; resize: none;
overflow: hidden; overflow: hidden;
width: 100%;
height: 6rem;
textarea {
min-height: 4rem;
}
&:focus { &:focus {
transition: all .2s ease; transition: all .2s ease;
outline: none; 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 // NOTE: should probably be put in a shared css location
.social-hidden { .social-hidden {
opacity: 0.0; opacity: 0.0;

View file

@ -14,18 +14,17 @@ require('./modal.scss');
const SocialModalPresentation = ({ const SocialModalPresentation = ({
embedHtml, embedHtml,
fbUrl,
googleClassroomUrl,
intl, intl,
isOpen, isOpen,
linkUrl,
onClickEmbedText,
onCopyEmbed, onCopyEmbed,
onCopyProjectLink, onCopyProjectLink,
onRequestClose, onRequestClose,
setEmbedTextarea, setEmbedTextarea,
setLinkTextarea,
showEmbedResult, showEmbedResult,
showLinkResult, showLinkResult
twitterUrl,
weChatUrl
}) => { }) => {
const title = intl.formatMessage({id: 'social.title'}); const title = intl.formatMessage({id: 'social.title'});
@ -44,117 +43,68 @@ const SocialModalPresentation = ({
</div> </div>
<div className="modal-content social-modal-content"> <div className="modal-content social-modal-content">
{/* top row: social links and copy link button */} {/* top row: link */}
<FlexRow className="social-row social-spaced-row"> <div className="link-section">
<FlexRow className="social-row social-spaced-row">
{/* social links */}
<div>
<FlexRow className="social-label-row"> <FlexRow className="social-label-row">
{intl.formatMessage({id: 'social.socialMediaLabel'})} <div className="social-label-title">
</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">
{intl.formatMessage({id: 'social.linkLabel'})} {intl.formatMessage({id: 'social.linkLabel'})}
</div> </div>
<div <FlexRow className="social-spaced-row social-row-right">
className={classNames( <div
'social-label', className={classNames(
'social-label-result', 'social-label-item',
{'social-hidden': !showLinkResult} 'social-label-result',
)} {'social-hidden': !showLinkResult}
> )}
{intl.formatMessage({id: 'social.embedCopiedResultText'})} >
</div> {intl.formatMessage({id: 'social.embedCopiedResultText'})}
</div>
<div className="social-label-item">
<a
onClick={onCopyProjectLink}
>
{intl.formatMessage({id: 'general.copyLink'})}
</a>
</div>
</FlexRow>
</FlexRow> </FlexRow>
<FlexRow className="social-spaced-row"> <textarea
<Button readOnly
className="social-copy-link-button social-copy-link-button-large" className="social-link-textarea"
onClick={onCopyProjectLink} name="link"
> ref={textarea => setLinkTextarea(textarea)}
<FormattedMessage id="general.copyLink" /> value={linkUrl}
</Button> onClick={onClickProjectLinkText}
</FlexRow> />
</div> </FlexRow>
</div>
</FlexRow>
{/* bottom row: embed */} {/* bottom row: embed */}
<div className="embed-section"> <div className="embed-section">
<FlexRow className="social-row social-spaced-row"> <FlexRow className="social-row social-spaced-row">
<FlexRow className="social-label-row"> <FlexRow className="social-label-row">
<div className="social-label"> <div className="social-label-title">
{intl.formatMessage({id: 'social.embedHtmlLabel'})} {intl.formatMessage({id: 'social.embedHtmlLabel'})}
</div> </div>
<div className="social-label"> <FlexRow className="social-spaced-row social-row-right">
<a <div
onClick={onCopyEmbed} className={classNames(
'social-label-item',
'social-label-result',
{'social-hidden': !showEmbedResult}
)}
> >
{intl.formatMessage({id: 'social.copyEmbedLinkText'})} {intl.formatMessage({id: 'social.embedCopiedResultText'})}
</a> </div>
</div> <div className="social-label-item">
<div <a
className={classNames( onClick={onCopyEmbed}
'social-label', >
'social-label-result', {intl.formatMessage({id: 'social.copyEmbedLinkText'})}
{'social-hidden': !showEmbedResult} </a>
)} </div>
> </FlexRow>
{intl.formatMessage({id: 'social.embedCopiedResultText'})}
</div>
</FlexRow> </FlexRow>
<textarea <textarea
readOnly readOnly
@ -162,7 +112,7 @@ const SocialModalPresentation = ({
name="embed" name="embed"
ref={textarea => setEmbedTextarea(textarea)} ref={textarea => setEmbedTextarea(textarea)}
value={embedHtml} value={embedHtml}
onClick={onCopyEmbed} onClick={onClickEmbedText}
/> />
</FlexRow> </FlexRow>
</div> </div>
@ -174,18 +124,17 @@ const SocialModalPresentation = ({
SocialModalPresentation.propTypes = { SocialModalPresentation.propTypes = {
embedHtml: PropTypes.string, embedHtml: PropTypes.string,
fbUrl: PropTypes.string,
googleClassroomUrl: PropTypes.string,
intl: intlShape, intl: intlShape,
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
linkUrl: PropTypes.string,
onClickEmbedText: PropTypes.func,
onCopyEmbed: PropTypes.func, onCopyEmbed: PropTypes.func,
onCopyProjectLink: PropTypes.func, onCopyProjectLink: PropTypes.func,
onRequestClose: PropTypes.func, onRequestClose: PropTypes.func,
setEmbedTextarea: PropTypes.func, setEmbedTextarea: PropTypes.func,
setLinkTextarea: PropTypes.func,
showEmbedResult: PropTypes.bool, showEmbedResult: PropTypes.bool,
showLinkResult: PropTypes.bool, showLinkResult: PropTypes.bool
twitterUrl: PropTypes.string,
weChatUrl: PropTypes.string
}; };
module.exports = injectIntl(SocialModalPresentation); module.exports = injectIntl(SocialModalPresentation);

View file

@ -258,7 +258,7 @@
"comments.status.deleted": "Deleted", "comments.status.deleted": "Deleted",
"comments.status.reported": "Reported", "comments.status.reported": "Reported",
"social.title": "Social", "social.title": "Embed",
"social.embedHtmlLabel": "Embed", "social.embedHtmlLabel": "Embed",
"social.copyEmbedLinkText": "Copy embed", "social.copyEmbedLinkText": "Copy embed",
"social.linkLabel": "Link", "social.linkLabel": "Link",

View file

@ -2,7 +2,7 @@ module.exports = {};
module.exports.embedHtml = projectId => { module.exports.embedHtml = projectId => {
if (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" ' + 'allowtransparency="true" width="485" height="402" ' +
'frameborder="0" scrolling="no" allowfullscreen></iframe>'; 'frameborder="0" scrolling="no" allowfullscreen></iframe>';
} }

View file

@ -88,7 +88,6 @@ const PreviewPresentation = ({
onAddToStudioClicked, onAddToStudioClicked,
onAddToStudioClosed, onAddToStudioClosed,
onCloseAdminPanel, onCloseAdminPanel,
onCopyProjectLink,
onDeleteComment, onDeleteComment,
onFavoriteClicked, onFavoriteClicked,
onGreenFlag, onGreenFlag,
@ -375,7 +374,6 @@ const PreviewPresentation = ({
userOwnsProject={userOwnsProject} userOwnsProject={userOwnsProject}
onAddToStudioClicked={onAddToStudioClicked} onAddToStudioClicked={onAddToStudioClicked}
onAddToStudioClosed={onAddToStudioClosed} onAddToStudioClosed={onAddToStudioClosed}
onCopyProjectLink={onCopyProjectLink}
onReportClicked={onReportClicked} onReportClicked={onReportClicked}
onReportClose={onReportClose} onReportClose={onReportClose}
onReportSubmit={onReportSubmit} onReportSubmit={onReportSubmit}
@ -524,7 +522,6 @@ const PreviewPresentation = ({
userOwnsProject={userOwnsProject} userOwnsProject={userOwnsProject}
onAddToStudioClicked={onAddToStudioClicked} onAddToStudioClicked={onAddToStudioClicked}
onAddToStudioClosed={onAddToStudioClosed} onAddToStudioClosed={onAddToStudioClosed}
onCopyProjectLink={onCopyProjectLink}
onReportClicked={onReportClicked} onReportClicked={onReportClicked}
onReportClose={onReportClose} onReportClose={onReportClose}
onReportSubmit={onReportSubmit} onReportSubmit={onReportSubmit}
@ -702,7 +699,6 @@ PreviewPresentation.propTypes = {
onAddToStudioClicked: PropTypes.func, onAddToStudioClicked: PropTypes.func,
onAddToStudioClosed: PropTypes.func, onAddToStudioClosed: PropTypes.func,
onCloseAdminPanel: PropTypes.func, onCloseAdminPanel: PropTypes.func,
onCopyProjectLink: PropTypes.func,
onDeleteComment: PropTypes.func, onDeleteComment: PropTypes.func,
onFavoriteClicked: PropTypes.func, onFavoriteClicked: PropTypes.func,
onGreenFlag: PropTypes.func, onGreenFlag: PropTypes.func,

View file

@ -8,7 +8,6 @@ const PropTypes = require('prop-types');
const connect = require('react-redux').connect; const connect = require('react-redux').connect;
const injectIntl = require('react-intl').injectIntl; const injectIntl = require('react-intl').injectIntl;
const parser = require('scratch-parser'); const parser = require('scratch-parser');
const copy = require('clipboard-copy');
const Page = require('../../components/page/www/page.jsx'); const Page = require('../../components/page/www/page.jsx');
const storage = require('../../lib/storage.js').default; const storage = require('../../lib/storage.js').default;
@ -55,7 +54,6 @@ class Preview extends React.Component {
'fetchCommunityData', 'fetchCommunityData',
'handleAddComment', 'handleAddComment',
'handleClickLogo', 'handleClickLogo',
'handleCopyProjectLink',
'handleDeleteComment', 'handleDeleteComment',
'handleSocialClick', 'handleSocialClick',
'handleSocialClose', 'handleSocialClose',
@ -582,11 +580,6 @@ class Preview extends React.Component {
this.props.user.token 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 () { handleSocialClick () {
this.setState({socialOpen: true}); this.setState({socialOpen: true});
} }
@ -694,7 +687,6 @@ class Preview extends React.Component {
onAddToStudioClicked={this.handleAddToStudioClick} onAddToStudioClicked={this.handleAddToStudioClick}
onAddToStudioClosed={this.handleAddToStudioClose} onAddToStudioClosed={this.handleAddToStudioClose}
onCloseAdminPanel={this.handleCloseAdminPanel} onCloseAdminPanel={this.handleCloseAdminPanel}
onCopyProjectLink={this.handleCopyProjectLink}
onDeleteComment={this.handleDeleteComment} onDeleteComment={this.handleDeleteComment}
onFavoriteClicked={this.handleFavoriteToggle} onFavoriteClicked={this.handleFavoriteToggle}
onGreenFlag={this.handleGreenFlag} onGreenFlag={this.handleGreenFlag}

View file

@ -61,7 +61,6 @@ const Subactions = props => (
isOpen isOpen
key="social-modal" key="social-modal"
projectId={props.projectInfo && props.projectInfo.id} projectId={props.projectInfo && props.projectInfo.id}
onCopyProjectLink={props.onCopyProjectLink}
onRequestClose={props.onSocialClosed} onRequestClose={props.onSocialClosed}
/> />
)} )}

View file

@ -61,7 +61,8 @@
} }
&.studio-button, &.studio-button,
&.copy-link-button, &.copy-link-button,
&.report-button { &.report-button,
&.social-button {
&:before { &:before {
display: inline-block; display: inline-block;
margin-right: .25rem; margin-right: .25rem;
@ -89,7 +90,7 @@
&.social-button { &.social-button {
&:before { &:before {
background-image: url("/svgs/project/copy-link-white.svg"); background-image: url("/svgs/project/embed-icon.svg");
} }
} }

View file

@ -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>

After

Width:  |  Height:  |  Size: 1,022 B