mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 07:38:07 -05:00
Merge branch 'develop' into responsive-project-page/header
This commit is contained in:
commit
a525e09cf6
11 changed files with 146 additions and 42 deletions
|
@ -100,7 +100,7 @@
|
|||
"redux-thunk": "2.0.1",
|
||||
"sass-lint": "1.5.1",
|
||||
"sass-loader": "6.0.6",
|
||||
"scratch-gui": "latest",
|
||||
"scratch-gui": "develop",
|
||||
"scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master",
|
||||
"slick-carousel": "1.6.0",
|
||||
"source-map-support": "0.3.2",
|
||||
|
|
|
@ -28,6 +28,7 @@ $ui-coral-dark: hsla(350, 100, 60, 1); // #FF3355 More Blocks tertiary
|
|||
$ui-white: hsla(0, 100%, 100%, 1); //#FFF
|
||||
$ui-white-15percent: hsla(0, 100%, 100%, .15); //#FFF
|
||||
$ui-light-primary: hsl(215, 100, 95);
|
||||
$ui-light-primary-transparent: hsla(215, 100, 95, 0);
|
||||
|
||||
$ui-border: hsla(0, 0, 85, 1); //#D9D9D9
|
||||
|
||||
|
|
|
@ -444,18 +444,20 @@ class DemographicsStep extends React.Component {
|
|||
handleChooseGender (name, gender) {
|
||||
this.setState({otherDisabled: gender !== 'other'});
|
||||
}
|
||||
handleValidSubmit (formData, reset, invalidate) {
|
||||
handleValidSubmit (formData) {
|
||||
return this.props.onNextStep(formData);
|
||||
}
|
||||
isValidBirthdate (year, month) {
|
||||
const birthdate = new Date(
|
||||
formData.user.birth.year,
|
||||
formData.user.birth.month - 1,
|
||||
year,
|
||||
month - 1,
|
||||
1
|
||||
);
|
||||
if (((Date.now() - birthdate) / (24 * 3600 * 1000 * 365.25)) < this.props.birthOffset) {
|
||||
return invalidate({
|
||||
'user.birth.year': this.props.intl.formatMessage({id: 'teacherRegistration.validationAge'})
|
||||
});
|
||||
}
|
||||
return this.props.onNextStep(formData);
|
||||
return (((Date.now() - birthdate) / (24 * 3600 * 1000 * 365.25)) >= this.props.birthOffset);
|
||||
}
|
||||
birthDateValidator (values) {
|
||||
const isValid = this.isValidBirthdate(values['user.birth.year'], values['user.birth.month']);
|
||||
return isValid ? true : this.props.intl.formatMessage({id: 'teacherRegistration.validationAge'});
|
||||
}
|
||||
render () {
|
||||
const countryOptions = getCountryOptions(this.props.intl, DEFAULT_COUNTRY);
|
||||
|
@ -485,6 +487,9 @@ class DemographicsStep extends React.Component {
|
|||
}
|
||||
name="user.birth.month"
|
||||
options={this.getMonthOptions()}
|
||||
validations={{
|
||||
birthDateVal: values => this.birthDateValidator(values)
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
required
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
float: left;
|
||||
max-width: 164px;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
|
||||
.thumbnail-creator a {
|
||||
color: $type-gray;
|
||||
|
|
|
@ -35,14 +35,6 @@ const Jobs = () => (
|
|||
MIT Media Lab, Cambridge, MA
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://scratch.mit.edu/jobs/moderator">
|
||||
Community Moderator
|
||||
</a>
|
||||
<span>
|
||||
Remote
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
position: absolute;
|
||||
bottom: 0;
|
||||
background: linear-gradient(
|
||||
transparent,
|
||||
$ui-light-primary-transparent,
|
||||
$ui-light-primary
|
||||
);
|
||||
width: 100%;
|
||||
|
@ -188,7 +188,7 @@
|
|||
margin-bottom: 24px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
|
@ -211,4 +211,3 @@
|
|||
margin-right: -50%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
font-size: .875rem;
|
||||
justify-content: center;
|
||||
flex-flow: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.extension-status {
|
||||
|
|
|
@ -2,6 +2,7 @@ const FormattedDate = require('react-intl').FormattedDate;
|
|||
const injectIntl = require('react-intl').injectIntl;
|
||||
const PropTypes = require('prop-types');
|
||||
const intlShape = require('react-intl').intlShape;
|
||||
const MediaQuery = require('react-responsive').default;
|
||||
const React = require('react');
|
||||
const Formsy = require('formsy-react').default;
|
||||
const classNames = require('classnames');
|
||||
|
@ -28,6 +29,8 @@ const ExtensionChip = require('./extension-chip.jsx');
|
|||
const projectShape = require('./projectshape.jsx').projectShape;
|
||||
require('./preview.scss');
|
||||
|
||||
const frameless = require('../../lib/frameless');
|
||||
|
||||
// disable enter key submission on formsy input fields; otherwise formsy thinks
|
||||
// we meant to trigger the "See inside" button. Instead, treat these keypresses
|
||||
// as a blur, which will trigger a save.
|
||||
|
@ -94,7 +97,6 @@ const PreviewPresentation = ({
|
|||
</a>
|
||||
<div className="title">
|
||||
{editable ?
|
||||
|
||||
<InplaceInput
|
||||
className="project-title"
|
||||
handleUpdate={onUpdate}
|
||||
|
@ -155,6 +157,21 @@ const PreviewPresentation = ({
|
|||
<RemixCredit projectInfo={parentInfo} />
|
||||
<RemixCredit projectInfo={originalInfo} />
|
||||
{/* eslint-disable max-len */}
|
||||
<MediaQuery maxWidth={frameless.tablet - 1}>
|
||||
<FlexRow className="preview-row">
|
||||
<FlexRow className="extension-list">
|
||||
{extensions && extensions.map(extension => (
|
||||
<ExtensionChip
|
||||
extensionL10n={extension.l10nId}
|
||||
extensionName={extension.name}
|
||||
hasStatus={extension.hasStatus}
|
||||
iconURI={extension.icon && `/svgs/project/${extension.icon}`}
|
||||
key={extension.name || extension.l10nId}
|
||||
/>
|
||||
))}
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
</MediaQuery>
|
||||
<FlexRow className="description-block">
|
||||
<div className="project-textlabel">
|
||||
Instructions
|
||||
|
@ -309,19 +326,21 @@ const PreviewPresentation = ({
|
|||
</FlexRow>
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
<FlexRow className="preview-row">
|
||||
<FlexRow className="extension-list">
|
||||
{extensions && extensions.map(extension => (
|
||||
<ExtensionChip
|
||||
extensionL10n={extension.l10nId}
|
||||
extensionName={extension.name}
|
||||
hasStatus={extension.hasStatus}
|
||||
iconURI={extension.icon && `/svgs/project/${extension.icon}`}
|
||||
key={extension.name || extension.l10nId}
|
||||
/>
|
||||
))}
|
||||
<MediaQuery minWidth={frameless.tablet}>
|
||||
<FlexRow className="preview-row">
|
||||
<FlexRow className="extension-list">
|
||||
{extensions && extensions.map(extension => (
|
||||
<ExtensionChip
|
||||
extensionL10n={extension.l10nId}
|
||||
extensionName={extension.name}
|
||||
hasStatus={extension.hasStatus}
|
||||
iconURI={extension.icon && `/svgs/project/${extension.icon}`}
|
||||
key={extension.name || extension.l10nId}
|
||||
/>
|
||||
))}
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
</FlexRow>
|
||||
</MediaQuery>
|
||||
</div>
|
||||
<div className="project-lower-container">
|
||||
<div className="inner">
|
||||
|
|
|
@ -23,6 +23,8 @@ const sessionActions = require('../../redux/session.js');
|
|||
const navigationActions = require('../../redux/navigation.js');
|
||||
const previewActions = require('../../redux/preview.js');
|
||||
|
||||
const frameless = require('../../lib/frameless');
|
||||
|
||||
const GUI = require('scratch-gui');
|
||||
const IntlGUI = injectIntl(GUI.default);
|
||||
|
||||
|
@ -46,7 +48,8 @@ class Preview extends React.Component {
|
|||
'handleUpdate',
|
||||
'initCounts',
|
||||
'pushHistory',
|
||||
'renderLogin'
|
||||
'renderLogin',
|
||||
'setScreenFromOrientation'
|
||||
]);
|
||||
const pathname = window.location.pathname.toLowerCase();
|
||||
const parts = pathname.split('/').filter(Boolean);
|
||||
|
@ -63,6 +66,8 @@ class Preview extends React.Component {
|
|||
};
|
||||
this.getExtensions(this.state.projectId);
|
||||
this.addEventListeners();
|
||||
/* In the beginning, if user is on mobile and landscape, go to fullscreen */
|
||||
this.setScreenFromOrientation();
|
||||
}
|
||||
componentDidUpdate (prevProps) {
|
||||
if (this.props.sessionStatus !== prevProps.sessionStatus &&
|
||||
|
@ -106,9 +111,26 @@ class Preview extends React.Component {
|
|||
}
|
||||
addEventListeners () {
|
||||
window.addEventListener('popstate', this.handlePopState);
|
||||
window.addEventListener('orientationchange', this.setScreenFromOrientation);
|
||||
}
|
||||
removeEventListeners () {
|
||||
window.removeEventListener('popstate', this.handlePopState);
|
||||
window.removeEventListener('orientationchange', this.setScreenFromOrientation);
|
||||
}
|
||||
setScreenFromOrientation () {
|
||||
/*
|
||||
* If the user is on a mobile device, switching to
|
||||
* landscape format should make the fullscreen mode active
|
||||
*/
|
||||
const isMobileDevice = screen.height <= frameless.mobile || screen.width <= frameless.mobile;
|
||||
if (this.props.playerMode && isMobileDevice) {
|
||||
const isLandscape = screen.height < screen.width;
|
||||
if (isLandscape) {
|
||||
this.props.setFullScreen(true);
|
||||
} else {
|
||||
this.props.setFullScreen(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
getExtensions (projectId) {
|
||||
storage
|
||||
|
@ -246,6 +268,9 @@ class Preview extends React.Component {
|
|||
handleSeeInside () {
|
||||
this.props.setPlayer(false);
|
||||
}
|
||||
handleShare () {
|
||||
// This is just a placeholder, but enables the button in the editor
|
||||
}
|
||||
handleUpdate (jsonData) {
|
||||
this.props.updateProject(
|
||||
this.props.projectInfo.id,
|
||||
|
@ -338,6 +363,7 @@ class Preview extends React.Component {
|
|||
renderLogin={this.renderLogin}
|
||||
onLogOut={this.props.handleLogOut}
|
||||
onOpenRegistration={this.props.handleOpenRegistration}
|
||||
onShare={this.handleShare}
|
||||
onToggleLoginOpen={this.props.handleToggleLoginOpen}
|
||||
onUpdateProjectTitle={this.handleUpdateProjectTitle}
|
||||
/>
|
||||
|
|
|
@ -157,7 +157,23 @@ $medium-and-small: "screen and (max-width : #{$tablet}-1)";
|
|||
}
|
||||
|
||||
.comments-container {
|
||||
width: 65%;
|
||||
padding-right: 1.5rem;
|
||||
min-width: 65%;
|
||||
max-width: 100%;
|
||||
flex: 1;
|
||||
|
||||
@media #{$medium-and-small} {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comment, .comment-top-row, .comment-bottom-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.comment-bubble {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.remix-button,
|
||||
|
@ -210,6 +226,14 @@ $medium-and-small: "screen and (max-width : #{$tablet}-1)";
|
|||
.guiPlayer {
|
||||
display: inline-block;
|
||||
width: $player-width;
|
||||
|
||||
@media #{$small} {
|
||||
width: 100%;
|
||||
|
||||
.stage-wrapper {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.project-notes {
|
||||
|
@ -219,6 +243,12 @@ $medium-and-small: "screen and (max-width : #{$tablet}-1)";
|
|||
flex: 1;
|
||||
flex-flow: column;
|
||||
|
||||
@media #{$medium-and-small} {
|
||||
margin-top: 1rem;
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .description-block:first-child {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
@ -525,6 +555,12 @@ $medium-and-small: "screen and (max-width : #{$tablet}-1)";
|
|||
|
||||
.extension-list {
|
||||
justify-content: flex-start;
|
||||
flex-direction: row;
|
||||
|
||||
@media #{$medium-and-small} {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.remix-list,
|
||||
|
@ -546,6 +582,21 @@ $medium-and-small: "screen and (max-width : #{$tablet}-1)";
|
|||
.thumbnail-column {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
|
||||
/* TODO: the following can be transferred to
|
||||
src/components/thumbnailcolumn/thumbnailcolumn.scss
|
||||
after testing */
|
||||
@media #{$medium-and-small} {
|
||||
flex-direction: row;
|
||||
|
||||
.thumbnail {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media #{$medium-and-small} {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,12 +57,21 @@ class Search extends React.Component {
|
|||
|
||||
}
|
||||
componentDidMount () {
|
||||
const query = window.location.search;
|
||||
const q = query.lastIndexOf('q=');
|
||||
let term = '';
|
||||
if (q !== -1) {
|
||||
term = query.substring(q + 2, query.length).toLowerCase();
|
||||
}
|
||||
const query = decodeURIComponent(window.location.search);
|
||||
let term = query;
|
||||
|
||||
const stripQueryValue = function (queryTerm) {
|
||||
const queryIndex = query.indexOf('q=');
|
||||
if (queryIndex !== -1) {
|
||||
queryTerm = query.substring(queryIndex + 2, query.length).toLowerCase();
|
||||
}
|
||||
return queryTerm;
|
||||
};
|
||||
// Strip off the initial "?q="
|
||||
term = stripQueryValue(term);
|
||||
// Strip off user entered "?q="
|
||||
term = stripQueryValue(term);
|
||||
|
||||
while (term.indexOf('/') > -1) {
|
||||
term = term.substring(0, term.indexOf('/'));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue