mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-17 00:21:20 -05:00
first attempt at external share modal
This commit is contained in:
parent
db4c81fbec
commit
9587de480c
7 changed files with 380 additions and 0 deletions
27
src/components/modal/externalshare/container.jsx
Normal file
27
src/components/modal/externalshare/container.jsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
const bindAll = require('lodash.bindall');
|
||||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const ExternalShareModalPresentation = require('./presentation.jsx');
|
||||
|
||||
class ExternalShareModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<ExternalShareModalPresentation
|
||||
isOpen={this.props.isOpen}
|
||||
onRequestClose={this.props.onRequestClose}
|
||||
onSubmit={this.props.onRequestClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExternalShareModal.propTypes = {
|
||||
isOpen: PropTypes.bool,
|
||||
onRequestClose: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = ExternalShareModal;
|
194
src/components/modal/externalshare/modal.scss
Normal file
194
src/components/modal/externalshare/modal.scss
Normal file
|
@ -0,0 +1,194 @@
|
|||
@import "../../../colors";
|
||||
@import "../../../frameless";
|
||||
|
||||
.mod-externalShare {
|
||||
min-height: 15rem;
|
||||
max-height: calc(100% - 8rem);
|
||||
|
||||
/* Some value for height must be set for scrolling to work */
|
||||
height: 100%;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
@media #{$small}, #{$small-height} {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.externalShare-modal-header {
|
||||
box-shadow: inset 0 -1px 0 0 $ui-blue-dark;
|
||||
background-color: $ui-blue;
|
||||
}
|
||||
|
||||
.externalShare-modal-content {
|
||||
margin: 0 auto;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
height: calc(100% - 3rem);
|
||||
}
|
||||
|
||||
.external-target-outer-scrollbox {
|
||||
position: relative;
|
||||
background-color: $ui-blue-10percent;
|
||||
flex: 1;
|
||||
height: calc(100% - 5rem);
|
||||
|
||||
@media #{$small-height} {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.external-target-inner-scrollbox {
|
||||
margin-right: .5rem;
|
||||
padding-right: .5rem;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background-color: $active-dark-gray;
|
||||
height: 92px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.external-target-container {
|
||||
display: flex;
|
||||
padding: .40625rem 0 0 1.46875rem;
|
||||
justify-content: flex-start;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
/* NOTE: force scrolling: add to above:
|
||||
min-height: 30rem;
|
||||
*/
|
||||
|
||||
.external-target-bottom-gradient {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: linear-gradient(
|
||||
$transparent-light-blue,
|
||||
$ui-light-primary
|
||||
);
|
||||
height: 32px;
|
||||
pointer-events: none; /* pass clicks through to buttons underneath */
|
||||
}
|
||||
|
||||
.studio-selector-button {
|
||||
display: flex;
|
||||
position: relative;
|
||||
transition: all .5s;
|
||||
margin: .21875rem;
|
||||
border-radius: .5rem;
|
||||
background-color: $ui-white;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 48%;
|
||||
height: 2.5rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
@media #{$small} {
|
||||
min-width: 98%;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.studio-selector-button-text {
|
||||
margin: auto 2.18375rem auto .6875rem;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: .875rem;
|
||||
font-weight: regular;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.studio-selector-button-selected {
|
||||
background-color: $ui-mint-green;
|
||||
color: $ui-white;
|
||||
}
|
||||
|
||||
.studio-selector-button-waiting {
|
||||
background-color: $ui-light-mint;
|
||||
color: $ui-white;
|
||||
}
|
||||
|
||||
.studio-selector-button-text-selected {
|
||||
color: $ui-white;
|
||||
}
|
||||
|
||||
.studio-selector-button-text-unselected {
|
||||
color: $type-gray;
|
||||
}
|
||||
|
||||
.studio-selector-button-enabled {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.studio-selector-button-disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.studio-status-icon {
|
||||
position: absolute;
|
||||
right: .625rem;
|
||||
border-radius: .75rem;
|
||||
padding: .0625rem .075rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
color: $ui-white;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.studio-status-icon-unselected {
|
||||
background-color: $ui-blue;
|
||||
}
|
||||
|
||||
.submit-button {
|
||||
background-color: $ui-blue;
|
||||
}
|
||||
|
||||
.submit-button-waiting {
|
||||
background-color: $ui-blue;
|
||||
}
|
||||
|
||||
.studio-status-icon-plus-img,
|
||||
.studio-status-icon-checkmark-img {
|
||||
animation-direction: normal;
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.studio-status-icon-with-animation {
|
||||
animation-name: bump;
|
||||
animation-duration: .25s;
|
||||
animation-timing-function: cubic-bezier(.3, -3, .6, 3);
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
@keyframes bump {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
-webkit-transform: scale(1);
|
||||
}
|
||||
}
|
113
src/components/modal/externalshare/presentation.jsx
Normal file
113
src/components/modal/externalshare/presentation.jsx
Normal file
|
@ -0,0 +1,113 @@
|
|||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const FormattedMessage = require('react-intl').FormattedMessage;
|
||||
const injectIntl = require('react-intl').injectIntl;
|
||||
const intlShape = require('react-intl').intlShape;
|
||||
const Modal = require('../base/modal.jsx');
|
||||
|
||||
const Form = require('../../forms/form.jsx');
|
||||
const Button = require('../../forms/button.jsx');
|
||||
const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||
const Input = require('../../components/forms/input.jsx');
|
||||
const TextArea = require('../../components/forms/textarea.jsx');
|
||||
|
||||
require('../../forms/button.scss');
|
||||
require('./modal.scss');
|
||||
|
||||
const ExternalShareModalPresentation = ({
|
||||
intl,
|
||||
isOpen,
|
||||
studios,
|
||||
waitingToClose,
|
||||
onToggleStudio,
|
||||
onRequestClose,
|
||||
onSubmit
|
||||
}) => {
|
||||
const contentLabel = intl.formatMessage({id: 'externalshare.title'});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
useStandardSizes
|
||||
className="mod-externalShare"
|
||||
contentLabel={contentLabel}
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
>
|
||||
<div className="externalShare-modal-header modal-header">
|
||||
<div className="externalShare-content-label content-label">
|
||||
{contentLabel}
|
||||
</div>
|
||||
</div>
|
||||
<div className="externalShare-modal-content modal-content">
|
||||
<div className="external-target-outer-scrollbox">
|
||||
<div className="external-target-inner-scrollbox">
|
||||
<div className="external-target-container">
|
||||
<Form
|
||||
ref={form => {
|
||||
this.form = form;
|
||||
}}
|
||||
onValidSubmit={this.handleValidSubmit}
|
||||
>
|
||||
<div>
|
||||
<div className="username-label">
|
||||
<b>
|
||||
{this.props.intl.formatMessage({id: 'registration.createUsername'})}
|
||||
</b>
|
||||
{this.props.usernameHelp ? (
|
||||
<p className="help-text">{this.props.usernameHelp}</p>
|
||||
) : (
|
||||
null
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
name="user.username"
|
||||
type="text"
|
||||
onBlur={this.handleUsernameBlur}
|
||||
/>
|
||||
<TextArea
|
||||
required
|
||||
className="report-text"
|
||||
elementWrapperClassName="report-modal-field"
|
||||
label={null}
|
||||
name="notes"
|
||||
placeholder={this.lookupPrompt(this.state.category)}
|
||||
value={this.state.notes}
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
</div>
|
||||
<div className="external-target-bottom-gradient" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<Form
|
||||
// className="external-share"
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<FlexRow className="action-buttons">
|
||||
<Button
|
||||
className="action-button submit-button"
|
||||
key="submitButton"
|
||||
type="submit"
|
||||
>
|
||||
<div className="action-button-text">
|
||||
<FormattedMessage id="general.done" />
|
||||
</div>
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</Form>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
ExternalShareModalPresentation.propTypes = {
|
||||
intl: intlShape,
|
||||
isOpen: PropTypes.bool,
|
||||
onRequestClose: PropTypes.func,
|
||||
onSubmit: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = injectIntl(ExternalShareModalPresentation);
|
|
@ -67,6 +67,7 @@ const PreviewPresentation = ({
|
|||
comments,
|
||||
editable,
|
||||
extensions,
|
||||
externalShareOpen,
|
||||
faved,
|
||||
favoriteCount,
|
||||
intl,
|
||||
|
@ -90,6 +91,8 @@ const PreviewPresentation = ({
|
|||
onCloseAdminPanel,
|
||||
onCopyProjectLink,
|
||||
onDeleteComment,
|
||||
onExternalShareClicked,
|
||||
onExternalShareClosed,
|
||||
onFavoriteClicked,
|
||||
onGreenFlag,
|
||||
onLoadMore,
|
||||
|
@ -364,6 +367,7 @@ const PreviewPresentation = ({
|
|||
<Subactions
|
||||
addToStudioOpen={addToStudioOpen}
|
||||
canReport={canReport}
|
||||
externalShareOpen={externalShareOpen}
|
||||
isAdmin={isAdmin}
|
||||
projectInfo={projectInfo}
|
||||
reportOpen={reportOpen}
|
||||
|
@ -372,6 +376,8 @@ const PreviewPresentation = ({
|
|||
onAddToStudioClicked={onAddToStudioClicked}
|
||||
onAddToStudioClosed={onAddToStudioClosed}
|
||||
onCopyProjectLink={onCopyProjectLink}
|
||||
onExternalShareClicked={onExternalShareClicked}
|
||||
onExternalShareClosed={onExternalShareClosed}
|
||||
onReportClicked={onReportClicked}
|
||||
onReportClose={onReportClose}
|
||||
onReportSubmit={onReportSubmit}
|
||||
|
@ -510,6 +516,7 @@ const PreviewPresentation = ({
|
|||
addToStudioOpen={addToStudioOpen}
|
||||
canAddToStudio={canAddToStudio}
|
||||
canReport={canReport}
|
||||
externalShareOpen={externalShareOpen}
|
||||
isAdmin={isAdmin}
|
||||
projectInfo={projectInfo}
|
||||
reportOpen={reportOpen}
|
||||
|
@ -518,6 +525,8 @@ const PreviewPresentation = ({
|
|||
onAddToStudioClicked={onAddToStudioClicked}
|
||||
onAddToStudioClosed={onAddToStudioClosed}
|
||||
onCopyProjectLink={onCopyProjectLink}
|
||||
onExternalShareClicked={onExternalShareClicked}
|
||||
onExternalShareClosed={onExternalShareClosed}
|
||||
onReportClicked={onReportClicked}
|
||||
onReportClose={onReportClose}
|
||||
onReportSubmit={onReportSubmit}
|
||||
|
@ -695,6 +704,8 @@ PreviewPresentation.propTypes = {
|
|||
onCloseAdminPanel: PropTypes.func,
|
||||
onCopyProjectLink: PropTypes.func,
|
||||
onDeleteComment: PropTypes.func,
|
||||
onExternalShareClicked: PropTypes.func,
|
||||
onExternalShareClosed: PropTypes.func,
|
||||
onFavoriteClicked: PropTypes.func,
|
||||
onGreenFlag: PropTypes.func,
|
||||
onLoadMore: PropTypes.func,
|
||||
|
|
|
@ -57,6 +57,8 @@ class Preview extends React.Component {
|
|||
'handleClickLogo',
|
||||
'handleCopyProjectLink',
|
||||
'handleDeleteComment',
|
||||
'handleExternalShareClick',
|
||||
'handleExternalShareClose',
|
||||
'handleToggleStudio',
|
||||
'handleFavoriteToggle',
|
||||
'handleLoadMore',
|
||||
|
@ -109,6 +111,7 @@ class Preview extends React.Component {
|
|||
clientFaved: false,
|
||||
clientLoved: false,
|
||||
extensions: [],
|
||||
externalShareOpen: false,
|
||||
favoriteCount: 0,
|
||||
isProjectLoaded: false,
|
||||
isRemixing: false,
|
||||
|
@ -584,6 +587,12 @@ class Preview extends React.Component {
|
|||
// Also do not include hash or query params
|
||||
copy(`${window.location.origin}${window.location.pathname}`);
|
||||
}
|
||||
handleExternalShareClick () {
|
||||
this.setState({externalShareOpen: true});
|
||||
}
|
||||
handleExternalShareClose () {
|
||||
this.setState({externalShareOpen: false});
|
||||
}
|
||||
initCounts (favorites, loves) {
|
||||
this.setState({
|
||||
favoriteCount: favorites,
|
||||
|
@ -648,6 +657,7 @@ class Preview extends React.Component {
|
|||
comments={this.props.comments}
|
||||
editable={this.props.isEditable}
|
||||
extensions={this.state.extensions}
|
||||
externalShareOpen={this.state.externalShareOpen}
|
||||
faved={this.state.clientFaved}
|
||||
favoriteCount={this.state.favoriteCount}
|
||||
isAdmin={this.props.isAdmin}
|
||||
|
@ -686,6 +696,8 @@ class Preview extends React.Component {
|
|||
onCloseAdminPanel={this.handleCloseAdminPanel}
|
||||
onCopyProjectLink={this.handleCopyProjectLink}
|
||||
onDeleteComment={this.handleDeleteComment}
|
||||
onExternalShareClicked={this.handleExternalShareClick}
|
||||
onExternalShareClosed={this.handleExternalShareClose}
|
||||
onFavoriteClicked={this.handleFavoriteToggle}
|
||||
onGreenFlag={this.handleGreenFlag}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
|
|
@ -6,6 +6,7 @@ const FlexRow = require('../../components/flex-row/flex-row.jsx');
|
|||
|
||||
const Button = require('../../components/forms/button.jsx');
|
||||
const AddToStudioModal = require('./add-to-studio.jsx');
|
||||
const ExternalShareModal = require('../../components/modal/externalshare/container.jsx');
|
||||
const ReportModal = require('../../components/modal/report/modal.jsx');
|
||||
|
||||
require('./subactions.scss');
|
||||
|
@ -54,6 +55,19 @@ const Subactions = props => (
|
|||
>
|
||||
<FormattedMessage id="general.copyLink" />
|
||||
</Button>
|
||||
<Button
|
||||
className="action-button external-share-button"
|
||||
onClick={props.onExternalShareClicked}
|
||||
>
|
||||
<FormattedMessage id="general.externalShare" />
|
||||
</Button>
|
||||
{props.externalShareOpen && (
|
||||
<ExternalShareModal
|
||||
isOpen
|
||||
key="external-share-modal"
|
||||
onRequestClose={props.onExternalShareClosed}
|
||||
/>
|
||||
)}
|
||||
{(props.canReport) &&
|
||||
<React.Fragment>
|
||||
<Button
|
||||
|
@ -82,10 +96,13 @@ Subactions.propTypes = {
|
|||
addToStudioOpen: PropTypes.bool,
|
||||
canAddToStudio: PropTypes.bool,
|
||||
canReport: PropTypes.bool,
|
||||
externalShareOpen: PropTypes.bool,
|
||||
isAdmin: PropTypes.bool,
|
||||
onAddToStudioClicked: PropTypes.func,
|
||||
onAddToStudioClosed: PropTypes.func,
|
||||
onCopyProjectLink: PropTypes.func,
|
||||
onExternalShareClicked: PropTypes.func,
|
||||
onExternalShareClosed: PropTypes.func,
|
||||
onReportClicked: PropTypes.func.isRequired,
|
||||
onReportClose: PropTypes.func.isRequired,
|
||||
onReportSubmit: PropTypes.func.isRequired,
|
||||
|
|
|
@ -87,6 +87,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.external-share-button {
|
||||
&:before {
|
||||
background-image: url("/svgs/project/copy-link-white.svg");
|
||||
}
|
||||
}
|
||||
|
||||
&.report-button {
|
||||
background-color: $ui-coral;
|
||||
|
||||
|
|
Loading…
Reference in a new issue