Merge pull request #2548 from LLK/release/3.0

[Master] Release Scratch 3.0!
This commit is contained in:
Ray Schamp 2019-01-02 07:30:19 -05:00 committed by GitHub
commit cc91b96167
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
237 changed files with 10352 additions and 6393 deletions

View file

@ -43,6 +43,11 @@ env:
- PROJECT_HOST_VAR=PROJECT_HOST_$TRAVIS_BRANCH - PROJECT_HOST_VAR=PROJECT_HOST_$TRAVIS_BRANCH
- PROJECT_HOST=${!PROJECT_HOST_VAR} - PROJECT_HOST=${!PROJECT_HOST_VAR}
- PROJECT_HOST=${PROJECT_HOST:-$PROJECT_HOST_STAGING} - PROJECT_HOST=${PROJECT_HOST:-$PROJECT_HOST_STAGING}
- STATIC_HOST_master=https://cdn2.scratch.mit.edu
- STATIC_HOST_STAGING=https://cdn.scratch.ly
- STATIC_HOST_VAR=STATIC_HOST_$TRAVIS_BRANCH
- STATIC_HOST=${!STATIC_HOST_VAR}
- STATIC_HOST=${STATIC_HOST:-$STATIC_HOST_STAGING}
- PATH=$PATH:$PWD/test/integration/node_modules/chromedriver/bin - PATH=$PATH:$PWD/test/integration/node_modules/chromedriver/bin
- AWS_ACCESS_KEY_ID=$EB_AWS_ACCESS_KEY_ID - AWS_ACCESS_KEY_ID=$EB_AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY=$EB_AWS_SECRET_ACCESS_KEY - AWS_SECRET_ACCESS_KEY=$EB_AWS_SECRET_ACCESS_KEY
@ -57,6 +62,7 @@ env:
- FASTLY_SERVICE_ID=${!FASTLY_SERVICE_ID_VAR} - FASTLY_SERVICE_ID=${!FASTLY_SERVICE_ID_VAR}
- FASTLY_SERVICE_ID=${FASTLY_SERVICE_ID:-$FASTLY_SERVICE_ID_STAGING} - FASTLY_SERVICE_ID=${FASTLY_SERVICE_ID:-$FASTLY_SERVICE_ID_STAGING}
- GA_TRACKER_master=UA-30688952-1 - GA_TRACKER_master=UA-30688952-1
- GA_TRACKER_STAGING=UA-30688952-7
- GA_TRACKER_VAR=GA_TRACKER_$TRAVIS_BRANCH - GA_TRACKER_VAR=GA_TRACKER_$TRAVIS_BRANCH
- GA_TRACKER=${!GA_TRACKER_VAR} - GA_TRACKER=${!GA_TRACKER_VAR}
- GA_TRACKER=${GA_TRACKER:-$GA_TRACKER_STAGING} - GA_TRACKER=${GA_TRACKER:-$GA_TRACKER_STAGING}
@ -71,11 +77,17 @@ env:
- S3_BUCKET_NAME=${!S3_BUCKET_NAME_VAR} - S3_BUCKET_NAME=${!S3_BUCKET_NAME_VAR}
- S3_BUCKET_NAME=${S3_BUCKET_NAME:-$S3_BUCKET_NAME_STAGING} - S3_BUCKET_NAME=${S3_BUCKET_NAME:-$S3_BUCKET_NAME_STAGING}
- S3_LOCAL_DIR=build - S3_LOCAL_DIR=build
- SENTRY_DSN_master=https://6cf7e15e06b24ba48b727910bd9e6d9e@app.getsentry.com/54913 - SENTRY_DSN_master=https://ebc2f8a6bc7b44ca8fd902fd4f16b3d7@sentry.io/1357122
- SENTRY_DSN_STAGING=https://7e69dd3d620e434490f07ef0e60613f9@app.getsentry.com/58289 - SENTRY_DSN_STAGING=https://c01014988b0a4f44bbefdf235623c456@sentry.io/1357982
- SENTRY_DSN_VAR=SENTRY_DSN_$TRAVIS_BRANCH - SENTRY_DSN_VAR=SENTRY_DSN_$TRAVIS_BRANCH
- SENTRY_DSN=${!SENTRY_DSN_VAR} - SENTRY_DSN=${!SENTRY_DSN_VAR}
- SENTRY_DSN=${SENTRY_DSN:-$SENTRY_DSN_STAGING} - SENTRY_DSN=${SENTRY_DSN:-$SENTRY_DSN_STAGING}
- SENTRY_ORG=scratch-foundation
- SENTRY_PROJECT_master=scratch-30-production
- SENTRY_PROJECT_STAGING=scratch-30-staging
- SENTRY_PROJECT_VAR=SENTRY_PROJECT_$TRAVIS_BRANCH
- SENTRY_PROJECT=${!SENTRY_PROJECT_VAR}
- SENTRY_PROJECT=${SENTRY_PROJECT:-$SENTRY_PROJECT_STAGING}
- SKIP_CLEANUP=true - SKIP_CLEANUP=true
- NODE_ENV=production - NODE_ENV=production
- WWW_VERSION=${TRAVIS_COMMIT:0:5} - WWW_VERSION=${TRAVIS_COMMIT:0:5}

View file

@ -20,12 +20,6 @@ source_file = src/views/wedo2/l10n.json
source_lang = en source_lang = en
type = KEYVALUEJSON type = KEYVALUEJSON
[scratch-website.cards-l10njson]
file_filter = localizations/cards/<lang>.json
source_file = src/views/cards/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.teacherregistration-l10njson] [scratch-website.teacherregistration-l10njson]
file_filter = localizations/teacherregistration/<lang>.json file_filter = localizations/teacherregistration/<lang>.json
source_file = src/views/teacherregistration/l10n.json source_file = src/views/teacherregistration/l10n.json
@ -86,12 +80,6 @@ source_file = src/views/splash/l10n.json
source_lang = en source_lang = en
type = KEYVALUEJSON type = KEYVALUEJSON
[scratch-website.microworlds-homepage-l10njson]
file_filter = localizations/microworlds-homepage/<lang>.json
source_file = src/views/microworldshomepage/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.conference-index-2017-l10njson] [scratch-website.conference-index-2017-l10njson]
file_filter = localizations/conference-index-2017/<lang>.json file_filter = localizations/conference-index-2017/<lang>.json
source_file = src/views/conference/2017/index/l10n.json source_file = src/views/conference/2017/index/l10n.json
@ -172,3 +160,18 @@ type = KEYVALUEJSON
source_file = src/views/wedo2-legacy/l10n.json source_file = src/views/wedo2-legacy/l10n.json
source_lang = en source_lang = en
type = KEYVALUEJSON type = KEYVALUEJSON
[scratch-website.parents-l10njson]
source_file = src/views/parents/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.scratch_14-l10njson]
source_file = src/views/scratch_1.4/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.ideas-l10njson]
source_file = src/views/ideas/l10n.json
source_lang = en
type = KEYVALUEJSON

View file

@ -1,6 +1,5 @@
ESLINT=./node_modules/.bin/eslint ESLINT=./node_modules/.bin/eslint
NODE= NODE_OPTIONS=--max_old_space_size=8000 node NODE= NODE_OPTIONS=--max_old_space_size=8000 node
SASSLINT=./node_modules/.bin/sass-lint -v
SCRATCH_DOCKER_CONFIG=./node_modules/.bin/docker_config.sh SCRATCH_DOCKER_CONFIG=./node_modules/.bin/docker_config.sh
S3CMD=s3cmd sync -P --delete-removed --add-header=Cache-Control:no-cache,public,max-age=3600 S3CMD=s3cmd sync -P --delete-removed --add-header=Cache-Control:no-cache,public,max-age=3600
TAP=./node_modules/.bin/tap TAP=./node_modules/.bin/tap
@ -70,8 +69,6 @@ test:
lint: lint:
$(ESLINT) . --ext .js,.jsx,.json $(ESLINT) . --ext .js,.jsx,.json
$(SASSLINT) ./src/*.scss
$(SASSLINT) ./src/**/*.scss
unit: unit:
$(TAP) ./test/unit/*.js $(TAP) ./test/unit/*.js

View file

@ -4,7 +4,7 @@
[![Build Status](https://travis-ci.org/LLK/scratch-www.svg)](https://travis-ci.org/LLK/scratch-www) [![Build Status](https://travis-ci.org/LLK/scratch-www.svg)](https://travis-ci.org/LLK/scratch-www)
[![Coverage Status](https://coveralls.io/repos/github/LLK/scratch-www/badge.svg?branch=develop)](https://coveralls.io/github/LLK/scratch-www?branch=develop) [![Coverage Status](https://coveralls.io/repos/github/LLK/scratch-www/badge.svg?branch=develop)](https://coveralls.io/github/LLK/scratch-www?branch=develop)
[![dependencies Status](https://david-dm.org/llk/scratch-www/status.svg)](https://david-dm.org/llk/scratch-www) [![dependencies Status](https://david-dm.org/llk/scratch-www/status.svg)](https://david-dm.org/llk/scratch-www)
[![devDependencies Status](https://david-dm.org/llk/scratch-www/dev-status.svg)](https://david-dm.org/llk/scratch-www?type=dev) [![devDependencies Status](https://david-dm.org/llk/scratch-www/dev-status.svg)](https://david-dm.org/llk/scratch-www?type=dev) [![Greenkeeper badge](https://badges.greenkeeper.io/LLK/scratch-www.svg)](https://greenkeeper.io/)
### Where am I? ### Where am I?
Physically? No idea. Physically? No idea.

View file

@ -34,7 +34,7 @@
*/ */
var async = require('async'); var async = require('async');
var fs = require('fs'); var fs = require('fs');
var languages = require('../languages.json'); const languages = require('scratch-l10n').default;
var localizedUrls = require('./lib/localized-urls'); var localizedUrls = require('./lib/localized-urls');
var merge = require('lodash.merge'); var merge = require('lodash.merge');
var defaults = require('lodash.defaults'); var defaults = require('lodash.defaults');

View file

@ -1,7 +1,7 @@
var async = require('async'); var async = require('async');
var defaults = require('lodash.defaults'); var defaults = require('lodash.defaults');
var fastlyConfig = require('./lib/fastly-config-methods'); var fastlyConfig = require('./lib/fastly-config-methods');
const languages = require('../languages.json'); const languages = require('scratch-l10n').default;
var routeJson = require('../src/routes.json'); var routeJson = require('../src/routes.json');
@ -171,6 +171,98 @@ async.auto({
if (err) return cb(err); if (err) return cb(err);
cb(null, headers); cb(null, headers);
}); });
}],
tipbarRedirectHeaders: ['version', function (cb, results) {
async.auto({
requestCondition: function (cb2) {
var condition = {
name: 'routes/?tip_bar= (request)',
statement: 'req.url ~ "\\?tip_bar="',
type: 'REQUEST',
priority: 10
};
fastly.setCondition(results.version, condition, cb2);
},
responseCondition: function (cb2) {
var condition = {
name: 'routes/?tip_bar= (response)',
statement: 'req.url ~ "\\?tip_bar="',
type: 'RESPONSE',
priority: 10
};
fastly.setCondition(results.version, condition, cb2);
},
responseObject: ['requestCondition', function (cb2, redirectResults) {
var responseObject = {
name: 'redirects/?tip_bar=',
status: 301,
response: 'Moved Permanently',
request_condition: redirectResults.requestCondition.name
};
fastly.setResponseObject(results.version, responseObject, cb2);
}],
redirectHeader: ['responseCondition', function (cb2, redirectResults) {
var header = {
name: 'redirects/?tip_bar=',
action: 'set',
ignore_if_set: 0,
type: 'RESPONSE',
dst: 'http.Location',
src: 'regsub(req.url, "tip_bar=", "tutorial=")',
response_condition: redirectResults.responseCondition.name
};
fastly.setFastlyHeader(results.version, header, cb2);
}]
}, function (err, redirectResults) {
if (err) return cb(err);
cb(null, redirectResults);
});
}],
embedRedirectHeaders: ['version', function (cb, results) {
async.auto({
requestCondition: function (cb2) {
var condition = {
name: 'routes/projects/embed (request)',
statement: 'req.url ~ "^/projects/embed/(\\d+)"',
type: 'REQUEST',
priority: 10
};
fastly.setCondition(results.version, condition, cb2);
},
responseCondition: function (cb2) {
var condition = {
name: 'routes/projects/embed (response)',
statement: 'req.url ~ "^/projects/embed/(\\d+)"',
type: 'RESPONSE',
priority: 10
};
fastly.setCondition(results.version, condition, cb2);
},
responseObject: ['requestCondition', function (cb2, redirectResults) {
var responseObject = {
name: 'redirects/projects/embed',
status: 301,
response: 'Moved Permanently',
request_condition: redirectResults.requestCondition.name
};
fastly.setResponseObject(results.version, responseObject, cb2);
}],
redirectHeader: ['responseCondition', function (cb2, redirectResults) {
var header = {
name: 'redirects/projects/embed',
action: 'set',
ignore_if_set: 0,
type: 'RESPONSE',
dst: 'http.Location',
src: '"/projects/" + re.group.1 + "/embed"',
response_condition: redirectResults.responseCondition.name
};
fastly.setFastlyHeader(results.version, header, cb2);
}]
}, function (err, redirectResults) {
if (err) return cb(err);
cb(null, redirectResults);
});
}] }]
}, function (err, results) { }, function (err, results) {
if (err) throw new Error(err); if (err) throw new Error(err);

View file

@ -1,51 +0,0 @@
#!/usr/bin/env node
/*
Generate language json files corresponding to l10n files to import from
pootle into transifex.
For example, extract the strings corresponding to splash ids from pootle.
For each language, in localizations/splash create
fr.json =>
{
'splash.welcome' : 'Bienvenue',
...
}
etc.
*/
var fs = require('fs');
var path = require('path');
var routes = require('../src/routes.json');
var languages = require('../languages.json');
var localeCompare = require('./lib/locale-compare');
var outputDir = path.resolve(__dirname, '../localizations');
try {
fs.accessSync(outputDir, fs.F_OK);
} catch (err) {
// Doesn't exist - create it.
fs.mkdirSync(outputDir);
}
// general is a special case, do it first
var l10n = path.resolve(__dirname, '../src/l10n.json');
localeCompare.writeTranslations('general', l10n, languages);
for (var v in routes) {
if (typeof routes[v].redirect !== 'undefined') {
continue;
}
var subdir = routes[v].view.split('/');
subdir.pop();
l10n = path.resolve(__dirname, '../src/views/' + subdir.join('/') + '/l10n.json');
var name = routes[v].name;
try {
// only import if there is an l10n file
fs.accessSync(l10n);
} catch (err) {
// skip views without l10n files
process.stdout.write(`Skipping ${name}, no l10n\n`);
continue;
}
localeCompare.writeTranslations(name, l10n, languages);
}

View file

@ -1,76 +0,0 @@
{
"ab": "Аҧсшәа",
"ar": "العربية",
"an": "Aragonés",
"ast": "Asturianu",
"id": "Bahasa Indonesia",
"ms": "Bahasa Melayu",
"be": "Беларуская",
"bg": "Български",
"ca": "Català",
"cs": "Česky",
"cy": "Cymraeg",
"da": "Dansk",
"de": "Deutsch",
"yum": "Edible Scratch",
"et": "Eesti",
"el": "Ελληνικά",
"en": "English",
"eo": "Esperanto",
"es": "Español",
"eu": "Euskara",
"fa": "فارسی",
"fr": "Français",
"fur": "Furlan",
"ga": "Gaeilge",
"gd": "Gàidhlig",
"gl": "Galego",
"ko": "한국어",
"hy": "Հայերեն",
"he": "עִבְרִית",
"hi": "हिन्दी",
"hr": "Hrvatski",
"zu": "isiZulu",
"is": "Íslenska",
"it": "Italiano",
"kn": "ಭಾಷೆ-ಹೆಸರು",
"kk": "Қазақша",
"rw": "Kinyarwanda",
"ht": "Kreyòl",
"ku": "Kurdî",
"la": "Latina",
"lv": "Latviešu",
"lt": "Lietuvių",
"mk": "Македонски",
"hu": "Magyar",
"ml": "മലയാളം",
"mt": "Malti",
"cat": "Meow",
"mr": "मराठी",
"mn": "Монгол хэл",
"my": "မြန်မာဘာသာ",
"nl": "Nederlands",
"ja": "日本語",
"nb": "Norsk Bokmål",
"nn": "Norsk Nynorsk",
"uz": "Oʻzbekcha",
"th": "ไทย",
"pl": "Polski",
"pt": "Português",
"pt-br": "Português Brasileiro",
"ro": "Română",
"ru": "Русский",
"sc": "Sardu",
"sq": "Shqip",
"sk": "Slovenčina",
"sl": "Slovenščina",
"sr": "Српски",
"fi": "Suomi",
"sv": "Svenska",
"te": "తెలుగు",
"vi": "Tiếng Việt",
"tr": "Türkçe",
"uk": "Українська",
"zh-cn": "简体中文",
"zh-tw": "繁體中文"
}

View file

@ -24,20 +24,21 @@
}, },
"homepage": "https://github.com/llk/scratch-www#readme", "homepage": "https://github.com/llk/scratch-www#readme",
"dependencies": { "dependencies": {
"@sentry/browser": "4.4.2",
"bunyan": "1.7.1", "bunyan": "1.7.1",
"clipboard-copy": "2.0.1",
"compression": "1.6.1", "compression": "1.6.1",
"express": "4.16.1", "express": "4.16.1",
"express-http-proxy": "1.1.0", "express-http-proxy": "1.1.0",
"lodash.defaults": "4.0.1", "lodash.defaults": "4.0.1",
"newrelic": "1.25.4", "newrelic": "1.25.4",
"raven": "0.10.0", "react-helmet": "5.2.0",
"scratch-docker": "^1.0.2", "scratch-docker": "^1.0.2",
"scratch-parser": "^4.2.0", "scratch-parser": "^4.2.0",
"scratch-storage": "^0.5.1" "scratch-storage": "^0.5.1"
}, },
"devDependencies": { "devDependencies": {
"ajv": "6.4.0", "ajv": "6.4.0",
"approximate-number": "2.0.0",
"async": "1.5.2", "async": "1.5.2",
"autoprefixer": "6.3.6", "autoprefixer": "6.3.6",
"babel-cli": "6.26.0", "babel-cli": "6.26.0",
@ -47,6 +48,7 @@
"babel-plugin-transform-object-rest-spread": "6.26.0", "babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-preset-es2015": "6.22.0", "babel-preset-es2015": "6.22.0",
"babel-preset-react": "6.22.0", "babel-preset-react": "6.22.0",
"bowser": "1.9.4",
"cheerio": "1.0.0-rc.2", "cheerio": "1.0.0-rc.2",
"classnames": "2.2.5", "classnames": "2.2.5",
"cookie": "0.2.2", "cookie": "0.2.2",
@ -85,7 +87,6 @@
"po2icu": "0.0.2", "po2icu": "0.0.2",
"postcss-loader": "2.0.10", "postcss-loader": "2.0.10",
"prop-types": "15.6.0", "prop-types": "15.6.0",
"raven-js": "3.0.4",
"react": "16.2.0", "react": "16.2.0",
"react-dom": "16.2.0", "react-dom": "16.2.0",
"react-intl": "2.4.0", "react-intl": "2.4.0",
@ -98,9 +99,9 @@
"react-telephone-input": "4.3.4", "react-telephone-input": "4.3.4",
"redux": "3.5.2", "redux": "3.5.2",
"redux-thunk": "2.0.1", "redux-thunk": "2.0.1",
"sass-lint": "1.5.1",
"sass-loader": "6.0.6", "sass-loader": "6.0.6",
"scratch-gui": "latest", "scratch-gui": "0.1.0-prerelease.20181227160059",
"scratch-l10n": "latest",
"scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master", "scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master",
"slick-carousel": "1.6.0", "slick-carousel": "1.6.0",
"source-map-support": "0.3.2", "source-map-support": "0.3.2",

View file

@ -5,9 +5,16 @@ $ui-blue-10percent: hsla(215, 100, 65, .1);
$ui-blue-25percent: hsla(215, 100, 65, .25); $ui-blue-25percent: hsla(215, 100, 65, .25);
$ui-orange: hsla(38, 100, 55, 1); // #FFAB19 Control Primary $ui-orange: hsla(38, 100, 55, 1); // #FFAB19 Control Primary
$ui-orange-high-contrast: hsla(30, 100, 55, 1); // #FFAB19 Control Primary
$ui-orange-10percent: hsla(35, 90, 55, .1); $ui-orange-10percent: hsla(35, 90, 55, .1);
$ui-orange-25percent: hsla(35, 90, 55, .25); $ui-orange-25percent: hsla(35, 90, 55, .25);
$ui-dark-orange: hsla(30, 100, 55, 1); // ##FF8C1A Variables Primary
$ui-red: hsla(20, 100%, 55%, 1); /* #FF661A */
$ui-red-25percent: hsla(20, 100%, 55%, .25);
$ui-green-35percent: rgba(126, 225, 195, .35);
$ui-light-gray: hsla(0, 0, 98, 1); //#FAFAFA $ui-light-gray: hsla(0, 0, 98, 1); //#FAFAFA
$ui-gray: hsla(0, 0, 95, 1); //#F2F2F2 $ui-gray: hsla(0, 0, 95, 1); //#F2F2F2
$ui-dark-gray: hsla(0, 0, 70, 1); //#B3B3B3 $ui-dark-gray: hsla(0, 0, 70, 1); //#B3B3B3
@ -40,6 +47,7 @@ $ui-light-mint: hsl(163, 53, 67);
$active-gray: hsla(0, 0, 0, .1); $active-gray: hsla(0, 0, 0, .1);
$active-dark-gray: hsla(0, 0, 0, .2); $active-dark-gray: hsla(0, 0, 0, .2);
$box-shadow-gray: hsla(0, 0, 0, .25); $box-shadow-gray: hsla(0, 0, 0, .25);
$box-shadow-light-gray: hsla(0, 0, 0, .15);
$overlay-gray: hsla(0, 0, 0, .75); $overlay-gray: hsla(0, 0, 0, .75);
$transparent-light-blue: rgba(229, 240, 254, 0); $transparent-light-blue: rgba(229, 240, 254, 0);

View file

@ -1,100 +1,49 @@
const bindAll = require('lodash.bindall'); const classNames = require('classnames');
const connect = require('react-redux').connect;
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const React = require('react'); const React = require('react');
const Button = require('../forms/button.jsx');
require('./adminpanel.scss'); require('./adminpanel.scss');
class AdminPanel extends React.Component { const AdminPanel = ({
constructor (props) { className,
super(props); children,
bindAll(this, [ isOpen,
'handleToggleVisibility' onOpen,
]); onClose
this.state = { }) => (
showPanel: false <div className={classNames('admin-panel', className, {hidden: !isOpen})}>
}; {isOpen ? (
} <React.Fragment>
handleToggleVisibility (e) {
e.preventDefault();
this.setState({showPanel: !this.state.showPanel});
}
render () {
if (!this.props.isAdmin) return false;
if (this.state.showPanel) {
return (
<div
className="visible"
id="admin-panel"
>
<span
className="toggle"
onClick={this.handleToggleVisibility}
>
x
</span>
<div className="admin-header">
<h3>Admin Panel</h3>
</div>
<div className="admin-content">
<dl>
{this.props.children}
<dt>Page Cache</dt>
<dd>
<ul className="cache-list">
<li>
<form
action="/scratch_admin/page/clear-anon-cache/"
method="post"
>
<input
name="path"
type="hidden"
value="/"
/>
<div className="button-row">
<span>For anonymous users:</span>
<Button type="submit">
<span>Clear</span>
</Button>
</div>
</form>
</li>
</ul>
</dd>
</dl>
</div>
</div>
);
}
return (
<div
className="hidden"
id="admin-panel"
>
<span <span
className="toggle" className="toggle"
onClick={this.handleToggleVisibility} onClick={onClose}
> >
&gt; x
</span> </span>
</div> <div className="admin-header">
); <h3>Admin Panel</h3>
} </div>
} <div className="admin-content">
{children}
</div>
</React.Fragment>
) : (
<span
className="toggle"
onClick={onOpen}
>
&gt;
</span>
)}
</div>
);
AdminPanel.propTypes = { AdminPanel.propTypes = {
children: PropTypes.node, children: PropTypes.node,
isAdmin: PropTypes.bool className: PropTypes.string,
isOpen: PropTypes.bool,
onClose: PropTypes.func,
onOpen: PropTypes.func
}; };
const mapStateToProps = state => ({ module.exports = AdminPanel;
isAdmin: state.permissions.admin
});
const ConnectedAdminPanel = connect(mapStateToProps)(AdminPanel);
module.exports = ConnectedAdminPanel;

View file

@ -1,6 +1,6 @@
@import "../../colors"; @import "../../colors";
#admin-panel { .admin-panel {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
@ -9,16 +9,11 @@
box-shadow: 0 2px 5px $box-shadow-gray; box-shadow: 0 2px 5px $box-shadow-gray;
background-color: $ui-gray; background-color: $ui-gray;
padding: 1rem; padding: 1rem;
width: 230px;
height: 100%; height: 100%;
overflow: scroll; overflow: scroll;
text-shadow: none; text-shadow: none;
&.visible {
width: 20%;
min-width: 180px;
max-width: 230px;
}
&.hidden { &.hidden {
width: 10px; width: 10px;
} }
@ -28,33 +23,6 @@
cursor: pointer; cursor: pointer;
} }
.admin-content {
dl {
list-style: none;
dt {
margin: 2rem 0 1rem 0;
border-bottom: 1px solid $ui-dark-gray;
font-size: large;
font-weight: 700;
}
dd {
margin-left: 0;
}
}
ul {
padding: 0;
li {
margin: 0;
list-style: none;
}
}
}
.button-row { .button-row {
display: flex; display: flex;
font-size: small; font-size: small;

View file

@ -20,6 +20,16 @@ const CrashMessage = props => (
<p> <p>
<FormattedMessage id="general.unhandledError" /> <FormattedMessage id="general.unhandledError" />
</p> </p>
{props.eventId && (
<p>
<FormattedMessage
id="general.errorIdentifier"
values={{
errorId: props.eventId
}}
/>
</p>
)}
<Button <Button
className="" className=""
onClick={props.onBack} onClick={props.onBack}
@ -32,6 +42,7 @@ const CrashMessage = props => (
CrashMessage.propTypes = { CrashMessage.propTypes = {
className: PropTypes.string, className: PropTypes.string,
eventId: PropTypes.string,
onBack: PropTypes.func onBack: PropTypes.func
}; };

View file

@ -1,5 +1,6 @@
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const React = require('react'); const React = require('react');
const Sentry = require('@sentry/browser');
const CrashMessageComponent = require('../crashmessage/crashmessage.jsx'); const CrashMessageComponent = require('../crashmessage/crashmessage.jsx');
import log from '../../lib/log.js'; import log from '../../lib/log.js';
@ -8,14 +9,24 @@ class ErrorBoundary extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
this.state = { this.state = {
hasError: false hasError: false,
errorId: null
}; };
} }
componentDidCatch (error, info) { componentDidCatch (error, errorInfo) {
// Display fallback UI // Display fallback UI
this.setState({hasError: true}); Sentry.withScope(scope => {
log.error(`Unhandled Error: ${error}, info: ${info}`); Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
Sentry.captureException(error);
});
this.setState({
hasError: true,
errorId: Sentry.lastEventId()
});
log.error(`Unhandled Error: ${error}, info: ${errorInfo}`);
} }
handleBack () { handleBack () {
@ -24,7 +35,12 @@ class ErrorBoundary extends React.Component {
render () { render () {
if (this.state.hasError) { if (this.state.hasError) {
return <CrashMessageComponent onBack={this.handleBack} />; return (
<CrashMessageComponent
eventId={this.state.errorId}
onBack={this.handleBack}
/>
);
} }
return this.props.children; return this.props.children;
} }

View file

@ -8,23 +8,21 @@ require('./extension-landing.scss');
const ExtensionHeader = props => ( const ExtensionHeader = props => (
<div className="extension-header"> <div className="extension-header">
<FlexRow className="inner"> <FlexRow className="inner">
<FlexRow className="column extension-info"> <FlexRow className="extension-info">
{props.children} {props.renderCopy}
<div className="extension-image">
{props.renderImage}
</div>
</FlexRow> </FlexRow>
<div className="extension-image"> {props.renderRequirements}
<img
alt={props.imageAlt}
src={props.imageSrc}
/>
</div>
</FlexRow> </FlexRow>
</div> </div>
); );
ExtensionHeader.propTypes = { ExtensionHeader.propTypes = {
children: PropTypes.node, renderCopy: PropTypes.node,
imageAlt: PropTypes.string, renderImage: PropTypes.node,
imageSrc: PropTypes.string renderRequirements: PropTypes.node
}; };
module.exports = ExtensionHeader; module.exports = ExtensionHeader;

View file

@ -79,15 +79,20 @@
.inner { .inner {
justify-content: space-between; justify-content: space-between;
flex-wrap: nowrap; flex-wrap: nowrap;
flex-direction: column;
align-items: flex-start;
} }
.extension-info { .extension-info {
max-width: $cols7; margin-bottom: 3rem;
align-items: flex-start; flex-wrap: nowrap;
flex-direction: row;
.extension-copy { .extension-copy {
margin-bottom: 5rem; padding-right: 3.75em;
max-width: $cols7;
align-items: flex-start; align-items: flex-start;
justify-content: start;
h1, h2 { h1, h2 {
display: flex; display: flex;
@ -110,40 +115,45 @@
} }
} }
.extension-requirements-container { .video-player {
font-weight: 500; border: .25rem solid $ui-white-15percent;
align-items: flex-start; border-radius: .75rem;
height: 180px;
.requirements-header { overflow: hidden;
margin-bottom: 1.5rem;
}
.extension-requirements {
justify-content: space-between;
}
.extension-requirements span {
display: flex;
margin-right: 1rem;
font-size: 15px; // TODO: change to rem later
align-items: center;
}
.extension-requirements span img {
padding-right: .5rem;
}
} }
} }
.extension-image { .extension-image {
width: 100%; margin-top: auto;
max-width: $cols5;
img { img {
max-width: 100%; max-width: $cols5;
max-height: 100%; max-height: $cols3;
}
}
.extension-requirements-container {
font-weight: 500;
align-items: flex-start;
.requirements-header {
margin-bottom: 1.5rem;
} }
.extension-requirements {
justify-content: space-between;
}
.extension-requirements span {
display: flex;
margin-right: 1rem;
font-size: 15px; // TODO: change to rem later
align-items: center;
}
.extension-requirements span img {
padding-right: .5rem;
}
} }
} }
@ -158,17 +168,40 @@
align-items: flex-start; align-items: flex-start;
} }
.step-image.badge { .downloads-container {
height: initial; text-align: center;
} }
.download-button { .store-badge {
display: flex; display: block;
align-items: center; width: 150px;
height: 80px;
}
img { .horizontal-divider {
margin-left: .5rem; display: block;
} margin: 20px;
}
.horizontal-divider:before,
.horizontal-divider:after {
display: inline-block;
position: relative;
background-color: $ui-dark-gray;
width: 50%;
height: 1px;
vertical-align: middle;
content: "";
}
.horizontal-divider:before {
right: .5em;
margin-left: -50%;
}
.horizontal-divider:after {
left: .5em;
margin-right: -50%;
} }
} }

View file

@ -0,0 +1,29 @@
const PropTypes = require('prop-types');
const React = require('react');
require('./extension-landing.scss');
const ExtensionVideo = props => (
<div className="video-player">
<iframe
allowFullScreen
allowTransparency="true"
frameBorder="0"
height="180"
scrolling="no"
src={`https://fast.wistia.net/embed/iframe/${props.videoId}?seo=false&videoFoam=true`}
title="📹"
width="320"
/>
<script
async
src="https://fast.wistia.net/assets/external/E-v1.js"
/>
</div>
);
ExtensionVideo.propTypes = {
videoId: PropTypes.string
};
module.exports = ExtensionVideo;

View file

@ -24,23 +24,34 @@ const InstallScratchLink = ({
<span className="step-description"> <span className="step-description">
<FormattedMessage id="installScratchLink.downloadAndInstall" /> <FormattedMessage id="installScratchLink.downloadAndInstall" />
</span> </span>
<a <div className="downloads-container">
className="step-image badge" <a
href={`https://downloads.scratch.mit.edu/link/${ href={
currentOS === OS_ENUM.WINDOWS ? 'windows' : 'mac' currentOS === OS_ENUM.WINDOWS ?
}.zip`} 'https://www.microsoft.com/store/productId/9N48XLLCZH0X' :
> 'https://itunes.apple.com/us/app/scratch-link/id1408863490'
<button className="button download-button">
{currentOS === OS_ENUM.WINDOWS ?
<FormattedMessage id="installScratchLink.windowsDownload" /> :
<FormattedMessage id="installScratchLink.macosDownload" />
} }
target="_blank"
>
<img <img
alt="" alt=""
src="/svgs/extensions/download-white.svg" className="store-badge"
src={`/images/scratchlink/${
currentOS === OS_ENUM.WINDOWS ? 'windows' : 'mac'
}-store-badge.svg`}
/> />
</button> </a>
</a> <span className="horizontal-divider">
<FormattedMessage id="installScratchLink.or" />
</span>
<a
href={`https://downloads.scratch.mit.edu/link/${
currentOS === OS_ENUM.WINDOWS ? 'windows' : 'mac'
}.zip`}
>
<FormattedMessage id="installScratchLink.directDownload" />
</a>
</div>
</Step> </Step>
</div> </div>

View file

@ -80,7 +80,7 @@ const ConferenceFooter = () => (
<a href="https://scratch.mit.edu">Scratch</a> <a href="https://scratch.mit.edu">Scratch</a>
</li> </li>
<li> <li>
<a href="http://www.scratchjr.org/">ScratchJr</a> <a href="https://www.scratchjr.org/">ScratchJr</a>
</li> </li>
</FlexRow> </FlexRow>
<FlexRow <FlexRow

View file

@ -23,7 +23,7 @@ const ConferenceFooter = props => (
<a href="https://scratch.mit.edu">Scratch</a> <a href="https://scratch.mit.edu">Scratch</a>
</li> </li>
<li> <li>
<a href="http://www.scratchjr.org/">ScratchJr</a> <a href="https://www.scratchjr.org/">ScratchJr</a>
</li> </li>
</FlexRow> </FlexRow>
<FlexRow <FlexRow

View file

@ -99,7 +99,7 @@ const ConferenceFooter = props => (
</li> </li>
<li> <li>
<a <a
href="http://www.scratchjr.org/" href="https://www.scratchjr.org/"
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >

View file

@ -124,8 +124,8 @@ const Footer = props => (
<FormattedMessage id="general.support" /> <FormattedMessage id="general.support" />
</dt> </dt>
<dd> <dd>
<a href="/tips"> <a href="/ideas">
<FormattedMessage id="general.tips" /> <FormattedMessage id="general.ideas" />
</a> </a>
</dd> </dd>
<dd> <dd>
@ -186,7 +186,7 @@ const Footer = props => (
</a> </a>
</dd> </dd>
<dd> <dd>
<a href="http://www.scratchjr.org/"> <a href="https://www.scratchjr.org/">
<FormattedMessage id="general.scratchJr" /> <FormattedMessage id="general.scratchJr" />
</a> </a>
</dd> </dd>

View file

@ -4,6 +4,7 @@ const React = require('react');
const Thumbnail = require('../thumbnail/thumbnail.jsx'); const Thumbnail = require('../thumbnail/thumbnail.jsx');
const FlexRow = require('../flex-row/flex-row.jsx'); const FlexRow = require('../flex-row/flex-row.jsx');
const thumbnailUrl = require('../../lib/user-thumbnail');
require('./grid.scss'); require('./grid.scss');
@ -15,7 +16,7 @@ const Grid = props => (
if (props.itemType === 'projects') { if (props.itemType === 'projects') {
return ( return (
<Thumbnail <Thumbnail
avatar={`https://cdn2.scratch.mit.edu/get_image/user/${item.author.id}_32x32.png`} avatar={thumbnailUrl(item.author.id)}
creator={item.author.username} creator={item.author.username}
favorites={item.stats.favorites} favorites={item.stats.favorites}
href={href} href={href}

View file

@ -5,8 +5,9 @@ const React = require('react');
const navigationActions = require('../../redux/navigation.js'); const navigationActions = require('../../redux/navigation.js');
const IframeModal = require('../modal/iframe/modal.jsx'); const Video = require('../video/video.jsx');
const Registration = require('../registration/registration.jsx'); const FlexRow = require('../flex-row/flex-row.jsx');
const TitleBanner = require('../title-banner/title-banner.jsx');
require('./intro.scss'); require('./intro.scss');
@ -14,8 +15,7 @@ class Intro extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
bindAll(this, [ bindAll(this, [
'handleShowVideo', 'handleShowVideo'
'handleCloseVideo'
]); ]);
this.state = { this.state = {
videoOpen: false videoOpen: false
@ -24,120 +24,84 @@ class Intro extends React.Component {
handleShowVideo () { handleShowVideo () {
this.setState({videoOpen: true}); this.setState({videoOpen: true});
} }
handleCloseVideo () {
this.setState({videoOpen: false});
}
render () { render () {
return ( return (
<div className="intro"> <TitleBanner className="intro-banner">
<div className="content"> <FlexRow className="intro-container">
<h1 <FlexRow className="intro-content column">
dangerouslySetInnerHTML={{ // eslint-disable-line react/no-danger <h1 className="intro-header">
__html: this.props.messages['intro.tagLine'] <span>{this.props.messages['intro.tagLine1']}</span>
}} <br />
/> <span>{this.props.messages['intro.tagLine2']}</span>
<div className="sprites"> </h1>
<a <FlexRow className="intro-buttons">
className="sprite sprite-1" <a
href="/projects/editor/?tip_bar=getStarted" className="intro-button create-button button"
> href="/create"
<img >
alt="Scratch Cat" {this.props.messages['intro.startCreating']}
className="costume costume-1" </a>
src="//cdn.scratch.mit.edu/scratchr2/static/images/cat-a.png" <a
/> className="intro-button join-button button"
<img href="#"
alt="Scratch Cat" onClick={this.props.handleOpenRegistration}
className="costume costume-2" >
src="//cdn.scratch.mit.edu/scratchr2/static/images/cat-b.png" {this.props.messages['intro.join']}
/> </a>
<div className="circle" /> </FlexRow>
<div className="text">
{this.props.messages['intro.tryItOut']} </FlexRow>
</div> <FlexRow className="intro-video-container">
</a> {this.state.videoOpen ?
<a (
className="sprite sprite-2" <Video
href="/starter_projects/" className="intro-video"
> videoId="joal01i8b1"
<img />
alt="Tera" ) : (
className="costume costume-1" <div
src="//cdn.scratch.mit.edu/scratchr2/static/images/tera-a.png" className="video-image"
/> onClick={this.handleShowVideo}
<img >
alt="Tera" <img src="/svgs/intro/video-image.svg" />
className="costume costume-2" <a
src="//cdn.scratch.mit.edu/scratchr2/static/images/tera-b.png" href="#"
/> onClick={this.handleShowVideo}
<div className="circle" /> >
<div className="text"> <div className="watch-button button">
{this.props.messages['intro.seeExamples']} {this.props.messages['intro.watchVideo']}
</div> </div>
</a> </a>
<a </div>
className="sprite sprite-3" )
href="#" }
onClick={this.props.handleOpenRegistration} </FlexRow>
> </FlexRow>
<img
alt="Gobo" <FlexRow className="intro-subnav">
className="costume costume-1" <a
src="//cdn.scratch.mit.edu/scratchr2/static/images/gobo-a.png" href="/about"
/> >
<img <div className="subnav-button button">
alt="Gobo"
className="costume costume-2"
src="//cdn.scratch.mit.edu/scratchr2/static/images/gobo-b.png"
/>
<div className="circle" />
<div className="text">
{this.props.messages['intro.joinScratch']}
</div>
<div className="text subtext">{this.props.messages['intro.itsFree']}</div>
</a>
<Registration
key="registration"
/>
</div>
<div
className="description"
dangerouslySetInnerHTML={{ // eslint-disable-line react/no-danger
__html: this.props.messages['intro.description']
}}
/>
<div className="links">
<a href="/about/">
{this.props.messages['intro.aboutScratch']} {this.props.messages['intro.aboutScratch']}
</a> </div>
<a href="/educators/"> </a>
{this.props.messages['intro.forEducators']} <a
</a> href="/parents"
<a >
className="last" <div className="subnav-button button">
href="/parents/"
>
{this.props.messages['intro.forParents']} {this.props.messages['intro.forParents']}
</a> </div>
</div> </a>
</div> <a
<div className="video"> href="/educators"
<div >
className="play-button" <div className="subnav-button button">
onClick={this.handleShowVideo} {this.props.messages['intro.forEducators']}
/> </div>
<img </a>
alt="Intro Video" </FlexRow>
src="//cdn.scratch.mit.edu/scratchr2/static/images/hp-video-screenshot.png" </TitleBanner>
/>
</div>
<IframeModal
className="mod-intro-video"
isOpen={this.state.videoOpen}
src="//player.vimeo.com/video/65583694?title=0&amp;byline=0&amp;portrait=0"
onRequestClose={this.handleCloseVideo}
/>
</div>
); );
} }
} }
@ -148,27 +112,24 @@ Intro.propTypes = {
'intro.aboutScratch': PropTypes.string, 'intro.aboutScratch': PropTypes.string,
'intro.forEducators': PropTypes.string, 'intro.forEducators': PropTypes.string,
'intro.forParents': PropTypes.string, 'intro.forParents': PropTypes.string,
'intro.itsFree': PropTypes.string, 'intro.join': PropTypes.string,
'intro.joinScratch': PropTypes.string, 'intro.startCreating': PropTypes.string,
'intro.seeExamples': PropTypes.string, 'intro.tagLine1': PropTypes.string,
'intro.tagLine': PropTypes.string, 'intro.tagLine2': PropTypes.string,
'intro.tryItOut': PropTypes.string, 'intro.watchVideo': PropTypes.string
'intro.description': PropTypes.string
}) })
}; };
Intro.defaultProps = { Intro.defaultProps = {
messages: { messages: {
'intro.aboutScratch': 'ABOUT SCRATCH', 'intro.aboutScratch': 'About Scratch',
'intro.forEducators': 'FOR EDUCATORS', 'intro.forEducators': 'For Educators',
'intro.forParents': 'FOR PARENTS', 'intro.forParents': 'For Parents',
'intro.itsFree': 'it\'s free!', 'intro.join': 'Join',
'intro.joinScratch': 'JOIN SCRATCH', 'intro.startCreating': 'Start Creating',
'intro.seeExamples': 'SEE EXAMPLES', 'intro.tagLine1': 'Create stories, games, and animations',
'intro.tagLine': 'Create stories, games, and animations<br /> Share with others around the world', 'intro.tagLine2': 'Share with others around the world',
'intro.tryItOut': 'TRY IT OUT', 'intro.watchVideo': 'Watch Video'
'intro.description': 'A creative learning community with <span class="project-count"> ' +
'over 14 million </span>projects shared'
}, },
session: {} session: {}
}; };
@ -180,7 +141,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
handleOpenRegistration: event => { handleOpenRegistration: event => {
event.preventDefault(); event.preventDefault();
dispatch(navigationActions.handleOpenRegistration()); dispatch(navigationActions.setRegistrationOpen(true));
} }
}); });

View file

@ -1,253 +1,207 @@
@import "../../colors"; @import "../../colors";
@import "../../frameless";
.intro { .intro-banner {
display: flex; display: flex;
margin-top: 20px; flex-direction: column;
margin-bottom: 30px; position: relative;
flex-direction: row; padding: 0;
flex-wrap: nowrap;
justify-content: space-between; justify-content: space-between;
align-content: flex-start; background-color: $ui-white;
h1 { .intro-container {
line-height: 2.125rem; min-height: 24rem;
color: $ui-orange; justify-content: space-between;
font-size: 1.625rem; background-color: $ui-blue;
font-weight: 400; background-size: auto;
background-repeat: no-repeat;
background-position: right;
background-image: url("/svgs/intro/background-cropped.svg");
} }
.content { /* flex: column */
display: inline-block; .intro-content {
width: calc(66% - 30px); flex: 1;
vertical-align: top; justify-content: center;
align-items: flex-start;
margin-left: 5%;
min-height: 20rem;
} }
.sprites { .intro-video-container {
position: relative; display: flex;
clear: both; justify-content: center;
margin: 20px 0; align-items: center;
overflow: hidden; flex: 0 0 29rem;
.intro-video {
margin-right: 4rem;
}
.video-image {
position: relative;
cursor: pointer;
margin-right: 4rem;
.watch-button {
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 50%);
border-radius: 4px;
background-color: rgba(0,0,0,0.15);
box-shadow: 0 0 0 4px rgba(0,0,0,0.15);
color: $ui-white;
padding: .625rem .75rem;
font-size: 1rem;
}
}
&:after { &:after {
display: block; display: block;
clear: both; position: absolute;
visibility: hidden; bottom: .75rem;
height: 0; right: 10%;
content: " "; background-image: url("/svgs/intro/hat-block.svg");
background-repeat: no-repeat;
width: 122px;
height: 81px;
content: "";
} }
} }
.sprite { .intro-header {
position: relative; margin-bottom: .75rem;
float: left; font-size: 2rem;
width: 193px; color: $ui-white;
height: 136px; line-height: 1.5em;
overflow: hidden; }
.costume, .intro-button {
.circle, border-radius: 4px;
.text { background-color: $ui-white;
position: absolute; color: $ui-blue;
padding: .625rem .75rem;
font-size: 1rem;
margin-right: .75rem;
&.create-button:before {
display: inline-block;
margin-right: .5rem;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
background-image: url("/svgs/intro/create.svg");
width: 1.5rem;
height: 1.5rem;
vertical-align: -.35rem;
content: "";
} }
.costume { &.join-button:before {
left: 0; display: inline-block;
z-index: 2; margin-right: .5rem;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
background-image: url("/svgs/intro/join.svg");
width: 1.5rem;
height: 1.5rem;
vertical-align: -.35rem;
content: "";
} }
}
.costume-2 {
display: none; .intro-subnav {
justify-content: center;
background-color: $ui-blue-10percent;
.subnav-button {
margin: .625rem .5rem;
padding: .5rem 1.5rem;
border-radius: 1.5rem;
} }
}
}
.circle { $rowLayoutMin: 900px;
display: block; $tabletPortrait: 768px;
top: 15px; $tabletLandscape: 1024px;
left: 43px; // $desktop: 942px;
z-index: 0; // $tablet: 640px; (should be renamed)
border-radius: 50%; // $mobile: 480px;
box-shadow: 0 0 5px $ui-white;
width: 112px; @media only screen and (min-width: $rowLayoutMin) and (max-width: $tabletLandscape - 1) {
height: 112px; .intro-banner {
.intro-header {
max-width: 22rem;
text-align: left; // override #view text centering
} }
}
}
.text { @media only screen and (min-width: $mobile) and (max-width: $rowLayoutMin - 1) {
$text-bg-color: $background-color; .intro-banner {
left: 35px; justify-content: flex-start;
z-index: 1;
border: 2px solid $text-bg-color; .intro-header {
background-color: $text-bg-color; margin-top: 1.75rem;
padding-right: 10px; font-size: 1.5rem;
padding-left: 40px;
white-space: nowrap;
font-size: 12px;
font-weight: 700;
} }
.subtext { .intro-container {
border: 0; flex-direction: column;
background-color: transparent; background-position: bottom 32px right 50%;
text-shadow: 0; background-size: 40rem;
font-size: 12px; background-image: url("/svgs/intro/background.svg");
font-weight: 400;
} .intro-content {
align-items: center;
min-height: 8rem;
&.sprite-1 { margin: 0;
.circle {
background-color: $ui-aqua;
}
.text {
top: 60px;
left: 50px;
color: $ui-aqua;
} }
} }
&.sprite-2 { .intro-video-container {
.circle { flex: 0 0 24rem;
background-color: $ui-purple;
.video-image,
.video-player {
margin: 0;
} }
&:after {
.text {
top: 77px;
left: 50px;
color: $ui-purple;
}
}
&.sprite-3 {
.circle {
background-color: $ui-blue;
}
.text {
top: 37px;
left: 45px;
color: $ui-blue;
}
.subtext {
top: 63px;
left: 60px;
color: $ui-white;
}
}
&:hover {
.costume-1 {
display: none; display: none;
} }
.costume-2 {
display: block;
}
&.sprite-1 {
.circle {
box-shadow: 0 0 10px 2px $ui-aqua;
}
}
&.sprite-2 {
.circle {
box-shadow: 0 0 10px 2px $ui-purple;
}
}
&.sprite-3 {
.circle {
box-shadow: 0 0 10px 2px $ui-blue;
}
}
}
}
.description {
margin-top: 10px;
font-size: 17px;
}
.project-count {
$project-count-color: hsl(318, 50%, 52%);
color: $project-count-color;
font-size: 18px;
font-weight: 700;
}
.links {
margin-top: 20px;
letter-spacing: .5px;
font-size: 12px;
a {
border-right: 1px solid $type-gray;
padding: 0 5px;
&:last-child { border-right: 0; }
&:first-child { padding-left: 0; }
}
}
.video {
display: inline-block;
position: relative;
border: 1px solid $ui-border;
border-radius: 10px;
background-color: $ui-white;
padding: 14px 10px;
width: 34%;
height: 208px;
text-align: center;
img {
border-radius: 5px;
}
}
.play-button {
display: block;
top: calc(50% - 25px);
left: calc(50% - 35px);
opacity: .8;
border: 5px solid $ui-border;
border-radius: 20px;
background-color: $type-gray;
width: 70px;
height: 50px;
&,
&:after {
position: absolute;
margin: 0;
cursor: pointer;
padding: 0;
}
&:after {
$play-arrow: rgba(255, 255, 255, 0);
top: 37px;
left: 28px;
margin-top: -30px;
border: solid transparent;
border-width: 18px;
border-color: $play-arrow;
border-left-color: $ui-white;
width: 0;
height: 0;
content: " ";
pointer-events: none;
} }
} }
} }
.modal-content.mod-intro-video { @media #{$medium-and-smaller} {
padding: 15px; .intro-buttons,
width: 35.625rem; .intro-subnav {
flex-direction: row; // override flexrow default
}
} }
.modal-content-iframe.mod-intro-video { @media only screen and (max-width: $mobile - 1) {
width: 35.625rem; .intro-banner {
min-height: 22.3125rem; .intro-container {
background-image: none;
.intro-content.column {
margin: auto 5%;
align-items: center;
}
.intro-header {
font-size: 1.5rem;
}
.intro-video-container {
display: none;
}
}
}
} }

View file

@ -4,7 +4,7 @@ const PropTypes = require('prop-types');
const React = require('react'); const React = require('react');
const jar = require('../../lib/jar.js'); const jar = require('../../lib/jar.js');
const languages = require('../../../languages.json'); const languages = require('scratch-l10n').default;
const Form = require('../forms/form.jsx'); const Form = require('../forms/form.jsx');
const Select = require('../forms/select.jsx'); const Select = require('../forms/select.jsx');
@ -27,7 +27,7 @@ class LanguageChooser extends React.Component {
render () { render () {
const languageOptions = Object.keys(this.props.languages).map(value => ({ const languageOptions = Object.keys(this.props.languages).map(value => ({
value: value, value: value,
label: this.props.languages[value] label: this.props.languages[value].name
})); }));
return ( return (
<Form className={classNames('language-chooser', this.props.className)}> <Form className={classNames('language-chooser', this.props.className)}>

View file

@ -3,7 +3,7 @@
.masonry { .masonry {
column-gap: $gutter; column-gap: $gutter;
column-width: $cols4; column-width: $cols4;
padding-bottom: 50px; padding-bottom: 1rem;
-webkit-perspective: 1; -webkit-perspective: 1;
} }

View file

@ -2,6 +2,12 @@
@import "../../../frameless"; @import "../../../frameless";
.mod-addToStudio { .mod-addToStudio {
min-height: 15rem;
max-height: calc(100% - 8rem);
/* Some value for height must be set for scrolling to work */
height: 100%;
overflow: hidden; overflow: hidden;
@media #{$small}, #{$small-height} { @media #{$small}, #{$small-height} {
@ -18,14 +24,14 @@
margin: 0 auto; margin: 0 auto;
box-shadow: none; box-shadow: none;
width: 100%; width: 100%;
height: calc(100% - 3rem);
} }
.studio-list-outer-scrollbox { .studio-list-outer-scrollbox {
position: relative; position: relative;
background-color: $ui-blue-10percent; background-color: $ui-blue-10percent;
min-height: 15rem;
max-height: calc(100% - 8rem);
flex: 1; flex: 1;
height: calc(100% - 5rem);
@media #{$small-height} { @media #{$small-height} {
min-height: 0; min-height: 0;

View file

@ -1,13 +1,9 @@
const FormattedMessage = require('react-intl').FormattedMessage; const FormattedMessage = require('react-intl').FormattedMessage;
const MediaQuery = require('react-responsive').default;
const omit = require('lodash.omit'); const omit = require('lodash.omit');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const React = require('react'); const React = require('react');
const FlexRow = require('../../flex-row/flex-row.jsx');
const frameless = require('../../../lib/frameless');
const Modal = require('../base/modal.jsx'); const Modal = require('../base/modal.jsx');
const TitleBanner = require('../../title-banner/title-banner.jsx');
require('../../forms/button.scss'); require('../../forms/button.scss');
require('./modal.scss'); require('./modal.scss');
@ -20,119 +16,82 @@ const TTTModal = props => (
[ [
'title', 'title',
'description', 'description',
'tutorialLoc', 'tutorialUrl',
'activityLoc', 'cardsUrl',
'guideLoc', 'guideUrl',
'thumbUrl', 'thumbImage',
'bannerUrl' 'modalImage'
] ]
)} )}
> >
<TitleBanner className="mod-ttt"> <div className="ttt-modal-header modal-header" />
<MediaQuery minWidth={frameless.mobile}> <div className="ttt-modal-body">
<img <a href={props.tutorialUrl}>
alt="" <div className="ttt-img-container">
className="mod-ttt-img" <img
src={props.bannerUrl} alt=""
/> className="mod-ttt-img"
</MediaQuery> src={props.modalImage}
<MediaQuery maxWidth={frameless.mobile - 1}> />
<img </div>
alt="" </a>
className="mod-ttt-img" <div className="ttt-content">
src={props.thumbUrl} <div className="ttt-content-chunk">
/> <h2>{props.title}</h2>
</MediaQuery> <p className="ttt-description">{props.description}</p>
</TitleBanner> <a
<div className="ttt-title"> className="button ttt-try-tutorial-button"
<h2>{props.title}</h2> href={props.tutorialUrl}
<p className="ttt-description">{props.description}</p> >
<img src="/images/ideas/bulb-icon.svg" />
<FormattedMessage id="ideas.tryTheTutorial" />
</a>
</div>
<div className="ttt-content-chunk">
<div className="ttt-row">
<div className="ttt-item">
<img src="/images/ideas/coding-cards-icon.svg" />
<FormattedMessage id="ideas.codingCards" />
</div>
<div className="ttt-item">
<a
href={props.cardsUrl}
target="_blank"
>
<FormattedMessage id="ideas.downloadPDF" />
</a>
</div>
</div>
</div>
<div className="ttt-content-chunk">
<div className="ttt-row">
<div className="ttt-item">
<img src="/images/ideas/educator-guide-icon.svg" />
<FormattedMessage id="ideas.educatorGuide" />
</div>
<div className="ttt-item">
<a
href={props.guideUrl}
target="_blank"
>
<FormattedMessage id="ideas.downloadPDF" />
</a>
</div>
</div>
</div>
</div>
</div> </div>
<ul className="modal-content-ttt">
<FlexRow
as="li"
className="mod-ttt-item"
>
<div className="modal-content-ttt-text">
<div className="modal-content-ttt-title">
<img
alt="tutorial-icon"
className="modal-content-ttt-title-img"
src="/svgs/ttt/tutorial.svg"
/>
<FormattedMessage id="ttt.tutorial" />
</div>
<p className="modal-content-ttt-subtitle">
<FormattedMessage id="ttt.tutorialSubtitle" />
</p>
</div>
<a
className="button white mod-ttt-item"
href={props.tutorialLoc}
>
<FormattedMessage id="tile.tryIt" />
</a>
</FlexRow>
<FlexRow
as="li"
className="mod-ttt-item"
>
<div className="modal-content-ttt-text">
<div className="modal-content-ttt-title">
<img
alt="activity-cards-icon"
className="modal-content-ttt-title-img"
src="/svgs/ttt/activity-cards.svg"
/>
<FormattedMessage id="ttt.activityTitle" />
</div>
<p className="modal-content-ttt-subtitle">
<FormattedMessage id="ttt.activitySubtitle" />
</p>
</div>
<a
className="button white mod-ttt-item"
href={props.activityLoc}
>
<FormattedMessage id="ttt.open" />
</a>
</FlexRow>
<FlexRow
as="li"
className="mod-ttt-item"
>
<div className="modal-content-ttt-text">
<div className="modal-content-ttt-title">
<img
alt="educator-guide-icon"
className="modal-content-ttt-title-img"
src="/svgs/ttt/educator-guide.svg"
/>
<FormattedMessage id="ttt.educatorTitle" />
</div>
<p className="modal-content-ttt-subtitle">
<FormattedMessage id="ttt.educatorSubtitle" />
</p>
</div>
<a
className="button white mod-ttt-item"
href={props.guideLoc}
>
<FormattedMessage id="ttt.open" />
</a>
</FlexRow>
</ul>
</Modal> </Modal>
); );
TTTModal.propTypes = { TTTModal.propTypes = {
activityLoc: PropTypes.string.isRequired, cardsUrl: PropTypes.string.isRequired,
bannerUrl: PropTypes.string.isRequired,
description: PropTypes.string.isRequired, description: PropTypes.string.isRequired,
guideLoc: PropTypes.string.isRequired, guideUrl: PropTypes.string.isRequired,
thumbUrl: PropTypes.string.isRequired, modalImage: PropTypes.string.isRequired,
thumbImage: PropTypes.string.isRequired,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
tutorialLoc: PropTypes.string.isRequired tutorialUrl: PropTypes.string.isRequired
}; };
module.exports = TTTModal; module.exports = TTTModal;

View file

@ -1,97 +1,62 @@
@import "../../../colors"; @import "../../../colors";
@import "../../../frameless"; @import "../../../frameless";
.modal-content.mod-ttt { .mod-ttt {
overflow: hidden; // Needed to put banner background behind border. overflow: hidden;
} }
.title-banner.mod-ttt { .ttt-modal-header {
margin-bottom: 0; background-color: $ui-blue;
background-color: transparent; height: 3rem;
padding: 0; }
.ttt-modal-body {
display: flex;
margin: 2.5rem 3rem;
} }
.mod-ttt-img { .mod-ttt-img {
padding: 0; border-radius: .5rem;
width: 100%; overflow: hidden;
height: 18rem;
width: 18rem;
} }
.ttt-title { .ttt-content {
text-align: center; margin-left: 2rem;
}
.ttt-content-chunk + .ttt-content-chunk {
margin-top: 1rem;
border-top: 1px solid $ui-border;
padding-top: 1rem;
} }
.ttt-description { .ttt-description {
margin: 0; margin-top: 0;
font-size: 1.1rem;
} }
.modal-content-ttt { a.ttt-try-tutorial-button {
padding: 0 5rem; display: flex;
list-style: none; width: fit-content;
align-items: center;
& > span {
color: $type-white;
}
& > img {
margin-right: .5rem;
}
} }
.flex-row.mod-ttt-item { .ttt-row {
margin: 0; display: flex;
border-top: 1px dashed $ui-border;
padding: .5rem;
justify-content: space-between; justify-content: space-between;
} }
.modal-content-ttt-text { .ttt-item {
max-width: 70%; display: flex;
} img {
margin-right: 1rem;
.modal-content-ttt-title,
.modal-content-ttt-subtitle {
margin: 0;
font-size: .875rem;
}
.modal-content-ttt-title {
font-weight: 500;
}
.modal-content-ttt-title-img {
margin-right: .25rem;
width: 1.25rem;
vertical-align: middle;
}
.button.white.mod-ttt-item {
border: 1px solid $ui-blue;
box-shadow: none;
}
@media #{$small} {
.modal-content.mod-ttt {
overflow: scroll;
}
.modal-content-ttt {
padding: 0;
}
.modal-content-ttt {
text-align: center;
}
}
@media #{$medium} {
.modal-content.mod-ttt {
overflow: scroll;
}
.modal-content-ttt {
padding: 0 2.5rem;
}
.flex-row.mod-ttt-item {
flex-direction: row;
}
}
@media #{$intermediate} {
.modal-content.mod-ttt {
overflow: scroll;
} }
} }

View file

@ -81,7 +81,7 @@ class Navigation extends React.Component {
window.location.href = `/search/projects?q=${encodeURIComponent(formData.q)}`; window.location.href = `/search/projects?q=${encodeURIComponent(formData.q)}`;
} }
render () { render () {
const createLink = this.props.user ? '/projects/editor/' : '/projects/editor/?tip_bar=home'; const createLink = this.props.user ? '/projects/editor/' : '/projects/editor/?tutorial=getStarted';
return ( return (
<NavigationBox <NavigationBox
className={classNames({ className={classNames({
@ -106,9 +106,9 @@ class Navigation extends React.Component {
<FormattedMessage id="general.explore" /> <FormattedMessage id="general.explore" />
</a> </a>
</li> </li>
<li className="link tips"> <li className="link ideas">
<a href="/tips"> <a href="/ideas">
<FormattedMessage id="general.tips" /> <FormattedMessage id="general.ideas" />
</a> </a>
</li> </li>
<li className="link about"> <li className="link about">

View file

@ -0,0 +1,24 @@
const React = require('react');
const FormattedMessage = require('react-intl').FormattedMessage;
const FlexRow = require('../../components/flex-row/flex-row.jsx');
require('./not-available.scss');
const ProjectNotAvailable = () => (
<div className="not-available-outer">
<FlexRow className="inner">
<img
className="not-available-image"
src="/images/404-giga.png"
/>
<h1>
<FormattedMessage id="general.notAvailableHeadline" />
</h1>
<p>
<FormattedMessage id="general.notAvailableSubtitle" />
</p>
</FlexRow>
</div>
);
module.exports = ProjectNotAvailable;

View file

@ -0,0 +1,5 @@
@import "../../colors";
.not-available-image {
padding: 5rem 0 2rem;
}

View file

@ -6,9 +6,12 @@ const Navigation = require('../../navigation/www/navigation.jsx');
const Footer = require('../../footer/www/footer.jsx'); const Footer = require('../../footer/www/footer.jsx');
const ErrorBoundary = require('../../errorboundary/errorboundary.jsx'); const ErrorBoundary = require('../../errorboundary/errorboundary.jsx');
const Page = props => ( const Page = ({
children,
className
}) => (
<ErrorBoundary> <ErrorBoundary>
<div className="page"> <div className={classNames('page', className)}>
<div <div
className={classNames({ className={classNames({
staging: process.env.SCRATCH_ENV === 'staging' staging: process.env.SCRATCH_ENV === 'staging'
@ -18,7 +21,7 @@ const Page = props => (
<Navigation /> <Navigation />
</div> </div>
<div id="view"> <div id="view">
{props.children} {children}
</div> </div>
<div id="footer"> <div id="footer">
<Footer /> <Footer />
@ -28,7 +31,8 @@ const Page = props => (
); );
Page.propTypes = { Page.propTypes = {
children: PropTypes.node children: PropTypes.node,
className: PropTypes.string
}; };
module.exports = Page; module.exports = Page;

View file

@ -4,6 +4,7 @@ const React = require('react');
const Thumbnail = require('../thumbnail/thumbnail.jsx'); const Thumbnail = require('../thumbnail/thumbnail.jsx');
const FlexRow = require('../flex-row/flex-row.jsx'); const FlexRow = require('../flex-row/flex-row.jsx');
const thumbnailUrl = require('../../lib/user-thumbnail');
require('./thumbnailcolumn.scss'); require('./thumbnailcolumn.scss');
@ -11,10 +12,10 @@ const ThumbnailColumn = props => (
<FlexRow className={classNames('thumbnail-column', props.className)}> <FlexRow className={classNames('thumbnail-column', props.className)}>
{props.items.map((item, key) => { {props.items.map((item, key) => {
const href = `/${props.itemType}/${item.id}/`; const href = `/${props.itemType}/${item.id}/`;
if (props.itemType === 'preview') { if (props.itemType === 'projects') {
return ( return (
<Thumbnail <Thumbnail
avatar={`https://cdn2.scratch.mit.edu/get_image/user/${item.author.id}_32x32.png`} avatar={thumbnailUrl(item.author.id)}
creator={item.author.username} creator={item.author.username}
favorites={item.stats.favorites} favorites={item.stats.favorites}
href={href} href={href}

View file

@ -1,5 +1,4 @@
const classNames = require('classnames'); const classNames = require('classnames');
const FormattedMessage = require('react-intl').FormattedMessage;
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const React = require('react'); const React = require('react');
@ -7,62 +6,34 @@ require('../forms/button.scss');
require('./ttt-tile.scss'); require('./ttt-tile.scss');
const TTTTile = props => ( const TTTTile = props => (
<div className={classNames('ttt-tile', props.className)}> <div
<a href={props.tutorialLoc}> className={classNames('ttt-tile', props.className)}
<div className="ttt-tile-tutorial"> onClick={props.onClick}
<div className="ttt-tile-image"> >
<img <div className="ttt-tile-tutorial">
alt="" <div className="ttt-tile-image">
className="ttt-tile-image-img"
src={props.thumbUrl}
/>
<div className="ttt-tile-image-try">
<div className="button mod-ttt-try-button">
<FormattedMessage id="tile.tryIt" />
</div>
</div>
</div>
<div className="ttt-tile-info">
<div className="ttt-tile-tag">
<FormattedMessage
defaultMessage="Tutorial"
id="ttt.tutorial"
/>
</div>
<h4 className="ttt-tile-title">{props.title}</h4>
<p className="ttt-tile-description">
{props.description}
</p>
</div>
</div>
</a>
{props.onGuideClick && (
<div
className="ttt-tile-guides"
onClick={props.onGuideClick}
>
<FormattedMessage
defaultMessage="See Cards and Guides"
id="tile.guides"
/>
<img <img
className="ttt-tile-open-modal" alt=""
src="/svgs/modal/open-blue.svg" className="ttt-tile-image-img"
src={props.thumbImage}
/> />
</div> </div>
)} <div className="ttt-tile-info">
<h4 className="ttt-tile-title">{props.title}</h4>
<p className="ttt-tile-description">
{props.description}
</p>
</div>
</div>
</div> </div>
); );
TTTTile.propTypes = { TTTTile.propTypes = {
className: PropTypes.string, className: PropTypes.string,
description: PropTypes.string, description: PropTypes.string,
onGuideClick: PropTypes.func, onClick: PropTypes.func,
thumbUrl: PropTypes.string.isRequired, thumbImage: PropTypes.string.isRequired,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired
tutorialLoc: PropTypes.string.isRequired
}; };
module.exports = TTTTile; module.exports = TTTTile;

View file

@ -12,6 +12,7 @@
background-color: $ui-white; background-color: $ui-white;
width: $cols4; width: $cols4;
text-align: center; text-align: center;
min-height: 18.125rem;
} }
.ttt-tile-tutorial { .ttt-tile-tutorial {
@ -19,21 +20,6 @@
position: relative; position: relative;
} }
// nesting is required (not just name-spacing) because we want the image
// and tile box to change style on hover of the parent component.
.ttt-tile-tutorial:hover {
.ttt-tile-image {
.ttt-tile-image-img {
opacity: .5;
}
.ttt-tile-image-try {
display: inline-block;
}
}
}
.ttt-tile-image { .ttt-tile-image {
border-radius: 1rem 1rem 0 0; border-radius: 1rem 1rem 0 0;
background: $ui-blue; background: $ui-blue;

View file

@ -0,0 +1,40 @@
const PropTypes = require('prop-types');
const React = require('react');
const classNames = require('classnames');
require('./video.scss');
const Video = props => (
<div className={classNames('video-player', props.className)}>
<iframe
allowFullScreen
// allowFullScreen is legacy, can we start using allow='fullscreen'?
// allow="fullscreen"
frameBorder="0" // deprecated attribute
height={props.height}
scrolling="no" // deprecated attribute
src={`https://fast.wistia.net/embed/iframe/${props.videoId}?seo=false&videoFoam=true`}
title={props.title}
width={props.width}
/>
<script
async
src="https://fast.wistia.net/assets/external/E-v1.js"
/>
</div>
);
Video.defaultProps = {
height: '225',
title: '',
width: '400'
};
Video.propTypes = {
className: PropTypes.string,
height: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
videoId: PropTypes.string.isRequired,
width: PropTypes.string.isRequired
};
module.exports = Video;

View file

@ -0,0 +1,9 @@
@import "../../colors";
@import "../../frameless";
.video-player {
border: .25rem solid $box-shadow-light-gray;
border-radius: .75rem;
height: 225px;
overflow: hidden;
}

View file

@ -19,11 +19,11 @@ const Welcome = props => (
> >
<div className="welcome-col blue"> <div className="welcome-col blue">
<h4> <h4>
<a href="/projects/editor/?tip_bar=getStarted"> <a href="/projects/editor/?tutorial=getStarted">
{props.messages['welcome.learn']} {props.messages['welcome.learn']}
</a> </a>
</h4> </h4>
<a href="/projects/editor/?tip_bar=getStarted"> <a href="/projects/editor/?tutorial=getStarted">
<img <img
alt="Get Started" alt="Get Started"
src="/images/welcome-learn.png" src="/images/welcome-learn.png"

View file

@ -1,16 +1,4 @@
const jar = require('./lib/jar'); const jar = require('./lib/jar');
const Raven = require('raven-js');
/**
* -----------------------------------------------------------------------------
* Error handling
* -----------------------------------------------------------------------------
*/
(() => {
if (process.env.SENTRY_DSN !== '') {
Raven.config(process.env.SENTRY_DSN).install();
}
})();
/** /**
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------

View file

@ -18,6 +18,7 @@
"general.dmca": "DMCA", "general.dmca": "DMCA",
"general.emailAddress": "Email Address", "general.emailAddress": "Email Address",
"general.error": "Oops! Something went wrong", "general.error": "Oops! Something went wrong",
"general.errorIdentifier": "Your error was logged with id {errorId}",
"general.explore": "Explore", "general.explore": "Explore",
"general.faq": "FAQ", "general.faq": "FAQ",
"general.female": "Female", "general.female": "Female",
@ -73,7 +74,7 @@
"general.statistics": "Statistics", "general.statistics": "Statistics",
"general.studios": "Studios", "general.studios": "Studios",
"general.support": "Support", "general.support": "Support",
"general.tips": "Tips", "general.ideas": "Ideas",
"general.tipsWindow": "Tips Window", "general.tipsWindow": "Tips Window",
"general.termsOfUse": "Terms of Use", "general.termsOfUse": "Terms of Use",
"general.unhandledError": "We are so sorry, but it looks like Scratch has crashed. This bug has been automatically reported to the Scratch Team.", "general.unhandledError": "We are so sorry, but it looks like Scratch has crashed. This bug has been automatically reported to the Scratch Team.",
@ -86,6 +87,9 @@
"general.wiki": "Scratch Wiki", "general.wiki": "Scratch Wiki",
"general.copyLink": "Copy Link", "general.copyLink": "Copy Link",
"general.report": "Report", "general.report": "Report",
"general.notAvailableHeadline": "Whoops! Our server is Scratch'ing its head",
"general.notAvailableSubtitle": "We couldn't find the page you're looking for. Check to make sure you've typed the url correctly.",
"general.seeAllComments": "See all comments",
"general.all": "All", "general.all": "All",
"general.animations": "Animations", "general.animations": "Animations",
@ -98,6 +102,10 @@
"general.teacherAccounts": "Teacher Accounts", "general.teacherAccounts": "Teacher Accounts",
"general.unsupportedBrowser": "This browser is not supported",
"general.unsupportedBrowserDescription": "We're very sorry, but Scratch 3.0 does not support Internet Explorer, Vivaldi, Opera or Silk. We recommend trying a newer browser such as Google Chrome, Mozilla Firefox, or Microsoft Edge.",
"general.3faq": "To learn more, go to the {faqLink}.",
"footer.discuss": "Discussion Forums", "footer.discuss": "Discussion Forums",
"footer.scratchFamily": "Scratch Family", "footer.scratchFamily": "Scratch Family",
@ -115,8 +123,8 @@
"installScratchLink.installHeaderTitle": "Install Scratch Link", "installScratchLink.installHeaderTitle": "Install Scratch Link",
"installScratchLink.downloadAndInstall": "Download and install Scratch Link.", "installScratchLink.downloadAndInstall": "Download and install Scratch Link.",
"installScratchLink.windowsDownload": "Download for Windows", "installScratchLink.or": "or",
"installScratchLink.macosDownload": "Download for macOS", "installScratchLink.directDownload": "Direct download",
"installScratchLink.startScratchLink": "Start Scratch Link and make sure it is running. It should appear in your toolbar.", "installScratchLink.startScratchLink": "Start Scratch Link and make sure it is running. It should appear in your toolbar.",
"parents.FaqAgeRangeA": "While Scratch is primarily designed for 8 to 16 year olds, it is also used by people of all ages, including younger children with their parents.", "parents.FaqAgeRangeA": "While Scratch is primarily designed for 8 to 16 year olds, it is also used by people of all ages, including younger children with their parents.",

View file

@ -12,24 +12,31 @@ const EXTENSION_INFO = {
l10nId: 'project.penExtensionChip', l10nId: 'project.penExtensionChip',
icon: 'extension-pen.svg' icon: 'extension-pen.svg'
}, },
speak: {
name: 'Amazon Polly'
},
speech: {
l10nId: 'project.speechExtensionChip'
},
translate: {
l10nId: 'project.translateExtensionChip',
icon: 'extension-translate.svg'
},
videoSensing: { videoSensing: {
l10nId: 'project.videoMotionChip', l10nId: 'project.videoMotionChip',
icon: 'extension-videomotion.svg' icon: 'extension-videosensing.svg'
},
text2speech: {
l10nId: 'project.text2SpeechChip',
icon: 'extension-text2speech.svg'
},
translate: {
l10nId: 'project.translateChip',
icon: 'extension-translate.svg'
}, },
wedo2: { wedo2: {
name: 'LEGO WeDo 2.0', name: 'LEGO WeDo 2.0',
icon: 'extension-wedo2.svg', icon: 'extension-wedo2.svg',
hasStatus: true hasStatus: true
},
ev3: {
name: 'LEGO MINDSTORMS EV3',
icon: 'extension-ev3.svg',
hasStatus: true
},
makeymakey: {
name: 'Makey Makey',
icon: 'extension-makeymakey.svg'
} }
}; };

35
src/lib/project-info.js Normal file
View file

@ -0,0 +1,35 @@
const EXTENSION_INFO = require('./extensions.js').default;
module.exports = {
// Keys match the projectVersion key from project serialization
3: {
extensions: project =>
(project.extensions || []).map(ext => EXTENSION_INFO[ext])
.filter(ext => !!ext), // Only include extensions in the info lib
spriteCount: project =>
project.targets.length - 1, // don't count stage
scriptCount: project => project.targets
.map(target => Object.values(target.blocks))
.reduce((accumulator, currentVal) => accumulator.concat(currentVal), [])
.filter(block => block.topLevel).length,
usernameBlock: project => project.targets
.map(target => Object.values(target.blocks))
.reduce((accumulator, currentVal) => accumulator.concat(currentVal), [])
.some(block => block.opcode === 'sensing_username'),
cloudData: project => {
const stage = project.targets[0];
return Object.values(stage.variables)
.some(variable => variable.length === 3); // 3 entries if cloud var
}
},
2: {
extensions: () => [], // Showing extension chip not implemented for scratch2 projects
spriteCount: project => project.info.spriteCount,
scriptCount: project => project.info.scriptCount,
usernameBlock: project =>
// Block traversing is complicated in scratch2 projects...
// This check should work even if you have sprites named getUserName, etc.
JSON.stringify(project).indexOf('["getUserName"]') !== -1,
cloudData: project => project.info.hasCloudData
}
};

View file

@ -11,12 +11,7 @@ class Storage extends ScratchStorage {
super(); super();
this.addWebSource( this.addWebSource(
[this.AssetType.Project], [this.AssetType.Project],
projectAsset => { projectAsset => `${PROJECT_HOST}/${projectAsset.assetId}`
const [projectId, revision] = projectAsset.assetId.split('.');
return revision ?
`${PROJECT_HOST}/internalapi/project/${projectId}/get/${revision}` :
`${PROJECT_HOST}/internalapi/project/${projectId}/get/`;
}
); );
} }
} }

View file

@ -0,0 +1,15 @@
import bowser from 'bowser';
/**
* Helper function to determine if the browser is supported.
* @returns {boolean} False if the platform is definitely not supported.
*/
export default function () {
if (bowser.msie ||
bowser.vivaldi ||
bowser.opera ||
bowser.silk) {
return false;
}
return true;
}

18
src/lib/user-thumbnail.js Normal file
View file

@ -0,0 +1,18 @@
/**
* @user-thumbnail
* Utility functions to return thumnail-related strings
*/
/**
* Generate a thumbnail url for a particular userid, with width and height.
* @param {string} userId userId for the user whose thumbnail we want
* @param {number} width desired thumbnail width; defaults to 32
* @param {number} height desired thumbnail height; defaults to width.
* @returns {string} thumbnail url string
*/
const thumbnailUrl = (userId, width, height) => (
`${process.env.STATIC_HOST}/get_image/user/${userId || 'default'}_` +
`${width ? width : 32}x${height ? height : (width ? width : 32)}.png`
);
module.exports = thumbnailUrl;

View file

@ -25,6 +25,7 @@ module.exports.getInitialState = () => ({
report: module.exports.Status.NOT_FETCHED, report: module.exports.Status.NOT_FETCHED,
projectStudios: module.exports.Status.NOT_FETCHED, projectStudios: module.exports.Status.NOT_FETCHED,
curatedStudios: module.exports.Status.NOT_FETCHED, curatedStudios: module.exports.Status.NOT_FETCHED,
visibility: module.exports.Status.NOT_FETCHED,
studioRequests: {} studioRequests: {}
}, },
projectInfo: {}, projectInfo: {},
@ -38,7 +39,9 @@ module.exports.getInitialState = () => ({
projectStudios: [], projectStudios: [],
curatedStudios: [], curatedStudios: [],
currentStudioIds: [], currentStudioIds: [],
moreCommentsToLoad: false moreCommentsToLoad: false,
projectNotAvailable: false,
visibilityInfo: {}
}); });
module.exports.previewReducer = (state, action) => { module.exports.previewReducer = (state, action) => {
@ -51,7 +54,12 @@ module.exports.previewReducer = (state, action) => {
return module.exports.getInitialState(); return module.exports.getInitialState();
case 'SET_PROJECT_INFO': case 'SET_PROJECT_INFO':
return Object.assign({}, state, { return Object.assign({}, state, {
projectInfo: action.info projectInfo: action.info ? action.info : {},
projectNotAvailable: !action.info
});
case 'UPDATE_PROJECT_INFO':
return Object.assign({}, state, {
projectInfo: Object.assign({}, state.projectInfo, action.info)
}); });
case 'SET_REMIXES': case 'SET_REMIXES':
return Object.assign({}, state, { return Object.assign({}, state, {
@ -85,6 +93,11 @@ module.exports.previewReducer = (state, action) => {
item !== action.studioId item !== action.studioId
)) ))
}); });
case 'RESET_COMMENTS':
return Object.assign({}, state, {
comments: [],
replies: {}
});
case 'SET_COMMENTS': case 'SET_COMMENTS':
return Object.assign({}, state, { return Object.assign({}, state, {
comments: [...state.comments, ...action.items] // TODO: consider a different way of doing this? comments: [...state.comments, ...action.items] // TODO: consider a different way of doing this?
@ -158,6 +171,10 @@ module.exports.previewReducer = (state, action) => {
return Object.assign({}, state, { return Object.assign({}, state, {
moreCommentsToLoad: action.moreCommentsToLoad moreCommentsToLoad: action.moreCommentsToLoad
}); });
case 'SET_VISIBILITY_INFO':
return Object.assign({}, state, {
visibilityInfo: action.visibilityInfo
});
case 'ERROR': case 'ERROR':
log.error(action.error); log.error(action.error);
return state; return state;
@ -180,6 +197,11 @@ module.exports.setProjectInfo = info => ({
info: info info: info
}); });
module.exports.updateProjectInfo = info => ({
type: 'UPDATE_PROJECT_INFO',
info: info
});
module.exports.setOriginalInfo = info => ({ module.exports.setOriginalInfo = info => ({
type: 'SET_ORIGINAL', type: 'SET_ORIGINAL',
info: info info: info
@ -301,6 +323,15 @@ module.exports.setMoreCommentsToLoad = moreCommentsToLoad => ({
moreCommentsToLoad: moreCommentsToLoad moreCommentsToLoad: moreCommentsToLoad
}); });
module.exports.resetComments = () => ({
type: 'RESET_COMMENTS'
});
module.exports.setVisibilityInfo = visibilityInfo => ({
type: 'SET_VISIBILITY_INFO',
visibilityInfo: visibilityInfo
});
module.exports.getProjectInfo = (id, token) => (dispatch => { module.exports.getProjectInfo = (id, token) => (dispatch => {
const opts = { const opts = {
uri: `/projects/${id}` uri: `/projects/${id}`
@ -309,19 +340,41 @@ module.exports.getProjectInfo = (id, token) => (dispatch => {
Object.assign(opts, {authentication: token}); Object.assign(opts, {authentication: token});
} }
dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHING)); dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHING));
api(opts, (err, body) => { api(opts, (err, body, response) => {
if (err) { if (err) {
dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR)); dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR));
dispatch(module.exports.setError(err)); dispatch(module.exports.setError(err));
return; return;
} }
if (typeof body === 'undefined') { if (typeof body === 'undefined' || response.statusCode === 404) {
dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR)); dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR));
dispatch(module.exports.setError('No project info')); dispatch(module.exports.setError('No project info'));
dispatch(module.exports.setProjectInfo(null));
return; return;
} }
dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHED)); dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHED));
dispatch(module.exports.setProjectInfo(body)); dispatch(module.exports.setProjectInfo(body));
// If the project is not public, make a follow-up request for why
if (!body.public) {
dispatch(module.exports.getVisibilityInfo(id, body.author.username, token));
}
});
});
module.exports.getVisibilityInfo = (id, ownerUsername, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('visibility', module.exports.Status.FETCHING));
api({
uri: `/users/${ownerUsername}/projects/${id}/visibility`,
authentication: token
}, (err, body, response) => {
if (err || !body || response.statusCode !== 200) {
dispatch(module.exports.setFetchStatus('visibility', module.exports.Status.ERROR));
dispatch(module.exports.setError('No visibility info available'));
return;
}
dispatch(module.exports.setFetchStatus('visibility', module.exports.Status.FETCHED));
dispatch(module.exports.setVisibilityInfo(body));
}); });
}); });
@ -341,6 +394,10 @@ module.exports.getOriginalInfo = id => (dispatch => {
return; return;
} }
dispatch(module.exports.setFetchStatus('original', module.exports.Status.FETCHED)); dispatch(module.exports.setFetchStatus('original', module.exports.Status.FETCHED));
if (body && body.code === 'NotFound') {
dispatch(module.exports.setOriginalInfo({}));
return;
}
dispatch(module.exports.setOriginalInfo(body)); dispatch(module.exports.setOriginalInfo(body));
}); });
}); });
@ -361,6 +418,10 @@ module.exports.getParentInfo = id => (dispatch => {
return; return;
} }
dispatch(module.exports.setFetchStatus('parent', module.exports.Status.FETCHED)); dispatch(module.exports.setFetchStatus('parent', module.exports.Status.FETCHED));
if (body && body.code === 'NotFound') {
dispatch(module.exports.setParentInfo({}));
return;
}
dispatch(module.exports.setParentInfo(body)); dispatch(module.exports.setParentInfo(body));
}); });
}); });
@ -420,7 +481,7 @@ module.exports.getTopLevelComments = (id, offset, isAdmin, token) => (dispatch =
module.exports.getCommentById = (projectId, commentId, isAdmin, token) => (dispatch => { module.exports.getCommentById = (projectId, commentId, isAdmin, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('comments', module.exports.Status.FETCHING)); dispatch(module.exports.setFetchStatus('comments', module.exports.Status.FETCHING));
api({ api({
uri: `${isAdmin ? '/admin' : ''}/projects/comments/${commentId}`, uri: `${isAdmin ? '/admin' : ''}/projects/${projectId}/comments/${commentId}`,
authentication: isAdmin ? token : null authentication: isAdmin ? token : null
}, (err, body) => { }, (err, body) => {
if (err) { if (err) {
@ -701,9 +762,9 @@ module.exports.updateProject = (id, jsonData, username, token) => (dispatch => {
dispatch(module.exports.setError('No project info')); dispatch(module.exports.setError('No project info'));
return; return;
} }
if (res.statusCode === 500) { // InternalServer if (res.statusCode >= 400) { // API responding with error
dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR)); dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR));
dispatch(module.exports.setError('API Internal Server Error')); dispatch(module.exports.setError('API Error Response'));
return; return;
} }
dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHED)); dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHED));
@ -767,6 +828,25 @@ module.exports.restoreComment = (projectId, commentId, topLevelCommentId, token)
}); });
}); });
module.exports.shareProject = (projectId, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHING));
api({
uri: `/proxy/projects/${projectId}/share`,
authentication: token,
withCredentials: true,
method: 'PUT',
useCsrf: true
}, (err, body, res) => {
if (err || res.statusCode !== 200) {
dispatch(module.exports.setFetchStatus('project', module.exports.Status.ERROR));
dispatch(module.exports.setError(err));
return;
}
dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHED));
dispatch(module.exports.updateProjectInfo(body));
});
});
module.exports.reportProject = (id, jsonData, token) => (dispatch => { module.exports.reportProject = (id, jsonData, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('report', module.exports.Status.FETCHING)); dispatch(module.exports.setFetchStatus('report', module.exports.Status.FETCHING));
// scratchr2 will fail if no thumbnail base64 string provided. We don't yet have // scratchr2 will fail if no thumbnail base64 string provided. We don't yet have
@ -791,3 +871,41 @@ module.exports.reportProject = (id, jsonData, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('report', module.exports.Status.FETCHED)); dispatch(module.exports.setFetchStatus('report', module.exports.Status.FETCHED));
}); });
}); });
module.exports.updateProjectThumbnail = (id, blob) => (dispatch => {
dispatch(module.exports.setFetchStatus('project-thumbnail', module.exports.Status.FETCHING));
api({
uri: `/internalapi/project/thumbnail/${id}/set/`,
method: 'POST',
headers: {
'Content-Type': 'image/png'
},
withCredentials: true,
useCsrf: true,
body: blob,
host: '' // Not handled by the API, use existing infrastructure
}, (err, body, res) => {
if (err || res.statusCode !== 200) {
dispatch(module.exports.setFetchStatus('project-thumbnail', module.exports.Status.ERROR));
return;
}
dispatch(module.exports.setFetchStatus('project-thumbnail', module.exports.Status.FETCHED));
});
});
module.exports.logProjectView = (id, authorUsername, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('project-log-view', module.exports.Status.FETCHING));
api({
uri: `/users/${authorUsername}/projects/${id}/views`,
method: 'POST',
authentication: token,
withCredentials: true,
useCsrf: true
}, (err, body, res) => {
if (err || res.statusCode !== 200) {
dispatch(module.exports.setFetchStatus('project-log-view', module.exports.Status.ERROR));
return;
}
dispatch(module.exports.setFetchStatus('project-log-view', module.exports.Status.FETCHED));
});
});

View file

@ -13,13 +13,6 @@
"view": "camp/camp", "view": "camp/camp",
"title": "Down Deep" "title": "Down Deep"
}, },
{
"name": "cards",
"pattern": "^/info/cards/?$",
"routeAlias": "/info/(cards|communityblocks-interviews|credits|faq)/?$",
"view": "cards/cards",
"title": "Cards"
},
{ {
"name": "communityblocks-interviews", "name": "communityblocks-interviews",
"pattern": "^/info/communityblocks-interviews/?$", "pattern": "^/info/communityblocks-interviews/?$",
@ -87,7 +80,7 @@
}, },
{ {
"name": "credits", "name": "credits",
"pattern": "^/info/credits/?$", "pattern": "^/credits/?$",
"routeAlias": "/info/(cards|communityblocks-interviews|credits|faq|donate)/?$", "routeAlias": "/info/(cards|communityblocks-interviews|credits|faq|donate)/?$",
"view": "credits/credits", "view": "credits/credits",
"title": "Credits" "title": "Credits"
@ -108,7 +101,7 @@
}, },
{ {
"name": "download", "name": "download",
"pattern": "^/download/?$", "pattern": "^/download/?(.+)?$",
"routeAlias": "/download", "routeAlias": "/download",
"view": "download/download", "view": "download/download",
"title": "Scratch Offline Editor" "title": "Scratch Offline Editor"
@ -129,7 +122,7 @@
}, },
{ {
"name": "faq", "name": "faq",
"pattern": "^/info/faq/?$", "pattern": "^/info/faq/?(.+)?$",
"routeAlias": "/info/(cards|communityblocks-interviews|credits|faq)/?$", "routeAlias": "/info/(cards|communityblocks-interviews|credits|faq)/?$",
"view": "faq/faq", "view": "faq/faq",
"title": "FAQ" "title": "FAQ"
@ -141,6 +134,13 @@
"view": "guidelines/guidelines", "view": "guidelines/guidelines",
"title": "Scratch Community Guidelines" "title": "Scratch Community Guidelines"
}, },
{
"name": "ideas",
"pattern": "^/ideas/?(\\?.*)?$",
"routeAlias": "/ideas/?\\??",
"view": "ideas/ideas",
"title": "Ideas"
},
{ {
"name": "jobs", "name": "jobs",
"pattern": "^/jobs/?$", "pattern": "^/jobs/?$",
@ -163,53 +163,19 @@
"title": "Messages" "title": "Messages"
}, },
{ {
"name": "microworld-art", "name": "projects",
"pattern": "^/microworlds/art", "pattern": "^/projects(/editor|(/\\d+(/editor|/fullscreen|/embed)?)?)?/?(\\?.*)?$",
"routeAlias": "/microworlds", "routeAlias": "/projects/?$",
"view": "microworld/art/art",
"title": "Art"
},
{
"name": "microworld-fashion",
"pattern": "^/microworlds/fashion",
"routeAlias": "/microworlds",
"view": "microworld/fashion/fashion",
"title": "Fashion"
},
{
"name": "microworld-hiphop",
"pattern": "^/microworlds/hiphop",
"routeAlias": "/microworlds",
"view": "microworld/hiphop/hiphop",
"title": "Hip Hop Dance"
},
{
"name": "microworld-soccer",
"pattern": "^/microworlds/soccer",
"routeAlias": "/microworlds",
"view": "microworld/soccer/soccer",
"title": "Soccer"
},
{
"name": "microworlds-homepage",
"pattern": "^/microworlds/go/?(\\?.*)?$",
"routeAlias": "/microworlds",
"view": "microworldshomepage/microworldshomepage",
"title": "Microworlds"
},
{
"name": "preview",
"pattern": "^/preview(/editor|(/\\d+(/editor|/fullscreen)?)?)?/?$",
"routeAlias": "/preview/?$",
"view": "preview/preview", "view": "preview/preview",
"title": "Scratch 3.0 Preview" "title": "Scratch Project",
"dynamicMetaTags": true
}, },
{ {
"name": "3faq", "name": "parents",
"pattern": "^/3faq/?$", "pattern": "^/parents/?$",
"routeAlias": "/3faq/?$", "routeAlias": "/parents/",
"view": "preview-faq/preview-faq", "view": "parents/parents",
"title": "Scratch 3.0 FAQ" "title": "For Parents"
}, },
{ {
"name": "preview-faq-redirect", "name": "preview-faq-redirect",
@ -231,6 +197,20 @@
"view": "research/research", "view": "research/research",
"title": "Research" "title": "Research"
}, },
{
"name": "scratch_1.4",
"pattern": "^/scratch_1.4/?$",
"routeAlias": "/scratch_1.4",
"view": "scratch_1.4/scratch_1.4",
"title": "Scratch 1.4"
},
{
"name": "scratch2",
"pattern": "^/download/scratch2/?$",
"routeAlias": "/download/scratch2",
"view": "download/scratch2/download",
"title": "Scratch 2.0"
},
{ {
"name": "search", "name": "search",
"pattern": "^/search/:projects/?$", "pattern": "^/search/:projects/?$",
@ -287,13 +267,6 @@
"view": "terms/terms", "view": "terms/terms",
"title": "Scratch Terms of Use" "title": "Scratch Terms of Use"
}, },
{
"name": "tips",
"pattern": "^/tips/?(\\?.*)?$",
"routeAlias": "/tips/?\\??",
"view": "tips/tips",
"title": "Tips"
},
{ {
"name": "wedo2", "name": "wedo2",
"pattern": "^/wedo/?$", "pattern": "^/wedo/?$",
@ -302,7 +275,7 @@
"title": "LEGO WeDo 2.0" "title": "LEGO WeDo 2.0"
}, },
{ {
"name": "wedo-legacy", "name": "wedo2-legacy",
"pattern": "^/wedo-legacy/?$", "pattern": "^/wedo-legacy/?$",
"routeAlias": "/wedo-legacy/?$", "routeAlias": "/wedo-legacy/?$",
"view": "wedo2-legacy/wedo2", "view": "wedo2-legacy/wedo2",
@ -322,6 +295,18 @@
"view": "microbit/microbit", "view": "microbit/microbit",
"title": "micro:bit" "title": "micro:bit"
}, },
{
"name":"3-faq-redirect",
"pattern": "^/3faq/?$",
"routeAlias": "/3faq/?$",
"redirect": "info/faq#scratch3"
},
{
"name" : "credits-redirect",
"pattern": "^/info/credits/?$",
"routeAlias": "/info/(cards|communityblocks-interviews|credits|faq|donate)/?$",
"redirect" : "/credits"
},
{ {
"name": "donate-redirect", "name": "donate-redirect",
"pattern": "^/info/donate/?", "pattern": "^/info/donate/?",
@ -358,29 +343,34 @@
"routeAlias": "/explore(?!/ajax)", "routeAlias": "/explore(?!/ajax)",
"redirect": "/explore/studios/all" "redirect": "/explore/studios/all"
}, },
{
"name": "info-cards-redirect",
"pattern": "^/info/cards/?$",
"redirect": "/ideas"
},
{ {
"name": "help-redirect", "name": "help-redirect",
"pattern": "^/help/?(\\?.*)?$", "pattern": "^/help/?(\\?.*)?$",
"routeAlias": "/help/?(\\?.*)?$", "routeAlias": "/help/?(\\?.*)?$",
"redirect": "/tips" "redirect": "/ideas"
}, },
{ {
"name": "hoc-redirect", "name": "hoc-redirect",
"pattern": "^/hoc/?(\\?.*)?$", "pattern": "^/hoc/?(\\?.*)?$",
"routeAlias": "/hoc/?\\??", "routeAlias": "/hoc/?\\??",
"redirect": "/tips" "redirect": "/ideas"
}, },
{ {
"name": "hoc2014-redirect", "name": "hoc2014-redirect",
"pattern": "^/hoc2014/?(\\?.*)?$", "pattern": "^/hoc2014/?(\\?.*)?$",
"routeAlias": "/hoc2014/?\\??", "routeAlias": "/hoc2014/?\\??",
"redirect": "/tips" "redirect": "/ideas"
}, },
{ {
"name": "info-redirect", "name": "info-redirect",
"pattern": "^/info/?(\\?.*)?$", "pattern": "^/info/?(\\?.*)?$",
"routeAlias": "/info/?(\\?.*)?$", "routeAlias": "/info/?(\\?.*)?$",
"redirect": "/tips" "redirect": "/ideas"
}, },
{ {
"name": "research-redirect", "name": "research-redirect",
@ -405,10 +395,158 @@
"routeAlias": "/store", "routeAlias": "/store",
"redirect": "https://scratch-foundation.myshopify.com" "redirect": "https://scratch-foundation.myshopify.com"
}, },
{
"name": "tips-redirect",
"pattern": "^/tips/?(\\?.*)?$",
"routeAlias": "/tips/?\\??",
"redirect": "/ideas"
},
{ {
"name": "things-to-try-redirect", "name": "things-to-try-redirect",
"pattern": "^/go/?(\\?.*)?$", "pattern": "^/go/?(\\?.*)?$",
"routeAlias": "/go/?\\??", "routeAlias": "/go/?\\??",
"redirect": "/tips" "redirect": "/ideas"
},
{
"name": "create-tutorial-redirect",
"pattern": "^/create/?$",
"redirect": "/projects/editor/?tutorial=getStarted"
},
{
"name": "name-tutorial-redirect",
"pattern": "^/name/?$",
"redirect": "/projects/editor/?tutorial=name"
},
{
"name": "music-tutorial-redirect",
"pattern": "^/music/?$",
"redirect": "/projects/editor/?tutorial=music"
},
{
"name": "story-tutorial-redirect",
"pattern": "^/story/?$",
"redirect": "/projects/editor/?tutorial=story"
},
{
"name": "pong-tutorial-redirect",
"pattern": "^/pong/?$",
"redirect": "/projects/editor/?tutorial=pong"
},
{
"name": "clicker-tutorial-redirect",
"pattern": "^/clicker/?$",
"redirect": "/projects/editor/?tutorial=clicker-game"
},
{
"name": "chase-tutorial-redirect",
"pattern": "^/chase/?$",
"redirect": "/projects/editor/?tutorial=chase-game"
},
{
"name": "jazz-tutorial-redirect",
"pattern": "^/jazz/?$",
"redirect": "/projects/editor/?tutorial=music"
},
{
"name": "catch-tutorial-redirect",
"pattern": "^/catch/?$",
"redirect": "/ideas"
},
{
"name": "dance-tutorial-redirect",
"pattern": "^/dance/?$",
"redirect": "/ideas"
},
{
"name": "fly-tutorial-redirect",
"pattern": "^/fly/?$",
"routeAlias": "/(makeit)?fly/?$",
"redirect": "/ideas"
},
{
"name": "makeitfly-tutorial-redirect",
"pattern": "^/makeitfly/?$",
"routeAlias": "/(makeit)?fly/?$",
"redirect": "/ideas"
},
{
"name": "pet-tutorial-redirect",
"pattern": "^/pet/?$",
"redirect": "/ideas"
},
{
"name": "racegame-tutorial-redirect",
"pattern": "^/racegame/?$",
"redirect": "/ideas"
},
{
"name": "hide-tutorial-redirect",
"pattern": "^/hide/?$",
"redirect": "/ideas"
},
{
"name": "fashion-tutorial-redirect",
"pattern": "^/fashion/?$",
"redirect": "/ideas"
},
{
"name": "dressup-tutorial-redirect",
"pattern": "^/dressup/?$",
"redirect": "/ideas"
},
{
"name": "card-tutorial-redirect",
"pattern": "^/card/?$",
"redirect": "/ideas"
},
{
"name": "valentines-tutorial-redirect",
"pattern": "^/valentines/?$",
"redirect": "/ideas"
},
{
"name": "bearstack-tutorial-redirect",
"pattern": "^/bearstack/?$",
"redirect": "/ideas"
},
{
"name": "favorite-tutorial-redirect",
"pattern": "^/favorite/?$",
"redirect": "/ideas"
},
{
"name": "hoops-tutorial-redirect",
"pattern": "^/hoops/?$",
"redirect": "/ideas"
},
{
"name": "soccer-tutorial-redirect",
"pattern": "^/soccer/?$",
"redirect": "/ideas"
},
{
"name": "codeweek-tutorial-redirect",
"pattern": "^/codeweekeu/?$",
"redirect": "/ideas"
},
{
"name": "madewithcode-tutorial-redirects",
"pattern": "^/madewithcode-(name|card)/?$",
"redirect": "/ideas"
},
{
"name": "odetocode-tutorial-redirect",
"pattern": "^/odetocode/?$",
"redirect": "/ideas"
},
{
"name": "makey-tutorial-redirects",
"pattern": "^/makey(piano|drum)?/?$",
"redirect": "/ideas"
},
{
"name": "bird-redirect",
"pattern": "^/bird/?$",
"redirect": "/ideas"
} }
] ]

View file

@ -8,23 +8,25 @@
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=<%= htmlWebpackPlugin.options.viewportWidth %>, initial-scale=1"> <meta name="viewport" content="width=<%= htmlWebpackPlugin.options.viewportWidth %>, initial-scale=1">
<title>Scratch - <%= htmlWebpackPlugin.options.title %></title>
<!-- Prevent mobile Safari from making phone numbers --> <!-- Prevent mobile Safari from making phone numbers -->
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<!-- Search & Open Graph--> <% if (!htmlWebpackPlugin.options.dynamicMetaTags) { %>
<meta name="description" content="<%= htmlWebpackPlugin.options.description %>" /> <title>Scratch - <%= htmlWebpackPlugin.options.title %></title>
<meta name="google-site-verification" content="m_3TAXDreGTFyoYnEmU9mcKB4Xtw5mw6yRkuJtXRKxM" />
<meta property="og:url" content="https://scratch.mit.edu/" /> <!-- Search & Open Graph-->
<meta property="og:type" content="website" /> <meta name="description" content="<%= htmlWebpackPlugin.options.description %>" />
<meta property="og:title" content="Scratch - <%= htmlWebpackPlugin.options.title %>" /> <meta name="google-site-verification" content="m_3TAXDreGTFyoYnEmU9mcKB4Xtw5mw6yRkuJtXRKxM" />
<meta property="og:description" content="<%= htmlWebpackPlugin.options.description %>" />
<meta property="og:image" content="<%- htmlWebpackPlugin.options.og_image %>" /> <meta property="og:url" content="https://scratch.mit.edu/" />
<meta property="og:image:type" content="<%- htmlWebpackPlugin.options.og_image_type %>" /> <meta property="og:type" content="website" />
<meta property="og:image:width" content="<%- htmlWebpackPlugin.options.og_image_width %>" /> <meta property="og:title" content="Scratch - <%= htmlWebpackPlugin.options.title %>" />
<meta property="og:image:height" content="<%- htmlWebpackPlugin.options.og_image_height %>" /> <meta property="og:description" content="<%= htmlWebpackPlugin.options.description %>" />
<meta property="og:image" content="<%- htmlWebpackPlugin.options.og_image %>" />
<meta property="og:image:type" content="<%- htmlWebpackPlugin.options.og_image_type %>" />
<meta property="og:image:width" content="<%- htmlWebpackPlugin.options.og_image_width %>" />
<meta property="og:image:height" content="<%- htmlWebpackPlugin.options.og_image_height %>" />
<% } %>
<!-- Favicon & CSS normalize --> <!-- Favicon & CSS normalize -->
<link rel="shortcut icon" href="/favicon.ico" /> <link rel="shortcut icon" href="/favicon.ico" />
@ -45,6 +47,7 @@
'sampleRate': 10 'sampleRate': 10
}); });
ga('send', 'pageview'); ga('send', 'pageview');
window.GA_ID = '<%- htmlWebpackPlugin.options.ga_tracker %>';
/* eslint-enable */ /* eslint-enable */
</script> </script>
</head> </head>
@ -60,19 +63,21 @@
<script src="/<%= htmlWebpackPlugin.files.chunks[htmlWebpackPlugin.options.route.name].entry %>"></script> <script src="/<%= htmlWebpackPlugin.files.chunks[htmlWebpackPlugin.options.route.name].entry %>"></script>
<!-- Translate title element --> <!-- Translate title element -->
<script> <% if (!htmlWebpackPlugin.options.dynamicMetaTags) { %>
var loc = window._locale || 'en'; <script>
if (typeof window._messages !== 'undefined' && loc !== 'en') { var loc = window._locale || 'en';
if (typeof window._messages[loc] === 'undefined') { if (typeof window._messages !== 'undefined' && loc !== 'en') {
loc = loc.split('-')[0]; if (typeof window._messages[loc] === 'undefined') {
} loc = loc.split('-')[0];
if (typeof window._messages[loc] !== 'undefined') { }
var localizedTitle = window._messages[loc]['general.' + '<%= htmlWebpackPlugin.options.title %>'.toLowerCase()] || ''; if (typeof window._messages[loc] !== 'undefined') {
if (localizedTitle.length > 0) { var localizedTitle = window._messages[loc]['general.' + '<%= htmlWebpackPlugin.options.title %>'.toLowerCase()] || '';
document.title = 'Scratch - ' + localizedTitle; if (localizedTitle.length > 0) {
document.title = 'Scratch - ' + localizedTitle;
}
} }
} }
} </script>
</script> <% } %>
</body> </body>
</html> </html>

View file

@ -1,480 +0,0 @@
const bindAll = require('lodash.bindall');
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const FormattedMessage = require('react-intl').FormattedMessage;
const React = require('react');
const render = require('../../lib/render.jsx');
const Box = require('../../components/box/box.jsx');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const Page = require('../../components/page/www/page.jsx');
require('./cards.scss');
class Cards extends React.Component {
constructor (props) {
super(props);
bindAll([
'pdfLocaleMismatch'
]);
}
pdfLocaleMismatch (locale, pdf, englishPdf) {
if (pdf === englishPdf && locale.indexOf('en') !== 0) {
return true;
}
return false;
}
render () {
const locale = this.props.intl.locale || 'en';
const formatMessage = this.props.intl.formatMessage;
const englishLinks = {
'cards.starterLink': 'https://resources.scratch.mit.edu/www/cards/en/Scratch2Cards.pdf',
'cards.nameLink': 'https://resources.scratch.mit.edu/www/cards/en/nameCards.pdf',
'cards.flyLink': 'https://resources.scratch.mit.edu/www/cards/en/flyCards.pdf',
'cards.raceLink': 'https://resources.scratch.mit.edu/www/cards/en/raceCards.pdf',
'cards.musicLink': 'https://resources.scratch.mit.edu/www/cards/en/musicCards.pdf',
'cards.hideLink': 'https://resources.scratch.mit.edu/www/cards/en/hide-seekCards.pdf',
'cards.storyLink': 'https://resources.scratch.mit.edu/www/cards/en/storyCards.pdf',
'cards.dressupLink': 'https://resources.scratch.mit.edu/www/cards/en/fashionCards.pdf',
'cards.pongLink': 'https://resources.scratch.mit.edu/www/cards/en/pongCards.pdf',
'cards.danceLink': 'https://resources.scratch.mit.edu/www/cards/en/danceCards.pdf',
'cards.catchLink': 'https://resources.scratch.mit.edu/www/cards/en/catchCards.pdf',
'cards.petLink': 'https://resources.scratch.mit.edu/www/cards/en/petCards.pdf'
};
const formattedLinks = {
'cards.starterLink': formatMessage({id: 'cards.Scratch2CardsLink'}),
'cards.nameLink': formatMessage({id: 'cards.nameCardsLink'}),
'cards.flyLink': formatMessage({id: 'cards.flyCardsLink'}),
'cards.raceLink': formatMessage({id: 'cards.raceCardsLink'}),
'cards.musicLink': formatMessage({id: 'cards.musicCardsLink'}),
'cards.hideLink': formatMessage({id: 'cards.hide-seekCardsLink'}),
'cards.storyLink': formatMessage({id: 'cards.storyCardsLink'}),
'cards.dressupLink': formatMessage({id: 'cards.fashionCardsLink'}),
'cards.pongLink': formatMessage({id: 'cards.pongCardsLink'}),
'cards.danceLink': formatMessage({id: 'cards.danceCardsLink'}),
'cards.catchLink': formatMessage({id: 'cards.catchCardsLink'}),
'cards.petLink': formatMessage({id: 'cards.petCardsLink'})
};
/* eslint-disable indent */
return (
<div className="inner cards">
<div className="cards-intro">
<div className="cards-intro-content">
<h1 className="cards-intro-content-header">
<FormattedMessage id="cards.introHeader" />
</h1>
<p className="cards-intro-content-body">
<FormattedMessage id="cards.introContent" />
</p>
</div>
<img
alt="Card Use Explanation"
className="cards-intro-img"
src="/images/cards/card-use-overview.png"
/>
</div>
<div className="cards-container">
<Box title={''}>
<FlexRow>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.starter" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.starterLink']}
>
<img
alt=""
src="/images/cards/cards-starter.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.starterLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.starterLink'],
englishLinks['cards.starterLink']
)) ? [
<span key="english-cards">
<FormattedMessage id="cards.english" />
</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.name" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.nameLink']}
>
<img
alt=""
src="/images/cards/cards-name.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.nameLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.nameLink'],
englishLinks['cards.nameLink']
)) ? [
<span key="name-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.fly" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.flyLink']}
>
<img
alt=""
src="/images/cards/cards-fly.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.flyLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.flyLink'],
englishLinks['cards.flyLink']
)) ? [
<span key="fly-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.race" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.raceLink']}
>
<img
alt=""
src="/images/cards/cards-race.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.raceLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.raceLink'],
englishLinks['cards.raceLink']
)) ? [
<span key="race-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.music" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.musicLink']}
>
<img
alt=""
src="/images/cards/cards-music.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.musicLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.musicLink'],
englishLinks['cards.musicLink']
)) ? [
<span key="music-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.hide" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.hideLink']}
>
<img
alt=""
src="/images/cards/cards-hide.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.hideLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.hideLink'],
englishLinks['cards.hideLink']
)) ? [
<span key="hide-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.story" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.storyLink']}
>
<img
alt=""
src="/images/cards/cards-story.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.storyLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.storyLink'],
englishLinks['cards.storyLink']
)) ? [
<span key="story-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.dressup" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.dressupLink']}
>
<img
alt=""
src="/images/cards/cards-dressup.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.dressupLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.dressupLink'],
englishLinks['cards.dressupLink']
)) ? [
<span key="dress-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.pong" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.pongLink']}
>
<img
alt=""
src="/images/cards/cards-pong.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.pongLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.pongLink'],
englishLinks['cards.pongLink']
)) ? [
<span key="pong-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.dance" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.danceLink']}
>
<img
alt=""
src="/images/cards/cards-dance.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.danceLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.danceLink'],
englishLinks['cards.danceLink']
)) ? [
<span key="dance-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.catch" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.catchLink']}
>
<img
alt=""
src="/images/cards/cards-catch.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.catchLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.catchLink'],
englishLinks['cards.catchLink']
)) ? [
<span key="catch-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
<div className="flex-row-card">
<h4 className="flex-row-card-header">
<FormattedMessage id="cards.pet" />
</h4>
<a
className="flex-row-card-link"
href={formattedLinks['cards.petLink']}
>
<img
alt=""
src="/images/cards/cards-pet.jpg"
/>
</a>
<a
className="flex-row-card-link"
href={formattedLinks['cards.petLink']}
>
<img
alt=""
className="flex-row-card-link-icon"
src="/svgs/pdf-icon-ui-blue.svg"
/>
<FormattedMessage id="cards.viewCard" />
{(this.pdfLocaleMismatch(
locale,
formattedLinks['cards.petLink'],
englishLinks['cards.petLink']
)) ? [
<span key="pet-link"> (<FormattedMessage id="cards.english" />)</span>
] : []}
</a>
</div>
</FlexRow>
</Box>
</div>
</div>
);
}
}
Cards.propTypes = {
intl: intlShape
};
const LocalizedCards = injectIntl(Cards);
render(<Page><LocalizedCards /></Page>, document.getElementById('app'));

View file

@ -1,47 +0,0 @@
@import "../../colors";
@import "../../frameless";
// Page header
.cards-intro {
display: flex;
margin: 1rem 0;
align-items: center;
justify-content: space-between;
}
.cards-intro-content {
float: left;
width: 45%;
}
.cards-intro-content-header {
margin: .75rem 0 .5rem;
}
.cards-intro-content-body {
margin: .25rem 0 1rem;
}
.cards-intro-img {
width: 45%;
}
// Cards and Card Container
.cards-container {
text-align: center;
}
.flex-row-card {
margin: 1.5rem 0;
padding: .5rem;
}
.flex-row-card-link {
display: block;
margin-top: .5rem;
}
.flex-row-card-link-icon {
margin-right: .2rem;
width: 1rem;
}

View file

@ -1,15 +0,0 @@
{
"cards.Scratch2CardsLink": "https://resources.scratch.mit.edu/www/cards/en/Scratch2Cards.pdf",
"cards.catchCardsLink": "https://resources.scratch.mit.edu/www/cards/en/catchCards.pdf",
"cards.danceCardsLink": "https://resources.scratch.mit.edu/www/cards/en/danceCards.pdf",
"cards.dressupCardsLink": "https://resources.scratch.mit.edu/www/cards/en/dressupCards.pdf",
"cards.fashionCardsLink": "https://resources.scratch.mit.edu/www/cards/en/fashionCards.pdf",
"cards.flyCardsLink": "https://resources.scratch.mit.edu/www/cards/en/flyCards.pdf",
"cards.hide-seekCardsLink": "https://resources.scratch.mit.edu/www/cards/en/hide-seekCards.pdf",
"cards.musicCardsLink": "https://resources.scratch.mit.edu/www/cards/en/musicCards.pdf",
"cards.nameCardsLink": "https://resources.scratch.mit.edu/www/cards/en/nameCards.pdf",
"cards.petCardsLink": "https://resources.scratch.mit.edu/www/cards/en/petCards.pdf",
"cards.pongCardsLink": "https://resources.scratch.mit.edu/www/cards/en/pongCards.pdf",
"cards.raceCardsLink": "https://resources.scratch.mit.edu/www/cards/en/raceCards.pdf",
"cards.storyCardsLink": "https://resources.scratch.mit.edu/www/cards/en/storyCards.pdf"
}

View file

@ -1,19 +0,0 @@
{
"cards.introHeader": "Scratch Cards",
"cards.introContent": "Scratch cards provide a quick way to learn new Scratch code.",
"cards.english": "English",
"cards.introWikiSupport": "Looking for Scratch Cards in your language? Check <a href=\"http://wiki.scratch.mit.edu/wiki/Scratch_Support_Materials\">Scratch Wiki</a>.",
"cards.viewCard": "View Cards",
"cards.starter": "Starter Cards",
"cards.name": "Animate Your Name",
"cards.fly": "Make It Fly",
"cards.race": "Race to the Finish",
"cards.music": "Make Music",
"cards.hide": "Hide and Seek",
"cards.story": "Create a Story",
"cards.dressup": "Fashion Game",
"cards.pong": "Pong Game",
"cards.dance": "Let's Dance",
"cards.catch": "Catch Game",
"cards.pet": "Virtual Pet"
}

View file

@ -1,459 +1,191 @@
const React = require('react'); const React = require('react');
const render = require('../../lib/render.jsx'); const render = require('../../lib/render.jsx');
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage; const FormattedMessage = require('react-intl').FormattedMessage;
const injectIntl = require('react-intl').injectIntl;
const Avatar = require('../../components/avatar/avatar.jsx');
const Page = require('../../components/page/www/page.jsx'); const Page = require('../../components/page/www/page.jsx');
const People = require('./people.json');
const Supporters = require('./supporters.json');
const TitleBanner = require('../../components/title-banner/title-banner.jsx');
require('./credits.scss'); require('./credits.scss');
const Credits = () => ( const Credits = () => (
<div className="inner credits"> <div className="credits">
<h1><FormattedMessage id="credits.title" /></h1> <TitleBanner className="masthead mod-blue-bg">
<h2>MIT Scratch Team</h2> <h1 className="title-banner-h1">
<p><FormattedMessage id="credits.developers" /></p> <FormattedMessage id="credits.title" />
</h1>
</TitleBanner>
<div className="content">
<div className="people">
<div className="mid-header">
<h2>MIT Scratch Team</h2>
<p>
<FormattedMessage id="credits.developers" />
</p>
</div>
<ul className="avatar-grid">
{People.map((person, index) => (
<li
className="avatar-item"
key={`person-${index}`}
>
<div>
<a href={`https://scratch.mit.edu/users/${person.userName}/`}>
<Avatar
alt=""
src={`https://cdn.scratch.mit.edu/get_image/user/${person.userId || 'default'}_80x80.png`}
/>
</a>
</div>
<span className="avatar-text">
{person.name}
</span>
</li>
))}
</ul>
</div>
<div className="supporters">
<div className="mid-header">
<h2>
<FormattedMessage id="credits.currentSponsors" />
</h2>
<p>
<FormattedMessage id="credits.currentFinancialSupport" />
</p>
</div>
<div className="logo-grid">
{Supporters.map((supporter, index) => (
<span
className="logo"
key={`logo-${index}`}
>
<a href={supporter.logoDestination}>
{supporter.logoSrc ? (
<img
alt=""
src={supporter.logoSrc}
width={supporter.width}
/>
) :
<div className="text-logo">
{supporter.textLogo}
</div>
}
</a>
</span>
))}
</div>
</div>
<div className="acknowledge-content">
<h2>
<FormattedMessage id="credits.translationsTitle" />
</h2>
<p>
<FormattedMessage
id="credits.acknowledgementsTranslators"
values={{
translatorsLink: (
<a href="http://wiki.scratch.mit.edu/wiki/Translators">
<FormattedMessage id="credits.acknowledgementsTranslatorsLinkText" />
</a>
)
}}
/>
</p>
<h2>
<FormattedMessage id="credits.illustrationsTitle" />
</h2>
<p>
<FormattedMessage id="credits.acknowledgementsIllustrations" />
</p>
<p>
Natalie Rosalinda Hall, Wren McDonald, Leigh McG, Andrew Rae, Daria Skrybchenko,
Robert Hunter, Alex Eben Meyer, Ding Ding Hu, Owen Davey.
</p>
<h2>
<FormattedMessage id="credits.pastContributors" />
</h2>
<p>
<FormattedMessage id="credits.pastContributorsThanks" />
</p>
<p>
<FormattedMessage id="credits.otherContributors" />
{' '}
Ben Berg, Amos Blanton, Karen Brennan, Juanita Buitrago, Leo Burd,
Gaia Carini, Kasia Chmielinski, Michelle Chung, Shane Clements,
Hannah Cole, Sayamindu Dasgupta, Margarita Dekoli, Evelyn Eastmond,
Dave Feinberg, Chris Graves, Megan Haddadi, Connor Hudson,
Christina Huang, Tony Hwang, Abdulrahman Idlbi, Randy Jou, Lily Kim,
Tauntaun Kim, Saskia Leggett, Tim Mickel, Amon Millner, Ricarose Roque,
Andrea Saxman, Jay Silver, Tammy Stern, Lis Sylvan, Hanako Tjia, Claudia
Urrea, Oren Zuckerman.
</p>
<p>
<FormattedMessage id="credits.partnersBody" />
</p>
<h2>
<FormattedMessage id="credits.researchersTitle" />
</h2>
<p>
<FormattedMessage
id="credits.researchersBody"
values={{
scratchResearchLink: (
<a href="https://scratch.mit.edu/info/research/">
<FormattedMessage id="credits.researchLinkText" />
</a>
)
}}
/>
</p>
<p>
<FormattedMessage
id="credits.researchersContributors"
values={{
nsfLink: (
<a href="http://www.nsf.gov/awardsearch/showAward?AWD_ID=0325828">
<FormattedMessage id="credits.researchNSFLinkText" />
</a>
),
scratchEdLink: (
<a href="http://scratched.gse.harvard.edu/">
<FormattedMessage id="credits.researchScratchEdLinkText" />
</a>
)
}}
/>
</p>
<h2>
<FormattedMessage id="credits.acknowledgementsTitle" />
</h2>
<p>
<FormattedMessage id="credits.acknowledgementsContributors" />
</p>
<p>
Susan Abend, Robbie Berg, Lauren Bessen, Keith Braadfladt, Katie Broida,
Susan Carillo, Will Denton, Nathan Dinsmore, Catherine Feldman, Rachel Fenichel,
Jodi Finch, Ioana Fineberg, Corey Frang, JT Galla, Rachel Garber, Cassy Gibbs,
Z Goddard, Brian Harvey, Roland Hebert, Tracy Ho, Benjamin Howe, Kapaya Katongo,
Evan Karatzas, Christine Kim, Joren Lauwers, Mike Lee, Jeff Lieberman,
Mark Loughridge, Kelly Liu, Anthony Lu, Danny Lutz, David Malan
Wayne Marshall, John McIntosh, Paul Medlock-Walton, Dongfang (Tian) Mi,
Ximena Miranda, Jens Moenig, Evan Moore, Geetha Narayanan, Kate Nazemi,
Liddy Nevile, Wing Ngan, Derek O&apos;Connell, Tim Radvan, Karen Randall,
Ian Reynolds, Miriam Ruiz, Boaz Sender, Chinua Shaw, Ed Shems, Cynthia Solomon,
Marie Staver, Daniel Strimpel, Kilmer Sweazy, John Henry Thompson, Ubong Ukoh,
Vladimir Vuksan, Han Xu.
</p>
<p>
<FormattedMessage id="credits.acknowledgementsInfluencers" />
</p>
<p>
<FormattedMessage id="credits.acknowledgementsCommunity" />
</p>
</div>
</div>
</div>);
<ul> const WrappedCredits = injectIntl(Credits);
<li> render(<Page><WrappedCredits /></Page>, document.getElementById('app'));
<img
alt="Christan Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2755634_170x170.png"
/>
<span className="name">Christan Balch</span>
</li>
<li>
<img
alt="Carl Avatar"
src="//cdn.scratch.mit.edu/get_image/user/3581881_170x170.png"
/>
<span className="name">Carl Bowman</span>
</li>
<li>
<img
alt="Karishma Avatar"
src="//cdn2.scratch.mit.edu/get_image/user/27383273_60x60.png"
/>
<span className="name">Karishma Chadha</span>
</li>
<li>
<img
alt="Champika Avatar"
src="//cdn.scratch.mit.edu/get_image/user/900283_170x170.png"
/>
<span className="name">Champika Fernando</span>
</li>
<li>
<img
alt="Mark Avatar"
src="//cdn.scratch.mit.edu/get_image/user/24137617_170x170.png"
/>
<span className="name">Mark Ferrell</span>
</li>
<li>
<img
alt="Chris Avatar"
src="//cdn.scratch.mit.edu/get_image/user/1494_170x170.png"
/>
<span className="name">Chris Garrity</span>
</li>
<li>
<img
alt="Colby Avatar"
src="//cdn.scratch.mit.edu/get_image/user/10866958_170x170.png"
/>
<span className="name">Colby Gutierrez-Kraybill</span>
</li>
<li>
<img
alt="Paul Avatar"
src="//cdn.scratch.mit.edu/get_image/user/21986973_170x170.png"
/>
<span className="name">Paul Kaplan</span>
</li>
<li>
<img
alt="DD Avatar"
src="//cdn.scratch.mit.edu/get_image/user/527836_170x170.png"
/>
<span className="name">DD Liu</span>
</li>
<li>
<img
alt="Katelyn Avatar"
src="//cdn.scratch.mit.edu/get_image/user/34607790_170x170.png"
/>
<span className="name">Katelyn Mann</span>
</li>
<li>
<img
alt="Shruti Avatar"
src="//cdn.scratch.mit.edu/get_image/user/3714374_170x170.png"
/>
<span className="name">Shruti Mohnot</span>
</li>
<li>
<img
alt="Sarah Avatar"
src="//cdn.scratch.mit.edu/get_image/user/246290_170x170.png"
/>
<span className="name">Sarah Otts</span>
</li>
<li>
<img
alt="Carmelo Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2286560_170x170.png"
/>
<span className="name">Carmelo Presicce</span>
</li>
<li>
<img
alt="Tina Avatar"
src="//cdn2.scratch.mit.edu/get_image/user/25500116_170x170.png"
/>
<span className="name">Tina Quach</span>
</li>
<li>
<img
alt="Mitchel Avatar"
src="//cdn.scratch.mit.edu/get_image/user/167_170x170.png"
/>
<span className="name">Mitchel Resnick</span>
</li>
<li>
<img
alt="ericr Avatar"
src="//cdn.scratch.mit.edu/get_image/user/159_170x170.png"
/>
<span className="name">Eric Rosenbaum</span>
</li>
<li>
<img
alt="Natalie Avatar"
src="//cdn.scratch.mit.edu/get_image/user/169_170x170.png"
/>
<span className="name">Natalie Rusk</span>
</li>
<li>
<img
alt="Ray Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2584924_170x170.png"
/>
<span className="name">Ray Schamp</span>
</li>
<li>
<img
alt="Eric Avatar"
src="//cdn.scratch.mit.edu/get_image/user/3484484_170x170.png"
/>
<span className="name">Eric Schilling</span>
</li>
<li>
<img
alt="Andrew Avatar"
src="//cdn.scratch.mit.edu/get_image/user/1709047_170x170.png"
/>
<span className="name">Andrew Sliwinski</span>
</li>
<li>
<img
alt="Tracy Avatar"
src="//cdn.scratch.mit.edu/get_image/user/18417774_170x170.png"
/>
<span className="name">Tracy Tang</span>
</li>
<li>
<img
alt="Bryce Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2029640_170x170.png"
/>
<span className="name">Bryce Taylor</span>
</li>
<li>
<img
alt="Matthew Avatar"
src="//cdn.scratch.mit.edu/get_image/user/4373707_170x170.png"
/>
<span className="name">Matthew Taylor</span>
</li>
<li>
<img
alt="Moran Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2678986_170x170.png"
/>
<span className="name">Moran Tsur</span>
</li>
<li>
<img
alt="Chris Avatar"
src="//cdn.scratch.mit.edu/get_image/user/3532363_170x170.png"
/>
<span className="name">Chris Willis-Ford</span>
</li>
<li>
<img
alt="Kathy Avatar"
src="//cdn.scratch.mit.edu/get_image/user/26779669_170x170.png"
/>
<span className="name">Kathy Wu</span>
</li>
<li>
<img
alt="Julia Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2796185_170x170.png"
/>
<span className="name">Julia Zimmerman</span>
</li>
</ul>
<p><FormattedMessage id="credits.moderators" /></p>
<ul>
<li>
<img
alt="Jolie Avatar"
src="//cdn.scratch.mit.edu/get_image/user/2496866_170x170.png"
/>
<span className="name">Jolie Castellucci</span>
</li>
<li>
<img
alt="Ellen Avatar"
src="//cdn.scratch.mit.edu/get_image/user/24164779_170x170.png"
/>
<span className="name">Ellen Daoust</span>
</li>
<li>
<img
alt="Linda Avatar"
src="//cdn.scratch.mit.edu/get_image/user/1048810_170x170.png"
/>
<span className="name">Linda Fernsel</span>
</li>
<li>
<img
alt="Mark Avatar"
src="//cdn.scratch.mit.edu/get_image/user/49156_170x170.png"
/>
<span className="name">Mark Goff</span>
</li>
<li>
<img
alt="Joel Avatar"
src="//cdn2.scratch.mit.edu/get_image/user/26249744_60x60.png"
/>
<span className="name">Joel Gritter</span>
</li>
<li>
<img
alt="Carolina Avatar"
src="//cdn2.scratch.mit.edu/get_image/user/5311910_60x60.png"
/>
<span className="name">Carolina Kaufman</span>
</li>
<li>
<img
alt="Dalton Avatar"
src="//cdn.scratch.mit.edu/get_image/user/373646_170x170.png"
/>
<span className="name">Dalton Miner</span>
</li>
<li>
<img
alt="Franchette Avatar"
src="//cdn.scratch.mit.edu/get_image/user/159139_170x170.png"
/>
<span className="name">Franchette Viloria</span>
</li>
<li>
<img
alt="Annie Avatar"
src="//cdn.scratch.mit.edu/get_image/user/4747093_170x170.png"
/>
<span className="name">Annie Whitehouse</span>
</li>
</ul>
<h2><FormattedMessage id="credits.previousTitle" /></h2>
<p>
<FormattedMessage id="credits.previousBody" />
&nbsp;
Ben Berg,
Amos Blanton,
Karen Brennan,
Juanita Buitrago,
Leo Burd,
Gaia Carini,
Kasia Chmielinski,
Michelle Chung,
Shane Clements,
Hannah Cole,
Sayamindu Dasgupta,
Margarita Dekoli,
Evelyn Eastmond,
Dave Feinberg,
Chris Graves,
Megan Haddadi,
Connor Hudson,
Christina Huang,
Tony Hwang,
Abdulrahman Idlbi,
Randy Jou,
Lily Kim,
Tauntaun Kim,
Saskia Leggett,
Tim Mickel,
Amon Millner,
Ricarose Roque,
Andrea Saxman,
Jay Silver,
Tammy Stern,
Lis Sylvan,
Hanako Tjia,
Claudia Urrea,
Oren Zuckerman
</p>
<h2>
<FormattedMessage id="credits.partnersTitle" />
</h2>
<p>
<FormattedMessage id="credits.partnersBody" />
</p>
<h2>
<FormattedMessage id="credits.researchersTitle" />
</h2>
<p>
<FormattedHTMLMessage id="credits.researchersBody" />
</p>
<h2>
<FormattedMessage id="credits.acknowledgementsTitle" />
</h2>
<p>
<FormattedHTMLMessage id="credits.acknowledgementsContributors" />
&nbsp;
Susan Abend, Robbie Berg, Lauren Bessen, Keith Braadfladt, Susan Carillo,
Will Denton, Nathan Dinsmore, Catherine Feldman, Jodi Finch, Ioana Fineberg,
JT Galla, Rachel Garber, Chris Garrity, Cassy Gibbs, Brian Harvey,
Roland Hebert, Tracy Ho, Benjamin Howe, Kapaya Katongo, Evan Karatzas,
Christine Kim, Joren Lauwers, Mike Lee, Jeff Lieberman, Mark Loughridge,
Kelly Liu, Anthony Lu, Danny Lutz, David Malan, Wayne Marshall,
John McIntosh, Paul Medlock-Walton, Dongfang (Tian) Mi, Ximena Miranda,
Jens Moenig, Evan Moore, Geetha Narayanan, Kate Nazemi, Liddy Nevile,
Wing Ngan, Derek O&#39;Connell, Tim Radvan, Karen Randall, Ian Reynolds,
Miriam Ruiz, Chinua Shaw, Ed Shems, Cynthia Solomon, Daniel Strimpel,
Kilmer Sweazy, John Henry Thompson, Ubong Ukoh, Vladimir Vuksan, Han Xu.
&nbsp;
<FormattedHTMLMessage id="credits.acknowledgementsTranslators" />
</p>
<p>
<FormattedMessage id="credits.acknowledgementsCommunity" />
</p>
<p>
<FormattedMessage id="credits.acknowledgementsInfluencers" />
</p>
<h2>
<FormattedMessage id="credits.supportersTitle" />
</h2>
<p>
<FormattedMessage id="credits.supportersFinancialHeader" />
</p>
<p>
<a href="http://www.nsf.gov/">National Science Foundation</a>,
<a href="http://www.scratchfoundation.org/"> Scratch Foundation</a>,
<a href="http:/www.siegelendowment.org"> Siegel Family Endowment</a>,
<a href="http://www.google.org/"> Google</a>,
<a href="http://www.legofoundation.com/"> LEGO Foundation</a>,
<a href="http://www.intel.com/"> Intel</a>,
<a href="http://www.turner.com/company/"> Cartoon Network</a>,
<a href="http://www.fundacaolemann.org.br/lemann-foundation/"> Lemann Foundation</a>,
<a href="https://www.macfound.org/"> MacArthur Foundation</a>.
</p>
<p><FormattedMessage id="credits.supportersServicesHeader" /></p>
<p>
<a href="http://www.advancedinstaller.com/"> Advanced Installer</a>,
<a href="http://aws.amazon.com/"> Amazon Web Services</a>,
<a href="https://codetree.com/"> Codetree</a>,
<a href="https://www.fastly.com/"> Fastly</a>,
<a href="https://www.geckoboard.com"> Geckoboard</a>,
<a href="https://github.com/"> Github</a>,
<a href="https://www.inversoft.com/"> Inversoft</a>,
<a href="http://mailchimp.com/"> MailChimp</a>,
<a href="http://mandrill.com/"> Mandrill</a>,
<a href="http://newrelic.com/"> New Relic</a>,
<a href="https://www.pagerduty.com/"> PagerDuty</a>,
<a href="https://www.pingdom.com/"> Pingdom</a>,
<a href="https://www.rallydev.com/"> Rally</a>,
<a href="https://saucelabs.com/"> SauceLabs</a>,
<a href="https://screenhero.com/"> Screenhero</a>,
<a href="https://getsentry.com/welcome/"> Sentry</a>,
<a href="http://www.git-tower.com/"> Tower</a>,
<a href="https://www.transifex.com/"> Transifex</a>,
<a href="https://travis-ci.org/"> Travis-CI</a>.
</p>
<p><FormattedMessage id="credits.supportersOpenHeader" /></p>
<p>
<a href="https://www.djangoproject.com/"> Django</a>,
<a href="http://djangobb.org/"> DjangoBB</a>,
<a href="https://www.docker.com/"> Docker</a>,
<a href="https://www.elastic.co/"> Elasticsearch</a>,
<a href="http://ganglia.sourceforge.net/"> Ganglia</a>,
<a href="http://gunicorn.org"> Gunicorn</a>,
<a href="https://jenkins-ci.org/"> Jenkins</a>,
<a href="http://www.linux.org/"> Linux</a>,
<a href="http://memcached.org/"> Memcached</a>,
<a href="https://www.mediawiki.org/wiki/MediaWiki"> MediaWiki</a>,
<a href="http://www.mysql.com/"> MySQL</a>,
<a href="https://www.nagios.org/"> Nagios</a>,
<a href="https://www.nginx.com/resources/wiki/"> Nginx</a>,
<a href="https://nodejs.org/en/"> Node.js</a>,
<a href="http://www.postgresql.org/"> PostgreSQL</a>,
<a href="https://www.python.org/"> Python</a>,
<a href="http://redis.io/"> Redis</a>,
<a href="http://saltstack.com/"> SaltStack</a>,
<a href="https://github.com/etsy/statsd/"> StatsD</a>,
<a href="http://www.ubuntu.com/"> Ubuntu</a>,
<a href="https://www.varnish-cache.org/"> Varnish</a>.
</p>
</div>
);
render(<Page><Credits /></Page>, document.getElementById('app'));

View file

@ -1,39 +1,172 @@
@import "../../colors"; @import "../../colors";
.credits { #view {
p { padding: 0;
line-height: 1.5rem; text-align: left;
}
.credits {
.avatar-grid {
display: flex;
margin: 0 auto;
padding: 64px 0;
max-width: 864px;
list-style: none;
flex-wrap: wrap;
flex-flow: row wrap;
justify-content: center;
}
.content {
padding-top: 40px;
}
.avatar-item {
display: inline-block;
margin: 0;
padding-bottom: 32px;
text-align: center;
line-height: 1.25rem;
img {
$img-border: rgba(0, 0, 0, .05);
border: 2px solid $img-border;
border-radius: 8px;
background-color: $ui-white;
width: 80px;
height: 80px;
}
.avatar-text {
display: inline-block;
width: 144px;
font-size: .875rem;
word-wrap: break-word;
a {
white-space: normal;
word-wrap: break-word; /* Overrides: https://github.com/LLK/scratch-www/blob/develop/src/main.scss#L43-L47 */
} }
} }
ul { .acknowledge-content {
display: flex; margin: 0 176px;
margin: 0; padding: 2.5rem 0 5.75rem 0;
padding: 0; max-width: 520px;
list-style: none;
flex-wrap: wrap; p {
margin: 0;
padding-bottom: 1.875rem;
line-height: 1.5rem;
}
h2 {
padding: 3rem 0 1.5rem;
line-height: 1.2em;
font-size: 2rem;
}
} }
li { .text-logo {
display: inline-block; max-width: 140px;
margin: 10px 0; text-align: center;
width: 188px; font-size: 16px;
text-align: center; font-weight: bold;
}
img { .mid-header {
margin: 10px 23px; display: flex;
border: 2px; margin: 0 88px;
border-style: solid; flex-direction: column;
border-radius: 50%; align-items: center;
border-color: $ui-dark-gray;
background-color: $ui-white; h2 {
padding: 20px; line-height: 1.2em;
width: 85px; }
height: 85px; }
.logo-grid {
display: flex;
margin: 0 auto;
max-width: 864px;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.supporters {
$bg-grey: #f7f6f8;
background-color: $bg-grey;
padding: 5.25rem 0;
}
.logo {
padding: 84px 24px 0;
}
.title-banner {
display: flex;
padding: 0;
height: 152px;
align-items: center;
}
.title-banner-h1 {
font-size: 2rem;
}
}
@media only screen and (min-width: 477px) and (max-width: 768px) {
.credits {
.acknowledge-content {
margin: 0 88px;
}
}
}
@media only screen and (min-width: 365px) and (max-width: 476px) {
.credits {
.avatar-item {
padding-bottom: 16px;
.avatar-text {
width: 112px;
}
}
.acknowledge-content,
.mid-header {
margin: 0 44px;
}
}
}
@media only screen and (max-width: 364px) {
.credits {
.avatar-item {
padding-bottom: 16px;
img {
width: 56px;
height: 56px;
}
.avatar-text {
width: 96px;
}
}
.logo-grid {
flex-direction: column;
}
.acknowledge-content {
margin: 0 12px;
}
.logo {
padding: 36px;
}
.avatar-grid {
margin: 0 12px;
} }
} }
} }

View file

@ -1,20 +1,36 @@
{ {
"credits.title": "Scratch Credits and Contributors", "credits.title": "Scratch Credits & Contributors",
"credits.developers": "Scratch is designed and developed by the Lifelong Kindergarten Group at MIT Media Lab:", "credits.developers": "Scratch is designed, developed, and moderated by the Lifelong Kindergarten Group at MIT Media Lab:",
"credits.moderators": "The team of Scratch moderators manages, supports, and improves the Scratch online community:", "credits.moderators": "The team of Scratch moderators manages, supports, and improves the Scratch online community:",
"credits.previousTitle": "Previous MIT Scratch Team Members", "credits.previousTitle": "Previous MIT Scratch Team Members",
"credits.previousBody": "Many important contributions have been made by previous Scratch Team members, including John Maloney (who led software development for the first decade of Scratch) and Andrés Monroy-Hernández (who led the development of the first Scratch community website). Other contributors include:", "credits.previousBody": "Many important contributions have been made by previous Scratch Team members, including John Maloney (who led software development for the first decade of Scratch) and Andrés Monroy-Hernández (who led the development of the first Scratch community website). Other contributors include:",
"credits.partnersTitle": "Design and Development Partners", "credits.partnersTitle": "Design and Development Partners",
"credits.researchersIntro": "Research on Scratch is being conducted by members of the MIT Scratch Team and researchers at other universities, including:",
"credits.partnersBody": "Paula Bontá and Brian Silverman, Playful Invention Company (who started contributing to the design of Scratch even before it was called Scratch).", "credits.partnersBody": "Paula Bontá and Brian Silverman, Playful Invention Company (who started contributing to the design of Scratch even before it was called Scratch).",
"credits.researchersTitle": "Scratch Researchers", "credits.researchersTitle": "Scratch Researchers",
"credits.researchersBody": "<a href=\"https://scratch.mit.edu/info/research/\">Research on Scratch</a> is being conducted by members of the MIT Scratch Team and researchers at other universities, including Yasmin Kafai (who collaborated on the <a href=\"http://www.nsf.gov/awardsearch/showAward?AWD_ID=0325828\">initial NSF Scratch grant</a>) at the University of Pennsylvania Graduate School of Education, Karen Brennan (who leads the <a href=\"http://scratched.gse.harvard.edu/\">ScratchEd project</a>) at the Harvard Graduate School of Education, Benjamin Mako Hill at the University of Washington, Andrés Monroy Hernández at Microsoft Research, Mimi Ito and Crystle Martin at the University of California, Irvine, Quinn Burke at College of Charleston, Deborah Fields at Utah State University, and Kylie Peppler at Indiana University.", "credits.researchersBody" : "{scratchResearchLink} is being conducted by members of the MIT Scratch Team and researchers at other universities, including:",
"credits.researchLinkText": "Research on Scratch",
"credits.researchersContributors" : "Yasmin Kafai (who collaborated on the {nsfLink}) at the University of Pennsylvania Graduate School of Education, Karen Brennan (who leads the {scratchEdLink}) at the Harvard Graduate School of Education, Benjamin Mako Hill at the University of Washington, Andrés Monroy Hernández at Microsoft Research, Mimi Ito and Crystle Martin at the University of California, Irvine, Quinn Burke at College of Charleston, Deborah Fields at Utah State University, and Kylie Peppler at Indiana University.",
"credits.researchNSFLinkText" : "initial NSF Scratch grant",
"credits.researchScratchEdLinkText" : "ScratchEd project",
"credits.acknowledgementsTitle": "Acknowledgements", "credits.acknowledgementsTitle": "Acknowledgements",
"credits.acknowledgementsContributors": "The following people have also contributed to the development and support of Scratch over the years:", "credits.acknowledgementsContributors": "The following people have also contributed to the development and support of Scratch over the years:",
"credits.acknowledgementsTranslators": "With the help of <a href=\"http://wiki.scratch.mit.edu/wiki/Translators\">Scratch Translators</a> around the world, Scratch is available in many languages.", "credits.acknowledgementsTranslators": "With the help of {translatorsLink} around the world, Scratch is available in many languages.",
"credits.acknowledgementsTranslatorsLinkText": "Scratch Translators",
"credits.acknowledgementsCommunity": "We greatly appreciate all of the contributions by members of the worldwide Scratch community, who have shaped the direction of Scratch by sharing their projects, comments, and ideas.", "credits.acknowledgementsCommunity": "We greatly appreciate all of the contributions by members of the worldwide Scratch community, who have shaped the direction of Scratch by sharing their projects, comments, and ideas.",
"credits.acknowledgementsInfluencers": "The ideas of Seymour Papert and Alan Kay have deeply inspired and influenced our work on Scratch.", "credits.acknowledgementsInfluencers": "The ideas of Seymour Papert and Alan Kay have deeply inspired and influenced our work on Scratch.",
"credits.supportersTitle": "Supporting Organizations", "credits.supportersTitle": "Supporting Organizations",
"credits.supportersFinancialHeader": "The following organizations have provided major financial support for Scratch:", "credits.supportersFinancialHeader": "The following organizations have provided major financial support for Scratch:",
"credits.supportersServicesHeader": "The following organizations donate their services to help keep the Scratch project running:", "credits.supportersServicesHeader": "The following organizations donate their services to help keep the Scratch project running:",
"credits.supportersOpenHeader": "Scratch would not be possible without free and open source software, including:" "credits.supportersOpenHeader": "Scratch would not be possible without free and open source software, including:",
"credits.currentSponsors": "Current Sponsors",
"credits.currentFinancialSupport": "The following organizations are providing major financial support for Scratch:",
"credits.translationsTitle": "Translations",
"credits.illustrationsTitle": "Illustrations",
"credits.acknowledgementsIllustrations": "Many thanks to the following artists for their contributions to the Scratch sprite library:",
"credits.soundsTitle": "Sounds",
"credits.pastContributors": "Past Contributors",
"credits.pastContributorsThanks" : "Many important contributions have been made by previous Scratch Team members, including John Maloney (who led software development for the first decade of Scratch) and Andrés Monroy-Hernández (who led the development of the first Scratch community website).",
"credits.otherContributors": "Other contributors include:",
"credits.acknowledgementsSound": "Thanks to the following freesound.org artists:"
} }

View file

@ -0,0 +1,242 @@
[
{
"userName": "labdalla",
"userId": 35687410,
"name": "Lena Abdalla"
},
{
"userName": "shaanmasala",
"userId": 29995562,
"name": "Yusuf Ahmad"
},
{
"userName": "ceebee",
"userId": 2755634,
"name": "Christan Balch"
},
{
"userName": "Zinnea",
"userId": 35911243,
"name": "Zo\u00eb Bentley"
},
{
"userName": "designerd",
"userId": 3581881,
"name": "Carl Bowman"
},
{
"userName": "leoburd",
"userId": 385,
"name": "Leo Burd"
},
{
"userName": "FredDog",
"userId": 2496866,
"name": "Jolie Castellucci"
},
{
"userName": "kittyloaf",
"userId": 27383273,
"name": "Karishma Chadha"
},
{
"userName": "SunnyDay4aBlueJay",
"userId": 24164779,
"name": "Ellen Daoust"
},
{
"userName": "shruti",
"userId": 3714374,
"name": "Shruti Dhariwal"
},
{
"userName": "Champ99",
"userId": 900283,
"name": "Champika Fernando"
},
{
"userName": "LiFaytheGoblin",
"userId": 1048810,
"name": "Linda Fernsel"
},
{
"userName": "dietbacon",
"userId": 24137617,
"name": "Mark Ferrell"
},
{
"userName": "rmiel",
"userId": 34557192,
"name": "Elizabeth Foster"
},
{
"userName": "lilyland",
"userId": 17184580,
"name": "Lily Gabaree"
},
{
"userName": "chrisg",
"userId": 1494,
"name": "Chris Garrity"
},
{
"userName": "Paddle2See",
"userId": 49156,
"name": "Mark Goff"
},
{
"userName": "GulpTea",
"userId": 26249744,
"name": "Joel Gritter"
},
{
"userName": "codubee",
"userId": 10866958,
"name": "Colby Gutierrez-Kraybill"
},
{
"userName": "khanning",
"userId": 1553886,
"name": "Kreg Hanning"
},
{
"userName": "pizzafordessert",
"userId": 22183577,
"name": "Sean Hickey"
},
{
"userName": "theladynico",
"userId": 35550237,
"name": "Nicole Hughes"
},
{
"userName": "sgcc_",
"userId": 21986973,
"name": "Paul Kaplan"
},
{
"userName": "dsquare",
"userId": 527836,
"name": "DD Liu"
},
{
"userName": "dinopickles",
"userId": 34607790,
"name": "Katelyn Mann"
},
{
"userName": "harakou",
"userId": 373646,
"name": "Dalton Miner"
},
{
"userName": "mwikali",
"userId": 24838781,
"name": "Marian Muthui"
},
{
"userName": "me_win",
"userId": 7664502,
"name": "My Nguyen"
},
{
"userName": "lob12",
"userId": 2860339,
"name": "Lisa O'Brien"
},
{
"userName": "",
"userId": "",
"name": "Abisola Okuk"
},
{
"userName": "KayOh",
"userId": 3018280,
"name": "Kristin Osiecki"
},
{
"userName": "scmb1",
"userId": 246290,
"name": "Sarah Otts"
},
{
"userName": "tarmelop",
"userId": 2286560,
"name": "Carmelo Presicce"
},
{
"userName": "quacht",
"userId": 25500116,
"name": "Tina Quach"
},
{
"userName": "mres",
"userId": 167,
"name": "Mitchel Resnick"
},
{
"userName": "ericr",
"userId": 159,
"name": "Eric Rosenbaum"
},
{
"userName": "natalie",
"userId": 169,
"name": "Natalie Rusk"
},
{
"userName": "raimondious",
"userId": 2584924,
"name": "Ray Schamp"
},
{
"userName": "speakvisually",
"userId": 3484484,
"name": "Eric Schilling"
},
{
"userName": "thisandagain",
"userId": 1709047,
"name": "Andrew Sliwinski"
},
{
"userName": "BrycedTea",
"userId": 2029640,
"name": "Bryce Taylor"
},
{
"userName": "jaleesa",
"userId": 2374106,
"name": "Jaleesa Trapp"
},
{
"userName": "cheddargirl",
"userId": 159139,
"name": "Franchette Viloria"
},
{
"userName": "wheelsonfire",
"userId": 10001044,
"name": "Ben Wheeler"
},
{
"userName": "achouse",
"userId": 4747093,
"name": "Annie Whitehouse"
},
{
"userName": "cwillisf",
"userId": 3532363,
"name": "Chris Willis-Ford"
},
{
"userName": "pondermake",
"userId": 26779669,
"name": "Kathy Wu"
},
{
"userName": "stymphalianbirb",
"userId": 2796185,
"name": "Julia Zimmerman"
}
]

View file

@ -0,0 +1,61 @@
[
{
"logoSrc": "/images/credits/siegelfamily.png",
"logoDestination": "https://www.siegelendowment.org",
"width": "146px"
},
{
"logoSrc": "/images/credits/smilegate.png",
"logoDestination": "https://www.smilegate.com/",
"width": "162px"
},
{
"logoSrc": "/svgs/credits/google.svg",
"logoDestination": "https://google.com/",
"width": "124px"
},
{
"textLogo": "Little Bluebridge Foundation",
"logoDestination": ""
},
{
"logoSrc": "/images/credits/legofoundation.png",
"logoDestination": "https://www.legofoundation.com",
"width": "240px"
},
{
"logoSrc": "/images/credits/lemann.png",
"logoDestination": "https://fundacaolemann.org.br/en/co-invest",
"width": "156px"
},
{
"logoSrc": "/svgs/credits/fastly.svg",
"logoDestination": "https://www.fastly.com/",
"width": "108px"
},
{
"logoSrc": "/images/credits/taledu.png",
"logoDestination": "https://en.100tal.com/",
"width": "188px"
},
{
"logoSrc": "/images/credits/lego-education.png",
"logoDestination": "https://education.lego.com",
"width": "194px"
},
{
"logoSrc": "/svgs/credits/cartoonnetwork.svg",
"logoDestination": "https://www.cartoonnetwork.com/",
"width": "78px"
},
{
"logoSrc": "/images/credits/brainpop.png",
"logoDestination": "https://www.brainpop.com/",
"width": "78px"
},
{
"logoSrc": "/svgs/credits/amazonws.svg",
"logoDestination": "https://aws.amazon.com/",
"width": "82px"
}
]

View file

@ -1,16 +1,17 @@
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage; const FormattedMessage = require('react-intl').FormattedMessage;
const injectIntl = require('react-intl').injectIntl; const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape; const intlShape = require('react-intl').intlShape;
const React = require('react'); const React = require('react');
const api = require('../../lib/api');
const FlexRow = require('../../components/flex-row/flex-row.jsx'); const FlexRow = require('../../components/flex-row/flex-row.jsx');
const SubNavigation = require('../../components/subnavigation/subnavigation.jsx'); const bindAll = require('lodash.bindall');
const TitleBanner = require('../../components/title-banner/title-banner.jsx'); const Steps = require('../../components/steps/steps.jsx');
const Step = require('../../components/steps/step.jsx');
const Page = require('../../components/page/www/page.jsx'); const Page = require('../../components/page/www/page.jsx');
const render = require('../../lib/render.jsx'); const render = require('../../lib/render.jsx');
const OS_ENUM = require('../../components/extension-landing/os-enum.js');
const OSChooser = require('../../components/os-chooser/os-chooser.jsx');
require('./download.scss'); require('./download.scss');
require('../../components/forms/button.scss'); require('../../components/forms/button.scss');
@ -18,246 +19,239 @@ require('../../components/forms/button.scss');
class Download extends React.Component { class Download extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
bindAll(this, [
'onSetOS'
]);
let detectedOS = OS_ENUM.WINDOWS;
if (window.navigator && window.navigator.platform) {
if (window.navigator.platform === 'MacIntel') {
detectedOS = OS_ENUM.MACOS;
}
}
this.state = { this.state = {
swfVersion: '' OS: detectedOS
}; };
} }
componentDidMount () {
let uri = '/scratchr2/static/sa/version.xml';
if (this.props.intl.locale === 'pt-br') {
uri = '/scratchr2/static/sa/pt-br/version.xml';
}
api({ onSetOS (os) {
host: '', this.setState({
uri: uri, OS: os
responseType: 'string'
}, (err, body, res) => {
if (err || res.statusCode >= 400) {
return this.setState({
swfVersion: -1
});
}
const doc = new DOMParser().parseFromString(body, 'text/xml');
return this.setState({
swfVersion: doc.getElementsByTagName('versionNumber')[0].childNodes[0].nodeValue
});
}); });
} }
render () {
let downloadPath = '/scratchr2/static/sa/Scratch-';
let downloadUrls = null;
if (this.props.intl.locale === 'pt-br') {
downloadPath = '/scratchr2/static/sa/pt-br/Scratch-';
}
if (this.state.swfVersion.length > 0 && this.state.swfVersion !== -1) {
downloadUrls = {
mac: `${downloadPath}${this.state.swfVersion}.dmg`,
mac105: `${downloadPath}${this.state.swfVersion}.air`,
windows: `${downloadPath}${this.state.swfVersion}.exe`
};
}
render () {
return ( return (
<div className="download"> <div className="download">
<TitleBanner className="masthead"> <div className="download-header">
<div className="inner"> <FlexRow className="inner">
<h1 className="title-banner-h1"> <FlexRow className="column download-info">
<FormattedMessage id="download.title" /> <FlexRow className="column download-copy">
</h1> <h1 className="download-title">
<p className="title-banner-p intro"> <img
<FormattedMessage id="download.intro" /> alt={this.props.intl.formatMessage({id: 'download.iconAltText'})}
</p> className="icon"
</div> height="40"
<div className="band"> src="/images/download/icon.png"
<SubNavigation className="inner"> width="40"
<a
className="sub-nav-item"
href="#installation"
>
<li>
<FormattedMessage id="download.installation" />
</li>
</a>
<a
className="sub-nav-item"
href="#updates"
>
<li>
<FormattedMessage id="download.updatesTitle" />
</li>
</a>
<a
className="sub-nav-item"
href="#other"
>
<li>
<FormattedMessage id="download.otherVersionsTitle" />
</li>
</a>
<a
className="sub-nav-item"
href="#issues"
>
<li>
<FormattedMessage id="download.knownIssuesTitle" />
</li>
</a>
</SubNavigation>
</div>
</TitleBanner>
<div className="download-content">
<section
className="installation"
id="installation"
>
<div className="inner">
<p className="callout">
<FormattedHTMLMessage id="download.introMac" />
</p>
<FlexRow className="three-col-row">
<div className="installation-column">
<div className="installation-column-number">
<h2 className="installation-column-number-text">{'1'}</h2>
</div>
<h3><FormattedMessage id="download.airTitle" /></h3>
<p><FormattedHTMLMessage id="download.airBody" /></p>
<ul className="installation-downloads">
<li className="installation-downloads-item">
<FormattedMessage id="download.macOSX" /> -
{' '}<a href="http://get.adobe.com/air/">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.macOlder" /> -
{' '}<a href="http://airdownload.adobe.com/air/mac/download/2.6/AdobeAIR.zip">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.windows" /> -
{' '}<a href="http://get.adobe.com/air/">
<FormattedMessage id="download.download" />
</a>
</li>
</ul>
</div>
<div className="installation-column">
<div className="installation-column-number">
<h2 className="installation-column-number-text">{'2'}</h2>
</div>
<h3><FormattedMessage id="download.offlineEditorTitle" /></h3>
<p><FormattedMessage id="download.offlineEditorBody" /></p>
{downloadUrls === null ? [] : [
<ul
className="installation-downloads"
key="installation-downloads"
>
<li className="installation-downloads-item">
<FormattedMessage id="download.macOSX" /> -
{' '}<a href={downloadUrls.mac}>
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.macOlder" /> -
{' '}<a href={downloadUrls.mac105}>
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.windows" /> -
{' '}<a href={downloadUrls.windows}>
<FormattedMessage id="download.download" />
</a>
</li>
</ul>
]}
{this.state.swfVersion === -1 ? [
<p key="not-available">
<i><FormattedMessage id="download.notAvailable" /></i>
</p>
] : []}
</div>
<div className="installation-column">
<div className="installation-column-number">
<h2 className="installation-column-number-text">{'3'}</h2>
</div>
<h3><FormattedMessage id="download.supportMaterialsTitle" /></h3>
<p><FormattedMessage id="download.supportMaterialsBody" /></p>
<ul className="installation-downloads">
<li className="installation-downloads-item">
<FormattedMessage id="download.starterProjects" /> -
{' '}<a href="https://scratch.mit.edu/scratchr2/static/sa/Scratch2StarterProjects.zip">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.gettingStarted" /> -
{' '}<a href="https://cdn.scratch.mit.edu/scratchr2/static/__709da8e5f3d72129538a4ccdbcbf5f2a__/pdfs/help/Getting-Started-Guide-Scratch2.pdf">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.scratchCards" /> -
{' '}<a href="https://cdn.scratch.mit.edu/scratchr2/static/__709da8e5f3d72129538a4ccdbcbf5f2a__/pdfs/help/Scratch2Cards.pdf">
<FormattedMessage id="download.download" />
</a>
</li>
</ul>
</div>
</FlexRow>
</div>
</section>
<div className="inner">
<section id="updates">
<span className="nav-spacer" />
<h2><FormattedMessage id="download.updatesTitle" /></h2>
<p><FormattedMessage id="download.updatesBody" /></p>
{this.state.swfVersion === -1 ? [] : [
<p key="current-version">
<FormattedMessage
id="download.currentVersion"
values={{
version: this.state.swfVersion
}}
/> />
</p> <FormattedMessage id="download.title" />
]} </h1>
</section> <span className="download-description">
<FormattedMessage id="download.intro" />
</span>
</FlexRow>
<FlexRow className="column download-requirements-container">
<span className="requirements-header">
<FormattedMessage id="download.requirements" />
</span>
<FlexRow className="download-requirements">
<span>
<img
alt=""
src="/svgs/extensions/windows.svg"
/>
Windows 10+
</span>
<span>
<img
alt=""
src="svgs/extensions/mac.svg"
/>
macOS 10.13+
</span>
</FlexRow>
</FlexRow>
</FlexRow>
<div className="download-image">
<img
alt={this.props.intl.formatMessage({id: 'download.imgAltDownloadIllustration'})}
src="/images/download/download.png"
/>
</div>
</FlexRow>
</div>
<OSChooser
currentOS={this.state.OS}
handleSetOS={this.onSetOS}
/>
<div className="blue install-scratch">
<FlexRow className="inner column">
<h2 className="title">
<FormattedMessage id="download.installHeaderTitle" />
</h2>
<Steps>
<div className="step">
<Step
compact
number={1}
>
<span className="step-description">
<FormattedMessage id="download.downloadScratchDesktop" />
</span>
<div className="downloads-container">
<a
className="download-button"
href={
this.state.OS === OS_ENUM.WINDOWS ?
'https://downloads.scratch.mit.edu/desktop/Scratch%20Desktop%20Setup%201.2.0.exe' :
'https://downloads.scratch.mit.edu/desktop/Scratch%20Desktop-1.2.0.dmg'
}
>
<FormattedMessage id="download.downloadButton" />
</a>
</div>
</Step>
<section id="other"> </div>
<span className="nav-spacer" /> <Step
<h2><FormattedMessage id="download.otherVersionsTitle" /></h2> compact
<p><FormattedHTMLMessage id="download.otherVersionsOlder" /></p> number={2}
<p><FormattedHTMLMessage id="download.otherVersionsAdmin" /></p>
</section>
<section id="issues">
<span className="nav-spacer" />
<h2><FormattedMessage id="download.knownIssuesTitle" /></h2>
<p><FormattedMessage id="download.knownIssuesOne" /></p>
<p><FormattedMessage id="download.knownIssuesTwo" /></p>
<p><FormattedHTMLMessage id="download.knownIssuesThree" /></p>
<p><FormattedMessage id="download.knownIssuesFour" /></p>
<a
className="button mod-link"
href="https://scratch.mit.edu/discuss/3/"
> >
<FormattedMessage id="download.reportBugs" /> <span className="step-description">
</a> {this.state.OS === OS_ENUM.WINDOWS ?
</section> <FormattedMessage id="download.winMoveToApplications" /> :
</div> <FormattedMessage id="download.macMoveToApplications" />
}
</span>
<div className="step-image">
<img
alt=""
className="screenshot"
src={`/images/download/${
this.state.OS === OS_ENUM.WINDOWS ? 'windows' : 'mac'
}-install.png`}
/>
</div>
</Step>
</Steps>
</FlexRow>
</div>
<div className="download-section faq">
<FlexRow className="inner column">
<h2 className="title">
<FormattedMessage id="download.troubleshootingTitle" />
</h2>
<h3 className="faq-question">
<FormattedMessage id="download.canIUseScratchLink" />
</h3>
<p>
<FormattedMessage id="download.canIUseScratchLinkAnswer" />
</p>
<h3 className="faq-question">
<FormattedMessage id="download.desktopAndBrowser" />
</h3>
<p>
<FormattedMessage id="download.yesAnswer" />
</p>
<h3 className="faq-question">
<FormattedMessage id="download.canIShare" />
</h3>
<p>
<FormattedMessage id="download.canIShareAnswer" />
</p>
<h3 className="faq-question">
<FormattedMessage id="download.supportChromeOS" />
</h3>
<p>
<FormattedMessage id="download.supportChromeOSAnswer" />
</p>
<h3 className="faq-question">
<FormattedMessage id="download.whenSupportLinux" />
</h3>
<p>
<FormattedMessage id="download.supportLinuxAnswer" />
</p>
</FlexRow>
</div>
<div className="download-section blue">
<FlexRow className="inner column">
<h2 className="title">
<FormattedMessage id="download.olderVersionsTitle" />
</h2>
<p>
<FormattedMessage id="download.olderVersions" />
</p>
<FlexRow>
<div className="older-version">
<a href="/download/scratch2">
<img
alt=""
className="screenshot"
height="106"
src="/images/download/scratch2.png"
width="150"
/>
</a>
<p>
<a
className="legacy-link"
href="/download/scratch2"
>
<FormattedMessage id="download.scratch2Desktop" />
<img
className="little-arrow"
src="/svgs/download/r-arrow.svg"
/>
</a>
</p>
</div>
<div className="older-version">
<a href="/scratch_1.4">
<img
alt=""
className="screenshot"
height="106"
src="/images/download/scratch1-4.png"
width="150"
/>
</a>
<p>
<a
className="legacy-link"
href="/scratch_1.4"
>
<FormattedMessage id="download.scratch1-4Desktop" />
<img
className="little-arrow"
src="/svgs/download/r-arrow.svg"
/>
</a>
</p>
</div>
</FlexRow>
</FlexRow>
</div> </div>
</div> </div>
); );
} }
} }
Download.propTypes = { Download.propTypes = {
intl: intlShape intl: intlShape
}; };
const WrappedDownload = injectIntl(Download); const WrappedDownload = injectIntl(Download);

View file

@ -6,123 +6,166 @@
} }
.download { .download {
.title-banner { .title {
&.masthead { margin-bottom: 2rem;
margin-bottom: 0; font-size: 2rem;
background-color: $ui-blue-dark; }
padding-bottom: 0;
h1 { .legacy-link {
margin: 0 0 2rem 0; display: flex;
text-align: left; }
color: $ui-white;
}
p { .download-button {
margin: 0; display: inline-block;
text-align: left; margin: .5em 0;
color: $ui-white; border: 0;
border-radius: 8px;
background-color: $ui-blue;
cursor: pointer;
padding: 1rem 2rem;
color: $ui-white;
font-size: 1rem;
}
a { .download-header {
border-bottom: 1px solid $ui-white; background-color: $ui-blue;
padding: 4rem 0;
color: $ui-white;
.title {
color: $ui-white;
}
.inner {
justify-content: space-between;
flex-wrap: nowrap;
}
.download-info {
padding-right: $cols1;
max-width: $cols6 + ($gutter / $em);
align-items: flex-start;
.download-copy {
margin-bottom: 5rem;
align-items: flex-start;
.download-title {
display: flex;
margin-bottom: 2rem;
color: $ui-white; color: $ui-white;
font-size: 2rem;
}
.icon {
padding-right: .5rem;
max-height: 100%;
align-self: center;
}
.download-description {
line-height: 1.7rem;
font-size: 1.2rem;
} }
} }
.band { .download-requirements-container {
margin-top: 2rem; font-weight: 500;
background-color: $ui-white-15percent; align-items: flex-start;
padding: 1rem 0;
}
.sub-nav { .requirements-header {
text-align: left; margin-bottom: 1.5rem;
justify-content: flex-start;
li {
margin: 0 .5rem 0 0;
} }
.download-requirements {
justify-content: space-between;
}
.download-requirements span {
display: flex;
margin-right: 1rem;
font-size: 15px;
align-items: center;
}
.download-requirements span img {
padding-right: .5rem;
}
}
}
.download-image {
width: 100%;
max-width: $cols6;
img {
max-width: 100%;
max-height: 100%;
} }
} }
} }
.sub-nav-item { .install-scratch {
margin: .5rem; padding: 2rem 0;
}
.inner {
.callout { align-items: flex-start;
text-align: center; }
}
.downloads-container {
.download-content { text-align: center;
padding-bottom: 2rem; }
.step-image {
height: 14rem;
}
} }
.three-col-row { .download-section {
align-items: flex-start; padding: 4rem 0;
.inner {
align-items: flex-start;
}
} }
.installation { .blue {
background-color: $ui-gray; background-color: $ui-blue-10percent;
padding: 2rem;
} }
.installation-column { .faq {
max-width: $cols4; p {
text-align: center; margin-bottom: 1.25rem;
margin-left: 0;
max-width: $cols8;
text-align: left;
}
.faq-question {
margin-bottom: 0;
font-size: 1.4rem;
}
}
.older-version {
padding-right: 24px;
p { p {
margin-right: .5rem; line-height: normal;
margin-left: .5rem; color: $link-blue;
font-weight: 600;
} }
}
.installation-column-number { .little-arrow {
margin: 2rem auto; padding-left: 2px;
border: 2px solid $active-gray;
border-radius: 2rem;
background-color: $ui-blue;
width: 3.75rem;
height: 3.75rem;
}
.installation-column-number-text {
text-align: center;
line-height: 1.8em;
color: $type-white;
}
.installation-downloads {
padding-left: 0;
list-style: none;
}
.installation-downloads-item {
margin: .25rem;
padding: 0;
text-align: center;
}
section {
margin-bottom: 2rem;
}
.mod-link {
color: $ui-white;
}
@media #{$small} {
.inner {
.installation-column {
max-width: 100%;
}
} }
}
@media #{$intermediate-and-smaller} { .screenshot {
.three-col-row { margin-top: 1rem;
flex-direction: column; $img-border: rgba(0, 0, 0, .05);
align-items: center; border: 2px solid $img-border;
border-radius: 8px;
} }
} }
} }

View file

@ -1,32 +1,30 @@
{ {
"download.title": "Scratch 2.0 Offline Editor", "download.title": "Scratch Desktop",
"download.intro": "You can install the Scratch 2.0 editor to work on projects without an internet connection. This version will work on Windows and MacOS.", "download.intro": "You can install the Scratch Desktop editor to work on projects without an internet connection. This version will work on Windows and MacOS.",
"download.introMac": "<b>Note for Mac Users:</b> the latest version of Scratch 2.0 Offline requires Adobe AIR 20. To upgrade to Adobe AIR 20 manually, go <a href=\"https://get.adobe.com/air/\">here</a>.", "download.requirements": "Requirements",
"download.installation": "Installation", "download.imgAltDownloadIllustration" : "Scratch 3.0 Desktop screenshot",
"download.airTitle": "Adobe AIR", "download.installHeaderTitle": "Install Scratch Desktop",
"download.airBody": "If you don't already have it, download and install the latest <a href=\"http://get.adobe.com/air/\">Adobe AIR</a>", "download.downloadScratchDesktop": "Download Scratch Desktop",
"download.macOSX": "Mac OS X", "download.downloadButton": "Download",
"download.macOlder": "Mac OS 10.5 & Older", "download.troubleshootingTitle": "FAQ",
"download.windows": "Windows", "download.startScratchDesktop": "Start Scratch Desktop",
"download.download": "Download", "download.howDoIInstall": "How do I install Scratch Desktop?",
"download.offlineEditorTitle": "Scratch Offline Editor", "download.whenSupportLinux": "When will you have Scratch Desktop for Linux?",
"download.offlineEditorBody": "Next download and install the Scratch 2.0 Offline Editor", "download.supportLinuxAnswer" : "Scratch Desktop on Linux is currently not supported. We are working with partners and the open-source community to determine if there is a way we can support Linux in the future. Stay tuned!",
"download.supportMaterialsTitle": "Support Materials", "download.supportChromeOS" : "When will you have Scratch Desktop for Chromebooks?",
"download.supportMaterialsBody": "Need some help getting started? Here are some helpful resources.", "download.supportChromeOSAnswer": "Scratch Desktop for Chromebooks is not yet available. We are working on it and expect to release later in 2019.",
"download.starterProjects": "Starter Projects", "download.olderVersionsTitle" : "Older Versions",
"download.gettingStarted": "Getting Started Guide", "download.olderVersions": "Looking for the Scratch 2.0 Offline Editor or Scratch 1.4?",
"download.scratchCards": "Scratch Cards", "download.scratch1-4Desktop" : "Scratch 1.4 Desktop",
"download.updatesTitle": "Updates", "download.scratch2Desktop" : "Scratch 2.0 Desktop",
"download.updatesBody": "The Offline Editor can update itself (with user permission). It will check for updates at startup or you can use the \"Check for updates\" command in the file menu.", "download.cannotAccessMacStore" : "What if I can't access the Mac App Store?",
"download.currentVersion": "The current version is {version}.", "download.cannotAccessWindowsStore" : "What if I can't access the Microsoft Store?",
"download.otherVersionsTitle": "Other Versions of Scratch", "download.macMoveToApplications" : "Open the .dmg file. Move Scratch Desktop into Applications.",
"download.otherVersionsOlder": "If you have an older computer, or cannot install the Scratch 2.0 offline editor, you can try installing <a href=\"http://scratch.mit.edu/scratch_1.4/\">Scratch 1.4</a>.", "download.winMoveToApplications" : "Run the .exe file.",
"download.otherVersionsAdmin": "If you are a network administrator: a Scratch 2.0 MSI has been created and maintained by a member of the community and hosted for public download <a href=\"http://llk.github.io/scratch-msi/\">here</a>.", "download.canIUseScratchLink" : "Can I use Scratch Link to connect to extensions?",
"download.knownIssuesTitle": "Known issues", "download.canIUseScratchLinkAnswer" : "Yes. However, you will need an Internet connection to use Scratch Link.",
"download.knownIssuesOne": "If your offline editor is crashing directly after Scratch is opened, install the Scratch 2 offline editor again (see step 2 above). This issue is due to a bug introduced in Adobe AIR version 14 (released April 2014).", "download.desktopAndBrowser": "Can I use Scratch Desktop and also have Scratch open in the browser?",
"download.knownIssuesTwo": "Graphic effects blocks (in \"Looks\") may slow down projects due to a known Flash bug.", "download.yesAnswer" : "Yes.",
"download.knownIssuesThree": "The <b>backpack</b> is not yet available.", "download.canIShare": "Can I share from Scratch Desktop?",
"download.knownIssuesFour": "On Mac OS you may see a prompt indicating that \"Scratch 2 is trying to install a new helper tool\" and asking for your user name and password. We are currently investigating a solution to this problem.", "download.canIShareAnswer": "This isnt supported currently. For now, you can save a project from Scratch Desktop, upload it to your Scratch account, and share it there. In a later version we will add the ability to upload to your Scratch account directly in Scratch Desktop."
"download.reportBugs": "Report Bugs and Glitches",
"download.notAvailable": "Hmm, editor downloads are not available right now - please refresh the page to try again."
} }

View file

@ -0,0 +1,265 @@
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage;
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const React = require('react');
const api = require('../../../lib/api');
const FlexRow = require('../../../components/flex-row/flex-row.jsx');
const SubNavigation = require('../../../components/subnavigation/subnavigation.jsx');
const TitleBanner = require('../../../components/title-banner/title-banner.jsx');
const Page = require('../../../components/page/www/page.jsx');
const render = require('../../../lib/render.jsx');
require('./download.scss');
require('../../../components/forms/button.scss');
class Download extends React.Component {
constructor (props) {
super(props);
this.state = {
swfVersion: ''
};
}
componentDidMount () {
let uri = '/scratchr2/static/sa/version.xml';
if (this.props.intl.locale === 'pt-br') {
uri = '/scratchr2/static/sa/pt-br/version.xml';
}
api({
host: '',
uri: uri,
responseType: 'string'
}, (err, body, res) => {
if (err || res.statusCode >= 400) {
return this.setState({
swfVersion: -1
});
}
const doc = new DOMParser().parseFromString(body, 'text/xml');
return this.setState({
swfVersion: doc.getElementsByTagName('versionNumber')[0].childNodes[0].nodeValue
});
});
}
render () {
let downloadPath = '/scratchr2/static/sa/Scratch-';
let downloadUrls = null;
if (this.props.intl.locale === 'pt-br') {
downloadPath = '/scratchr2/static/sa/pt-br/Scratch-';
}
if (this.state.swfVersion.length > 0 && this.state.swfVersion !== -1) {
downloadUrls = {
mac: `${downloadPath}${this.state.swfVersion}.dmg`,
mac105: `${downloadPath}${this.state.swfVersion}.air`,
windows: `${downloadPath}${this.state.swfVersion}.exe`
};
}
return (
<div className="download">
<TitleBanner className="masthead">
<div className="inner">
<h1 className="title-banner-h1">
<FormattedMessage id="download.title" />
</h1>
<p className="title-banner-p intro">
<FormattedMessage id="download.intro" />
</p>
</div>
<div className="band">
<SubNavigation className="inner">
<a
className="sub-nav-item"
href="#installation"
>
<li>
<FormattedMessage id="download.installation" />
</li>
</a>
<a
className="sub-nav-item"
href="#updates"
>
<li>
<FormattedMessage id="download.updatesTitle" />
</li>
</a>
<a
className="sub-nav-item"
href="#other"
>
<li>
<FormattedMessage id="download.otherVersionsTitle" />
</li>
</a>
<a
className="sub-nav-item"
href="#issues"
>
<li>
<FormattedMessage id="download.knownIssuesTitle" />
</li>
</a>
</SubNavigation>
</div>
</TitleBanner>
<div className="download-content">
<section
className="installation"
id="installation"
>
<div className="inner">
<p className="callout">
<FormattedHTMLMessage id="download.introMac" />
</p>
<FlexRow className="three-col-row">
<div className="installation-column">
<div className="installation-column-number">
<h2 className="installation-column-number-text">{'1'}</h2>
</div>
<h3><FormattedMessage id="download.airTitle" /></h3>
<p><FormattedHTMLMessage id="download.airBody" /></p>
<ul className="installation-downloads">
<li className="installation-downloads-item">
<FormattedMessage id="download.macOSX" /> -
{' '}<a href="http://get.adobe.com/air/">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.macOlder" /> -
{' '}<a href="http://airdownload.adobe.com/air/mac/download/2.6/AdobeAIR.zip">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.windows" /> -
{' '}<a href="http://get.adobe.com/air/">
<FormattedMessage id="download.download" />
</a>
</li>
</ul>
</div>
<div className="installation-column">
<div className="installation-column-number">
<h2 className="installation-column-number-text">{'2'}</h2>
</div>
<h3><FormattedMessage id="download.offlineEditorTitle" /></h3>
<p><FormattedMessage id="download.offlineEditorBody" /></p>
{downloadUrls === null ? [] : [
<ul
className="installation-downloads"
key="installation-downloads"
>
<li className="installation-downloads-item">
<FormattedMessage id="download.macOSX" /> -
{' '}<a href={downloadUrls.mac}>
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.macOlder" /> -
{' '}<a href={downloadUrls.mac105}>
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.windows" /> -
{' '}<a href={downloadUrls.windows}>
<FormattedMessage id="download.download" />
</a>
</li>
</ul>
]}
{this.state.swfVersion === -1 ? [
<p key="not-available">
<i><FormattedMessage id="download.notAvailable" /></i>
</p>
] : []}
</div>
<div className="installation-column">
<div className="installation-column-number">
<h2 className="installation-column-number-text">{'3'}</h2>
</div>
<h3><FormattedMessage id="download.supportMaterialsTitle" /></h3>
<p><FormattedMessage id="download.supportMaterialsBody" /></p>
<ul className="installation-downloads">
<li className="installation-downloads-item">
<FormattedMessage id="download.starterProjects" /> -
{' '}<a href="https://scratch.mit.edu/scratchr2/static/sa/Scratch2StarterProjects.zip">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.gettingStarted" /> -
{' '}<a href="https://cdn.scratch.mit.edu/scratchr2/static/__709da8e5f3d72129538a4ccdbcbf5f2a__/pdfs/help/Getting-Started-Guide-Scratch2.pdf">
<FormattedMessage id="download.download" />
</a>
</li>
<li className="installation-downloads-item">
<FormattedMessage id="download.scratchCards" /> -
{' '}<a href="https://cdn.scratch.mit.edu/scratchr2/static/__709da8e5f3d72129538a4ccdbcbf5f2a__/pdfs/help/Scratch2Cards.pdf">
<FormattedMessage id="download.download" />
</a>
</li>
</ul>
</div>
</FlexRow>
</div>
</section>
<div className="inner">
<section id="updates">
<span className="nav-spacer" />
<h2><FormattedMessage id="download.updatesTitle" /></h2>
<p><FormattedMessage id="download.updatesBody" /></p>
{this.state.swfVersion === -1 ? [] : [
<p key="current-version">
<FormattedMessage
id="download.currentVersion"
values={{
version: this.state.swfVersion
}}
/>
</p>
]}
</section>
<section id="other">
<span className="nav-spacer" />
<h2><FormattedMessage id="download.otherVersionsTitle" /></h2>
<p><FormattedHTMLMessage id="download.otherVersionsOlder" /></p>
<p><FormattedHTMLMessage id="download.otherVersionsAdmin" /></p>
</section>
<section id="issues">
<span className="nav-spacer" />
<h2><FormattedMessage id="download.knownIssuesTitle" /></h2>
<p><FormattedMessage id="download.knownIssuesOne" /></p>
<p><FormattedMessage id="download.knownIssuesTwo" /></p>
<p><FormattedHTMLMessage id="download.knownIssuesThree" /></p>
<p><FormattedMessage id="download.knownIssuesFour" /></p>
<a
className="button mod-link"
href="https://scratch.mit.edu/discuss/3/"
>
<FormattedMessage id="download.reportBugs" />
</a>
</section>
</div>
</div>
</div>
);
}
}
Download.propTypes = {
intl: intlShape
};
const WrappedDownload = injectIntl(Download);
render(<Page><WrappedDownload /></Page>, document.getElementById('app'));

View file

@ -0,0 +1,128 @@
@import "../../../colors";
@import "../../../frameless";
#view {
padding: 0;
}
.download {
.title-banner {
&.masthead {
margin-bottom: 0;
background-color: $ui-blue-dark;
padding-bottom: 0;
h1 {
margin: 0 0 2rem 0;
text-align: left;
color: $ui-white;
}
p {
margin: 0;
text-align: left;
color: $ui-white;
a {
border-bottom: 1px solid $ui-white;
color: $ui-white;
}
}
.band {
margin-top: 2rem;
background-color: $ui-white-15percent;
padding: 1rem 0;
}
.sub-nav {
text-align: left;
justify-content: flex-start;
li {
margin: 0 .5rem 0 0;
}
}
}
}
.sub-nav-item {
margin: .5rem;
}
.callout {
text-align: center;
}
.download-content {
padding-bottom: 2rem;
}
.three-col-row {
align-items: flex-start;
}
.installation {
background-color: $ui-gray;
padding: 2rem;
}
.installation-column {
max-width: $cols4;
text-align: center;
p {
margin-right: .5rem;
margin-left: .5rem;
}
}
.installation-column-number {
margin: 2rem auto;
border: 2px solid $active-gray;
border-radius: 2rem;
background-color: $ui-blue;
width: 3.75rem;
height: 3.75rem;
}
.installation-column-number-text {
text-align: center;
line-height: 1.8em;
color: $type-white;
}
.installation-downloads {
padding-left: 0;
list-style: none;
}
.installation-downloads-item {
margin: .25rem;
padding: 0;
text-align: center;
}
section {
margin-bottom: 2rem;
}
.mod-link {
color: $ui-white;
}
@media #{$small} {
.inner {
.installation-column {
max-width: 100%;
}
}
}
@media #{$intermediate-and-smaller} {
.three-col-row {
flex-direction: column;
align-items: center;
}
}
}

View file

@ -0,0 +1,32 @@
{
"download.title": "Scratch 2.0 Offline Editor",
"download.intro": "You can install the Scratch 2.0 editor to work on projects without an internet connection. This version will work on Windows and MacOS.",
"download.introMac": "<b>Note for Mac Users:</b> the latest version of Scratch 2.0 Offline requires Adobe AIR 20. To upgrade to Adobe AIR 20 manually, go <a href=\"https://get.adobe.com/air/\">here</a>.",
"download.installation": "Installation",
"download.airTitle": "Adobe AIR",
"download.airBody": "If you don't already have it, download and install the latest <a href=\"http://get.adobe.com/air/\">Adobe AIR</a>",
"download.macOSX": "Mac OS X",
"download.macOlder": "Mac OS 10.5 & Older",
"download.windows": "Windows",
"download.download": "Download",
"download.offlineEditorTitle": "Scratch Offline Editor",
"download.offlineEditorBody": "Next download and install the Scratch 2.0 Offline Editor",
"download.supportMaterialsTitle": "Support Materials",
"download.supportMaterialsBody": "Need some help getting started? Here are some helpful resources.",
"download.starterProjects": "Starter Projects",
"download.gettingStarted": "Getting Started Guide",
"download.scratchCards": "Scratch Cards",
"download.updatesTitle": "Updates",
"download.updatesBody": "The Offline Editor can update itself (with user permission). It will check for updates at startup or you can use the \"Check for updates\" command in the file menu.",
"download.currentVersion": "The current version is {version}.",
"download.otherVersionsTitle": "Other Versions of Scratch",
"download.otherVersionsOlder": "If you have an older computer, or cannot install the Scratch 2.0 offline editor, you can try installing <a href=\"http://scratch.mit.edu/scratch_1.4/\">Scratch 1.4</a>.",
"download.otherVersionsAdmin": "If you are a network administrator: a Scratch 2.0 MSI has been created and maintained by a member of the community and hosted for public download <a href=\"http://llk.github.io/scratch-msi/\">here</a>.",
"download.knownIssuesTitle": "Known issues",
"download.knownIssuesOne": "If your offline editor is crashing directly after Scratch is opened, install the Scratch 2 offline editor again (see step 2 above). This issue is due to a bug introduced in Adobe AIR version 14 (released April 2014).",
"download.knownIssuesTwo": "Graphic effects blocks (in \"Looks\") may slow down projects due to a known Flash bug.",
"download.knownIssuesThree": "The <b>backpack</b> is not yet available.",
"download.knownIssuesFour": "On Mac OS you may see a prompt indicating that \"Scratch 2 is trying to install a new helper tool\" and asking for your user name and password. We are currently investigating a solution to this problem.",
"download.reportBugs": "Report Bugs and Glitches",
"download.notAvailable": "Hmm, editor downloads are not available right now - please refresh the page to try again."
}

View file

@ -13,6 +13,7 @@ const OSChooser = require('../../components/os-chooser/os-chooser.jsx');
const ExtensionLanding = require('../../components/extension-landing/extension-landing.jsx'); const ExtensionLanding = require('../../components/extension-landing/extension-landing.jsx');
const ExtensionHeader = require('../../components/extension-landing/extension-header.jsx'); const ExtensionHeader = require('../../components/extension-landing/extension-header.jsx');
const ExtensionVideo = require('../../components/extension-landing/extension-video.jsx');
const ExtensionRequirements = require('../../components/extension-landing/extension-requirements.jsx'); const ExtensionRequirements = require('../../components/extension-landing/extension-requirements.jsx');
const ExtensionSection = require('../../components/extension-landing/extension-section.jsx'); const ExtensionSection = require('../../components/extension-landing/extension-section.jsx');
const InstallScratchLink = require('../../components/extension-landing/install-scratch-link.jsx'); const InstallScratchLink = require('../../components/extension-landing/install-scratch-link.jsx');
@ -32,57 +33,62 @@ class EV3 extends ExtensionLanding {
return ( return (
<div className="extension-landing ev3"> <div className="extension-landing ev3">
<ExtensionHeader <ExtensionHeader
imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltEv3Illustration'})} renderCopy={
imageSrc="/images/ev3/ev3-illustration.png" <FlexRow className="column extension-copy">
> <h1><img
<FlexRow className="column extension-copy">
<h1><img
alt=""
src="/images/ev3/ev3.svg"
/>LEGO MINDSTORMS EV3</h1>
<FormattedMessage
id="ev3.headerText"
values={{
ev3Link: (
<a
href="https://education.lego.com/en-us/middle-school/intro/mindstorms-ev3"
rel="noopener noreferrer"
target="_blank"
>
LEGO MINDSTORMS Education EV3
</a>
)
}}
/>
</FlexRow>
<ExtensionRequirements>
<span>
<img
alt="" alt=""
src="/svgs/extensions/windows.svg" src="/images/ev3/ev3.svg"
/>LEGO MINDSTORMS EV3</h1>
<FormattedMessage
id="ev3.headerText"
values={{
ev3Link: (
<a
href="https://education.lego.com/en-us/middle-school/intro/mindstorms-ev3"
rel="noopener noreferrer"
target="_blank"
>
LEGO MINDSTORMS Education EV3
</a>
)
}}
/> />
Windows 10+ </FlexRow>
</span> }
<span> renderImage={
<img <ExtensionVideo
alt="" videoId="0huu6wfiki"
src="/svgs/extensions/mac.svg" />}
/> renderRequirements={
macOS 10.13+ <ExtensionRequirements>
</span> <span>
<span> <img
<img src="/svgs/extensions/bluetooth.svg" /> alt=""
Bluetooth src="/svgs/extensions/windows.svg"
</span> />
<span> Windows 10 version 1709+
<img </span>
alt="" <span>
src="/svgs/extensions/scratch-link.svg" <img
/> alt=""
Scratch Link src="/svgs/extensions/mac.svg"
</span> />
</ExtensionRequirements> macOS 10.13+
</ExtensionHeader> </span>
<span>
<img src="/svgs/extensions/bluetooth.svg" />
Bluetooth
</span>
<span>
<img
alt=""
src="/svgs/extensions/scratch-link.svg"
/>
Scratch Link
</span>
</ExtensionRequirements>
}
/>
<OSChooser <OSChooser
currentOS={this.state.OS} currentOS={this.state.OS}
handleSetOS={this.onSetOS} handleSetOS={this.onSetOS}
@ -118,11 +124,11 @@ class EV3 extends ExtensionLanding {
values={{ values={{
scratch3Link: ( scratch3Link: (
<a <a
href="https://beta.scratch.mit.edu/" href="/projects/editor/?tutorial=ev3"
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Scratch 3.0 Scratch
</a> </a>
) )
}} }}
@ -239,30 +245,56 @@ class EV3 extends ExtensionLanding {
<h3><FormattedMessage id="ev3.starterProjects" /></h3> <h3><FormattedMessage id="ev3.starterProjects" /></h3>
<Steps> <Steps>
<ProjectCard <ProjectCard
cardUrl="https://beta.scratch.mit.edu/#239075992" cardUrl="/projects/269442346/editor?tutorial=ev3"
description={this.props.intl.formatMessage({id: 'ev3.waveHelloDescription'})} description={this.props.intl.formatMessage({id: 'ev3.starter1BasketballDescription'})}
imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltWaveHello'})} imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltStarter1Basketball'})}
imageSrc="/images/ev3/starter-wave-hello.png" imageSrc="/images/ev3/ev3-starter1.png"
title={this.props.intl.formatMessage({id: 'ev3.waveHelloTitle'})} title={this.props.intl.formatMessage({id: 'ev3.starter1BasketballTitle'})}
/> />
<ProjectCard <ProjectCard
cardUrl="https://beta.scratch.mit.edu/#239076020" cardUrl="/projects/269442350/editor?tutorial=ev3"
description={this.props.intl.formatMessage({id: 'ev3.distanceInstrumentDescription'})} description={this.props.intl.formatMessage({id: 'ev3.starter2MusicDescription'})}
imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltDistanceInstrument'})} imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltStarter2Music'})}
imageSrc="/images/ev3/starter-distance-instrument.png" imageSrc="/images/ev3/ev3-starter2.png"
title={this.props.intl.formatMessage({id: 'ev3.distanceInstrumentTitle'})} title={this.props.intl.formatMessage({id: 'ev3.starter2MusicTitle'})}
/> />
<ProjectCard <ProjectCard
cardUrl="https://beta.scratch.mit.edu/#239076044" cardUrl="/projects/269442354/editor?tutorial=ev3"
description={this.props.intl.formatMessage({id: 'ev3.spaceTacosDescription'})} description={this.props.intl.formatMessage({id: 'ev3.starter3SpaceDescription'})}
imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltSpaceTacos'})} imageAlt={this.props.intl.formatMessage({id: 'ev3.imgAltStarter3Space'})}
imageSrc="/images/ev3/starter-flying-game.png" imageSrc="/images/ev3/ev3-starter3.png"
title={this.props.intl.formatMessage({id: 'ev3.spaceTacosTitle'})} title={this.props.intl.formatMessage({id: 'ev3.starter3SpaceTitle'})}
/> />
</Steps> </Steps>
</ExtensionSection> </ExtensionSection>
<ExtensionSection className="faq"> <ExtensionSection className="faq">
<h2><FormattedMessage id="ev3.troubleshootingTitle" /></h2> <h2><FormattedMessage id="ev3.troubleshootingTitle" /></h2>
<h3 className="faq-title"><FormattedMessage id="ev3.checkOSVersionTitle" /></h3>
<p>
<FormattedMessage
id="ev3.checkOSVersionText"
values={{
winOSVersionLink: (
<a
href="https://support.microsoft.com/en-us/help/13443/windows-which-operating-system"
rel="noopener noreferrer"
target="_blank"
>
<FormattedMessage id="ev3.winOSVersionLinkText" />
</a>
),
macOSVersionLink: (
<a
href="https://support.apple.com/en-us/HT201260"
rel="noopener noreferrer"
target="_blank"
>
<FormattedMessage id="ev3.macOSVersionLinkText" />
</a>
)
}}
/>
</p>
<h3 className="faq-title"><FormattedMessage id="ev3.makeSurePairedTitle" /></h3> <h3 className="faq-title"><FormattedMessage id="ev3.makeSurePairedTitle" /></h3>
<p> <p>
<FormattedMessage <FormattedMessage
@ -280,6 +312,10 @@ class EV3 extends ExtensionLanding {
}} }}
/> />
</p> </p>
<h3 className="faq-title"><FormattedMessage id="ev3.reconnectTitle" /></h3>
<p>
<FormattedMessage id="ev3.reconnectText" />
</p>
<h3 className="faq-title"><FormattedMessage id="ev3.closeScratchCopiesTitle" /></h3> <h3 className="faq-title"><FormattedMessage id="ev3.closeScratchCopiesTitle" /></h3>
<p> <p>
<FormattedMessage id="ev3.closeScratchCopiesText" /> <FormattedMessage id="ev3.closeScratchCopiesText" />

View file

@ -18,16 +18,22 @@
"ev3.clickMotorBlock": "Find the {motorBlockText} block and click on it.", "ev3.clickMotorBlock": "Find the {motorBlockText} block and click on it.",
"ev3.motorBlockText": "\"motor A turn this way\"", "ev3.motorBlockText": "\"motor A turn this way\"",
"ev3.starterProjects": "Starter Projects", "ev3.starterProjects": "Starter Projects",
"ev3.waveHelloTitle": "Wave Hello", "ev3.starter1BasketballTitle": "Play Basketball",
"ev3.waveHelloDescription": "Make a puppet robot and have a friendly chat.", "ev3.starter1BasketballDescription": "Move in front of the distance sensor to bounce the ball.",
"ev3.distanceInstrumentTitle": "Distance Instrument", "ev3.starter2MusicTitle": "Make Music",
"ev3.distanceInstrumentDescription": "Move your body in front of the sensor to make music.", "ev3.starter2MusicDescription": "Press the buttons to play saxophone and drums.",
"ev3.spaceTacosTitle": "Space Tacos", "ev3.starter3SpaceTitle": "Space Tacos",
"ev3.spaceTacosDescription": "Build your own controller to catch tacos in space.", "ev3.starter3SpaceDescription": "Build your own controller to catch tacos in space.",
"ev3.troubleshootingTitle": "Troubleshooting", "ev3.troubleshootingTitle": "Troubleshooting",
"ev3.checkOSVersionTitle": "Make sure your operating system is compatible with Scratch Link",
"ev3.checkOSVersionText": "The minimum operating system versions are listed at the top of this page. See instructions for checking your version of {winOSVersionLink} or {macOSVersionLink}.",
"ev3.winOSVersionLinkText": "Windows",
"ev3.macOSVersionLinkText": "Mac OS",
"ev3.makeSurePairedTitle": "Make sure your computer is paired with your EV3", "ev3.makeSurePairedTitle": "Make sure your computer is paired with your EV3",
"ev3.makeSurePairedText": "Your computer needs to be paired with your EV3 before it can connect to Scratch. We try to do this automatically the first time you add the EV3 extension, but if it isn't working you can try these {pairingInstructionLink}.", "ev3.makeSurePairedText": "Your computer needs to be paired with your EV3 before it can connect to Scratch. We try to do this automatically the first time you add the EV3 extension, but if it isn't working you can try these {pairingInstructionLink}.",
"ev3.pairingInstructionText": "bluetooth pairing instructions from LEGO", "ev3.pairingInstructionText": "bluetooth pairing instructions from LEGO",
"ev3.reconnectTitle": "On Windows, try un-pairing before connecting",
"ev3.reconnectText": "If you have connected before and are unable to reconnect, try manually un-pairing your EV3 from your computer: open your Bluetooth settings, find your EV3, and remove it.",
"ev3.closeScratchCopiesTitle": "Close other copies of Scratch", "ev3.closeScratchCopiesTitle": "Close other copies of Scratch",
"ev3.closeScratchCopiesText": "Only one copy of Scratch can connect with the EV3 at a time. If you have Scratch open in other browser tabs, close it and try again.", "ev3.closeScratchCopiesText": "Only one copy of Scratch can connect with the EV3 at a time. If you have Scratch open in other browser tabs, close it and try again.",
"ev3.otherComputerConnectedTitle": "Make sure no other computer is connected to your EV3", "ev3.otherComputerConnectedTitle": "Make sure no other computer is connected to your EV3",
@ -41,7 +47,7 @@
"ev3.imgAltWaitForWindows": "Windows will notify you when the EV3 is ready.", "ev3.imgAltWaitForWindows": "Windows will notify you when the EV3 is ready.",
"ev3.imgAltEnterPasscodeMac": "Enter the passcode into the connection request window opening on your Mac.", "ev3.imgAltEnterPasscodeMac": "Enter the passcode into the connection request window opening on your Mac.",
"ev3.imgAltPlugInMotor": "To find port A: hold the EV3 with the screen and buttons facing you, with the screen above the buttons. Port A is on top, and it is the left-most one", "ev3.imgAltPlugInMotor": "To find port A: hold the EV3 with the screen and buttons facing you, with the screen above the buttons. Port A is on top, and it is the left-most one",
"ev3.imgAltWaveHello": "A Scratch project with a waving fairy.", "ev3.imgAltStarter1Basketball": "A Scratch project with a basketball.",
"ev3.imgAltDistanceInstrument": "A Scratch project with a guitar.", "ev3.imgAltStarter2Music": "A Scratch project with musical instruments.",
"ev3.imgAltSpaceTacos": "A Scratch project with Scratch Cat and a taco in space." "ev3.imgAltStarter3Space": "A Scratch project with Scratch Cat and a taco in space."
} }

View file

@ -22,18 +22,37 @@ const Faq = injectIntl(props => (
<dt><FormattedMessage id="faq.makeGameTitle" /></dt> <dt><FormattedMessage id="faq.makeGameTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.makeGameBody" /></dd> <dd><FormattedHTMLMessage id="faq.makeGameBody" /></dd>
<dt><FormattedMessage id="faq.whoUsesScratchTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.whoUsesScratchBody" /></dd>
<dt><FormattedMessage id="faq.requirementsTitle" /></dt> <dt><FormattedMessage id="faq.requirementsTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.requirementsBody" /></dd> <dd><FormattedHTMLMessage id="faq.requirementsBody" /></dd>
<b><FormattedHTMLMessage id="faq.requirementsDesktop" /></b>
<ul>
<li><FormattedHTMLMessage id="faq.requirementsDesktopChrome" /></li>
<li><FormattedHTMLMessage id="faq.requirementsDesktopEdge" /></li>
<li><FormattedHTMLMessage id="faq.requirementsDesktopFirefox" /></li>
<li><FormattedHTMLMessage id="faq.requirementsDesktopSafari" /></li>
<li><FormattedHTMLMessage id="faq.requirementsDesktopIE" /></li>
</ul>
<b><FormattedHTMLMessage id="faq.requirementsTablet" /></b>
<ul>
<li><FormattedHTMLMessage id="faq.requirementsTabletChrome" /></li>
<li><FormattedHTMLMessage id="faq.requirementsTabletSafari" /></li>
</ul>
<FormattedMessage id="faq.requirementsNote" />
<ul>
<li><FormattedHTMLMessage id="faq.requirementsNoteDesktop" /></li>
<li><FormattedHTMLMessage id="faq.requirementsNoteWebGL" /></li>
<li><FormattedHTMLMessage id="faq.requirementsNoteTablets" /></li>
</ul>
<dt><FormattedMessage id="faq.offlineTitle" /></dt> <dt><FormattedMessage id="faq.offlineTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.offlineBody" /></dd> <dd><FormattedHTMLMessage id="faq.offlineBody" /></dd>
<dt><FormattedMessage id="faq.uploadOldTitle" /></dt> <dt><FormattedMessage id="faq.uploadOldTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.uploadOldBody" /></dd> <dd><FormattedHTMLMessage id="faq.uploadOldBody" /></dd>
<dt><FormattedMessage id="faq.recordVideoTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.recordVideoBody" /></dd>
<dt><FormattedMessage id="faq.scratchCostTitle" /></dt> <dt><FormattedMessage id="faq.scratchCostTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.scratchCostBody" /></dd> <dd><FormattedHTMLMessage id="faq.scratchCostBody" /></dd>
@ -41,26 +60,51 @@ const Faq = injectIntl(props => (
<dd><FormattedHTMLMessage id="faq.mediaLabBody" /></dd> <dd><FormattedHTMLMessage id="faq.mediaLabBody" /></dd>
</dl> </dl>
</section> </section>
<section id="privacy"> <section id="scratch3">
<span className="nav-spacer" /> <span className="nav-spacer" />
<h2><FormattedMessage id="faq.privacyTitle" /></h2> <h2><FormattedMessage id="faq.scratch3Title" /></h2>
<dl> <dl>
<dt><FormattedMessage id="faq.accountInfoTitle" /></dt> <dt><FormattedMessage id="faq.aboutScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.accountInfoList" /></dd> <dd><FormattedHTMLMessage id="faq.aboutScratch3Body" /></dd>
<dt><FormattedMessage id="faq.reportBugsScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.reportBugsScratch3Body" /></dd>
<dt><FormattedMessage id="faq.languagesScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.languagesScratch3Body" /></dd>
<dt><FormattedMessage id="faq.removedBlocksScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.removedBlocksScratch3Body" /></dd>
<dt><FormattedMessage id="faq.newBlocksScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.newBlocksScratch3Body" /></dd>
<ul> <ul>
<li><FormattedHTMLMessage id="faq.privacyUsername" /></li> <li><FormattedHTMLMessage id="faq.newBlocksSoundEffect" /></li>
<li><FormattedHTMLMessage id="faq.privacyCountry" /></li> <li><FormattedHTMLMessage id="faq.newBlocksOperators" /></li>
<li><FormattedHTMLMessage id="faq.privacyBirthdate" /></li> <li><FormattedHTMLMessage id="faq.newBlocksPen" /></li>
<li><FormattedHTMLMessage id="faq.privacyGender" /></li> <li><FormattedHTMLMessage id="faq.newBlocksGlide" /></li>
<li><FormattedHTMLMessage id="faq.privacyEmail" /></li> <li><FormattedHTMLMessage id="faq.newBlocksExtensions" /></li>
</ul> </ul>
<dd><FormattedHTMLMessage id="faq.accountPublicInfo" /></dd> <dt><FormattedMessage id="faq.biggerBlocksScratch3Title" /></dt>
<dt><FormattedMessage id="faq.dataCollectionTitle" /></dt> <dd><FormattedHTMLMessage id="faq.biggerBlocksScratch3Body" /></dd>
<dd><FormattedHTMLMessage id="faq.dataCollectionOne" /></dd> <dt><FormattedMessage id="faq.paintEditorScratch3Title" /></dt>
<dt><FormattedMessage id="faq.rentInfoTitle" /></dt> <dd><FormattedHTMLMessage id="faq.paintEditorScratch3Body" /></dd>
<dd><FormattedHTMLMessage id="faq.rentInfoBody" /></dd> <ul>
<dt><FormattedMessage id="faq.viewUnsharedTitle" /></dt> <li><FormattedHTMLMessage id="faq.paintEditorLayout" /></li>
<dd><FormattedHTMLMessage id="faq.viewUnsharedBody" /></dd> <li><FormattedHTMLMessage id="faq.paintEditorTools" /></li>
<li><FormattedHTMLMessage id="faq.paintEditorColors" /></li>
<li><FormattedHTMLMessage id="faq.paintEditorVector" /></li>
<li><FormattedHTMLMessage id="faq.paintEditorLayers" /></li>
<li><FormattedHTMLMessage id="faq.paintEditorGradients" /></li>
</ul>
<dt><FormattedMessage id="faq.soundEditorScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.soundEditorScratch3Body" /></dd>
<ul>
<li><FormattedHTMLMessage id="faq.soundEditorRecording" /></li>
<li><FormattedHTMLMessage id="faq.soundEditorTrimming" /></li>
<li><FormattedHTMLMessage id="faq.soundEditorEffects" /></li>
</ul>
<dt><FormattedMessage id="faq.tipsWindwScratch3Title" /></dt>
<dd><FormattedHTMLMessage id="faq.tipsWindowScratch3Body" /></dd>
</dl> </dl>
</section> </section>
<section id="remix"> <section id="remix">
@ -81,12 +125,18 @@ const Faq = injectIntl(props => (
<span className="nav-spacer" /> <span className="nav-spacer" />
<h2><FormattedMessage id="faq.accountsTitle" /></h2> <h2><FormattedMessage id="faq.accountsTitle" /></h2>
<dl> <dl>
<dt><FormattedMessage id="faq.confirmedAccountTitle" /></dt> <dt><FormattedMessage id="faq.whyAccountTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.confirmedAccountBody" /></dd> <dd><FormattedHTMLMessage id="faq.whyAccountBody" /></dd>
<dt><FormattedMessage id="faq.checkConfirmedTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.checkConfirmedBody" /></dd> <dt><FormattedMessage id="faq.createAccountTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.createAccountBody" /></dd>
<dt><FormattedMessage id="faq.howToConfirmTitle" /></dt> <dt><FormattedMessage id="faq.howToConfirmTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.howToConfirmBody" /></dd> <dd><FormattedHTMLMessage id="faq.howToConfirmBody" /></dd>
<dt><FormattedMessage id="faq.checkConfirmedTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.checkConfirmedBody" /></dd>
<dt><FormattedMessage id="faq.requireConfirmTitle" /></dt> <dt><FormattedMessage id="faq.requireConfirmTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.requireConfirmBody" /></dd> <dd><FormattedHTMLMessage id="faq.requireConfirmBody" /></dd>
<dt><FormattedMessage id="faq.forgotPasswordTitle" /></dt> <dt><FormattedMessage id="faq.forgotPasswordTitle" /></dt>
@ -147,6 +197,20 @@ const Faq = injectIntl(props => (
<dd><FormattedHTMLMessage id="faq.stolenAccountBody" /></dd> <dd><FormattedHTMLMessage id="faq.stolenAccountBody" /></dd>
</dl> </dl>
</section> </section>
<section id="scratch-extensions">
<span className="nav-spacer" />
<h2><FormattedMessage id="faq.scratchExtensionsTitle" /></h2>
<dl>
<dt><FormattedMessage id="faq.aboutExtensionsTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.aboutExtensionsBody" /></dd>
<dt><FormattedMessage id="faq.howToAddExtensionsTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.howToAddExtensionsBody" /></dd>
<dt><FormattedMessage id="faq.createExtensionsTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.createExtensionsBody" /></dd>
<dt><FormattedMessage id="faq.scratchXTitle" /></dt>
<dd><FormattedMessage id="faq.scratchXBody" /></dd>
</dl>
</section>
<section id="clouddata"> <section id="clouddata">
<span className="nav-spacer" /> <span className="nav-spacer" />
<h2><FormattedMessage id="faq.cloudDataTitle" /></h2> <h2><FormattedMessage id="faq.cloudDataTitle" /></h2>
@ -169,8 +233,6 @@ const Faq = injectIntl(props => (
<dd><FormattedHTMLMessage id="faq.newScratcherCloudBody" /></dd> <dd><FormattedHTMLMessage id="faq.newScratcherCloudBody" /></dd>
<dt><FormattedMessage id="faq.multiplayerTitle" /></dt> <dt><FormattedMessage id="faq.multiplayerTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.multiplayerBody" /></dd> <dd><FormattedHTMLMessage id="faq.multiplayerBody" /></dd>
<dt><FormattedMessage id="faq.cloudLagTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.cloudLagBody" /></dd>
</dl> </dl>
</section> </section>
<section id="schools"> <section id="schools">
@ -179,36 +241,34 @@ const Faq = injectIntl(props => (
<dl> <dl>
<dt><FormattedMessage id="faq.howTitle" /></dt> <dt><FormattedMessage id="faq.howTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.howBody" /></dd> <dd><FormattedHTMLMessage id="faq.howBody" /></dd>
<dt><FormattedMessage id="faq.ageTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.ageBody" /></dd>
<dt><FormattedMessage id="faq.noInternetTitle" /></dt> <dt><FormattedMessage id="faq.noInternetTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.noInternetBody" /></dd> <dd><FormattedHTMLMessage id="faq.noInternetBody" /></dd>
<dt><FormattedMessage id="faq.communityTitle" /></dt> <dt><FormattedMessage id="faq.communityTitle" /></dt>
<dd><FormattedMessage id="faq.communityBody" /></dd> <dd><FormattedHTMLMessage id="faq.communityBody" /></dd>
<dt><FormattedMessage id="faq.teacherAccountTitle" /></dt> <dt><FormattedMessage id="faq.teacherAccountTitle" /></dt>
<dd><FormattedMessage id="faq.teacherAccountBody" /></dd> <dd><FormattedHTMLMessage id="faq.teacherAccountBody" /></dd>
<dt><FormattedMessage id="faq.requestTitle" /></dt> <dt><FormattedMessage id="faq.requestTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.requestBody" /></dd> <dd><FormattedHTMLMessage id="faq.requestBody" /></dd>
<dt><FormattedMessage id="faq.edTitle" /></dt>
<dd><FormattedHTMLMessage id="faq.edBody" /></dd>
<dt><FormattedMessage id="faq.dataTitle" /></dt> <dt><FormattedMessage id="faq.dataTitle" /></dt>
<dd><FormattedMessage id="faq.dataBody" /></dd> <dd><FormattedMessage id="faq.dataBody" /></dd>
<dt><FormattedMessage id="faq.lawComplianceTitle" /></dt> <dt><FormattedMessage id="faq.lawComplianceTitle" /></dt>
<dd><FormattedMessage id="faq.lawComplianceBody" /></dd> <dd><FormattedHTMLMessage id="faq.lawComplianceBody" /></dd>
</dl> </dl>
<i><FormattedHTMLMessage id="faq.schoolsMoreInfo" /></i>
</section> </section>
</div> </div>
<nav> <nav>
<ol> <ol>
<li><a href="#about-scratch"><FormattedMessage id="faq.aboutTitle" /></a></li> <li><a href="#about-scratch"><FormattedMessage id="faq.aboutTitle" /></a></li>
<li><a href="#privacy"><FormattedMessage id="faq.privacyTitle" /></a></li> <li><a href="#scratch3"><FormattedMessage id="faq.scratch3Title" /></a></li>
<li><a href="#remix"><FormattedMessage id="faq.remixTitle" /></a></li> <li><a href="#remix"><FormattedMessage id="faq.remixTitle" /></a></li>
<li><a href="#accounts"><FormattedMessage id="faq.accountsTitle" /></a></li> <li><a href="#accounts"><FormattedMessage id="faq.accountsTitle" /></a></li>
<li><a href="#permissions"><FormattedMessage id="faq.permissionsTitle" /></a></li> <li><a href="#permissions"><FormattedMessage id="faq.permissionsTitle" /></a></li>
<li><a href="#inappropriate-content"> <li><a href="#inappropriate-content">
<FormattedMessage id="faq.inappropriateContentTitle" /> <FormattedMessage id="faq.inappropriateContentTitle" />
</a></li> </a></li>
<li><a href="#scratch-extensions">
<FormattedMessage id="faq.scratchExtensionsTitle" />
</a></li>
<li><a href="#clouddata"><FormattedMessage id="faq.cloudDataTitle" /></a></li> <li><a href="#clouddata"><FormattedMessage id="faq.cloudDataTitle" /></a></li>
<li><a href="#schools"><FormattedMessage id="faq.schoolsTitle" /></a></li> <li><a href="#schools"><FormattedMessage id="faq.schoolsTitle" /></a></li>
</ol> </ol>

View file

@ -2,141 +2,178 @@
"faq.title":"Frequently Asked Questions (FAQ)", "faq.title":"Frequently Asked Questions (FAQ)",
"faq.intro":"On this page, youll find answers to frequently asked questions about Scratch.", "faq.intro":"On this page, youll find answers to frequently asked questions about Scratch.",
"faq.aboutTitle":"General Questions", "faq.aboutTitle":"General Questions",
"faq.privacyTitle":"Privacy Policy", "faq.scratch3Title":"Scratch 3.0",
"faq.remixTitle":"Remixing and Copying", "faq.remixTitle":"Remixing and Copying",
"faq.accountsTitle":"Accounts", "faq.accountsTitle":"Accounts",
"faq.permissionsTitle":"Licensing and Permissions", "faq.permissionsTitle":"Licensing and Permissions",
"faq.inappropriateContentTitle":"Inappropriate Content", "faq.inappropriateContentTitle":"Inappropriate Content",
"faq.cloudDataTitle":"Cloud Data", "faq.scratchExtensionsTitle":"Scratch Extensions",
"faq.cloudDataTitle":"Cloud Variables",
"faq.aboutScratchTitle":"What is Scratch, and what can I do with it?", "faq.aboutScratchTitle":"What is Scratch, and what can I do with it?",
"faq.aboutScratchBody":"Scratch is a programming language and online community where you can create your own interactive stories, games, and animations -- and share your creations with others around the world. In the process of designing and programming Scratch projects, young people learn to think creatively, reason systematically, and work collaboratively. To learn more about Scratch, check out the <a href=\"/about\">About Scratch</a> page.", "faq.aboutScratchBody":"With the Scratch programming language and online community, you can create your own interactive stories, games, and animations -- and share your creations with others around the world. As young people create and share Scratch projects, they learn to think creatively, reason systematically, and work collaboratively. To learn more about Scratch, see the <a href=\"/about\">About Scratch</a> page.",
"faq.makeGameTitle":"How do I make a game or animation with Scratch?", "faq.makeGameTitle":"How do I make a game or animation with Scratch?",
"faq.makeGameBody":"Check out the <a href=\"/tips\">tips page</a> to see lots of ways to get started with Scratch. Or just <a href=\"/projects/editor/?tip_bar=getStarted\">dive in</a> to the project editor.", "faq.makeGameBody":"Check out the <a href=\"/ideas\">Ideas page</a> to see lots of ways to get started with Scratch",
"faq.whoUsesScratchTitle":"Who uses Scratch?",
"faq.whoUsesScratchBody":"Scratch is used by people from all backgrounds, in all countries around the world, in all types of settings -- homes, schools, libraries, museums, and more. Scratch is designed especially for young people ages 8 to 16, but people of all ages create and share with Scratch. Younger children may want to try <a href=\"https://www.scratchjr.org/\">ScratchJr</a>, a simplified version of Scratch designed for ages 5 to 7.",
"faq.requirementsTitle":"What are the system requirements for Scratch?", "faq.requirementsTitle":"What are the system requirements for Scratch?",
"faq.requirementsBody":"To run Scratch 2.0, you need to be using (1) a Windows, ChromeOS, Mac, or Linux computer; (2) a version of <a href=\"https://get.adobe.com/flashplayer/\">Adobe Flash Player</a> released on or after June 15, 2016; (3) a relatively recent web browser: one of the latest two versions of <a href=\"http://google.com/chrome/\">Chrome</a> (Windows, ChromeOS, Mac or Linux), <a href=\"http://www.mozilla.org/firefox/new/\">Firefox</a> (Windows or Mac only), <a href=\"https://support.apple.com/downloads/safari\">Safari</a> (Mac only), <a href=\"https://www.microsoft.com/windows/microsoft-edge\">Edge</a> (Windows only), or <a href=\"https://www.microsoft.com/download/internet-explorer.aspx\">Internet Explorer 11</a> (Windows only). If your computer doesnt meet these requirements, you can try downloading and installing <a href=\"/scratch_1.4\">Scratch 1.4</a>, which you can still use to share projects to the Scratch 2.0 website.", "faq.requirementsBody":"Scratch will run in most current web browsers on desktops, laptops and tablets. You can view projects on mobile phones, but currently you are not able to create or edit projects on phones. Below is the list of officially supported browsers.",
"faq.requirementsDesktop":"Desktop",
"faq.requirementsDesktopChrome":"Chrome (63+)",
"faq.requirementsDesktopEdge":"Edge (15+)",
"faq.requirementsDesktopFirefox":"Firefox (57+)",
"faq.requirementsDesktopSafari":"Safari (11+)",
"faq.requirementsDesktopIE":"Internet Explorer is NOT supported.",
"faq.requirementsTablet":"Tablet",
"faq.requirementsTabletChrome":"Mobile Chrome (62+)",
"faq.requirementsTabletSafari":"Mobile Safari (11+)",
"faq.requirementsNote":"Note:",
"faq.requirementsNoteDesktop":"If your computer doesnt meet these requirements, you can try the <a href=\"/download\">Scratch Desktop</a> editor (see next item in FAQ). ",
"faq.requirementsNoteWebGL":"If you encounter a WebGL error, try a different browser.",
"faq.requirementsNoteTablets":"On tablets, there is currently not a way to use \"key pressed\" blocks or right-click context menus.",
"faq.offlineTitle":"Do you have a downloadable version so I can create and view projects offline?", "faq.offlineTitle":"Do you have a downloadable version so I can create and view projects offline?",
"faq.offlineBody":"The Scratch 2.0 offline editor allows you to create Scratch projects without an internet connection. You can <a href=\"/scratch2download/\">download Scratch 2.0</a> from the website. You can also still use <a href=\"/scratch_1.4\">Scratch 1.4</a>. Note: You can have both Scratch 1.4 and 2.0 on your computer.", "faq.offlineBody":"The Scratch Desktop editor allows you to create Scratch projects without an internet connection. You can download <a href=\"/download\">Scratch Desktop</a> from the website. This was previously called the Scratch Offline editor.",
"faq.uploadOldTitle":"Can I still upload projects created with older versions of Scratch to the website?", "faq.uploadOldTitle":"Can I still upload projects created with older versions of Scratch to the website?",
"faq.uploadOldBody":"Yes - you can share or upload projects made with earlier versions of Scratch, and they will be visible and playable. (However, you cant download projects made with or edited in later versions of Scratch and open them in earlier versions. For example, you cant open a Scratch 2.0 project in <a href=\"/scratch_1.4\">Scratch 1.4</a>, because <a href=\"/scratch_1.4\">Scratch 1.4</a> doesnt know how to read the .sb2 project file format.)", "faq.uploadOldBody":"Yes: You can share or upload projects made with earlier versions of Scratch, and they will be visible and playable. (However, you cant download projects made with or edited in later versions of Scratch and open them in earlier versions. For example, you cant open a Scratch 3.0 project in the desktop version of <a href=\"/download/scratch2\">Scratch 2.0</a>, because Scratch 2.0 doesnt know how to read the .sb3 project file format.)",
"faq.recordVideoTitle":"Can I record a video of my Scratch project?",
"faq.recordVideoBody":"Yes, you can record a video of your Scratch project up to 60 seconds. In the Scratch editor, from the File menu, select \"Record Project Video.\" (You need to be signed in to see this option.) You can choose additional recording options (such as recording sound and mouse clicks) through the \"More Options\" menu. Then, run your project however you'd like. Once the recording is done, follow the instructions to download the file to your computer. Depending on what kind of computer you have, you may need to download another program like the <a href=\"http://www.videolan.org/vlc/index.html\">VLC Media Player</a> to play the file. This file will run on YouTube, Vimeo, and Facebook, but may need to be converted for other websites like Twitter or Tumblr.",
"faq.scratchCostTitle":"How much does Scratch cost? Do I need a license?", "faq.scratchCostTitle":"How much does Scratch cost? Do I need a license?",
"faq.scratchCostBody":"Scratch is and always will be free. You dont need a license to use Scratch in your school, home, or anywhere else. The development and maintenance of Scratch is paid for by grants and donations. If youd like to contribute to Scratch, check out our <a href=\"https://secure.donationpay.org/scratchfoundation/\">Donate page</a>.", "faq.scratchCostBody":"Scratch is and always will be free. You dont need a license to use Scratch in your school, home, or anywhere else. The development and maintenance of Scratch is paid for by grants and donations. If youd like to contribute to Scratch, check out our <a href=\"https://secure.donationpay.org/scratchfoundation/\">Donate page</a>.",
"faq.mediaLabTitle":"Who created Scratch?", "faq.mediaLabTitle":"Who created Scratch?",
"faq.mediaLabBody":"Scratch is developed and maintained by the Scratch Team at the <a href=\"http://llk.media.mit.edu/\">Lifelong Kindergarten group</a> at <a href=\"http://www.media.mit.edu/\">MIT Media Lab</a>.", "faq.mediaLabBody":"Scratch is developed and maintained by the Scratch Team at the <a href=\"http://llk.media.mit.edu/\">Lifelong Kindergarten group</a> at <a href=\"http://www.media.mit.edu/\">MIT Media Lab</a>.",
"faq.accountInfoTitle":"What information do you ask for during account registration?", "faq.aboutScratch3Title":"What is Scratch 3.0?",
"faq.accountInfoList":"To protect the privacy of our community members, we limit what we collect and what we publish on the website. During the registration process, we ask for the following information:", "faq.aboutScratch3Body":"Scratch 3.0 is the latest generation of Scratch, launched on January 2, 2019. It is designed to expand how, what, and where you can create with Scratch. It includes dozens of new sprites, a totally new sound editor, and many new programming blocks. And with Scratch 3.0, youre able to create and play projects on your tablet, in addition to your laptop or desktop computer.",
"faq.privacyUsername":"username - We ask that users avoid using their real names or other identifying information.", "faq.reportBugsScratch3Title":"How can I report bugs and share feedback on Scratch 3.0?",
"faq.privacyCountry":"country", "faq.reportBugsScratch3Body":"You can report bugs and share feedback in the <a href=\"https://scratch.mit.edu/discuss/3/\">Bugs & Glitches</a> section of the Scratch discussion forums.",
"faq.privacyBirthdate":"birth month and year - We use this to confirm ownership of the account if the owner loses the password and email or asks to close an account.", "faq.languagesScratch3Title":"Is Scratch 3.0 available in multiple languages?",
"faq.privacyGender":"gender", "faq.languagesScratch3Body":"Yes. To change the language of the programming blocks, click on the “globe” icon in the top navigation bar of the programming editor, then click on the dropdown menu to select a language.<br /><br />All of our translations are done by volunteers. The Scratch 3.0 editor has already been translated into 40+ languages. You can view all the languages currently being translated and reviewed on our <a href=\"https://www.transifex.com/llk/scratch-editor/\">translation server</a>. If you want to help with translation or review, please contact <a href=\"mailto:translate@scratch.mit.edu\">translate@scratch.mit.edu</a>.",
"faq.privacyEmail":"contact email address - If the account holder is younger than 16, we ask for the email address of their parent or guardian. We do not send email to this address except when someone requests to have the account password reset.", "faq.removedBlocksScratch3Title":"Does Scratch 3.0 remove any coding blocks from earlier versions of Scratch?",
"faq.accountPublicInfo":"The username and country of the account holder are displayed publicly on their profile page. The birth month / year, email address, and gender associated with the account are not displayed publicly. We collect this info so we can know the age and gender of our users in aggregate, and for research purposes. We do not sell or rent information about our users to anyone.", "faq.removedBlocksScratch3Body":"No coding blocks have been removed in Scratch 3.0, but some have changed a bit and others have moved into \"Extensions\" (as described below, under \"Where did the Pen blocks go?..\").",
"faq.dataCollectionTitle":"What data is collected from people while they use the website?", "faq.newBlocksScratch3Title":"Does Scratch 3.0 introduce new blocks?",
"faq.dataCollectionOne":"When a user logs in, the Scratch website asks their browser to put an <a href=\"http://en.wikipedia.org/wiki/HTTP_cookie\">http cookie</a> on their computer in order to remember that they are logged in while they browse different pages. We collect some data on where users click and which parts of the site they visit using Google Analytics. This \"click data\" helps us figure out ways to improve the website.", "faq.newBlocksScratch3Body":"Yes! In Scratch 3.0 youll find:",
"faq.dataCollectionTwo":"Some of the information and data collected on the Scratch website are used in research studies intended to improve our understanding of how people learn with Scratch. The results of this research are shared with educators and researchers through conferences, journals, and other publications. You can find out more on our <a href=\"/info/research\">Research page</a>.", "faq.newBlocksSoundEffect":"New \"sound effect\" blocks",
"faq.rentInfoTitle":"Does the Scratch Team sell or rent information about users of Scratch to anyone?", "faq.newBlocksOperators":"New operators that make it easier to work with text (strings)",
"faq.rentInfoBody":"No.", "faq.newBlocksPen":"New pen blocks, including support for transparency",
"faq.viewUnsharedTitle":"Can the Scratch Team view unshared projects on my 'My Stuff' page?", "faq.newBlocksGlide":"New glide block to move easily to a sprite (or random point)",
"faq.viewUnsharedBody":"Since the Scratch Team is responsible for moderation, we have access to all content stored on the Scratch website - including unshared projects. If you prefer to work on projects in complete privacy, you can use either the <a href=\"/scratch2download\">Scratch 2.0 offline editor</a> or <a href=\"/scratch_1.4\">Scratch 1.4</a>.", "faq.newBlocksExtensions":"Many new capabilities through \"Scratch Extensions\" (see the Extensions section below)",
"faq.remixDefinitionTitle":"What is a remix?", "faq.biggerBlocksScratch3Title":"Why are the blocks bigger in Scratch 3.0 than in earlier versions?",
"faq.biggerBlocksScratch3Body":"In order to make Scratch 3.0 work well on touch devices (like many Chromebooks, Windows Surface laptops, and tablets), we needed to make the blocks bigger, so that its easier to drag and tap the blocks. In addition, blocks are slightly bigger in Scratch 3.0 to help address issues we observed with new users having trouble clicking and dragging small interface elements.",
"faq.extensionsScratch3Title":"Where did the Pen blocks go? Where did the Music blocks go? Where did the Video Sensing blocks go?",
"faq.extensionsScratch3Body":"The Pen, Music, and Video Sensing blocks have been moved into extensions. Extensions can be added by clicking the button on the bottom left of the screen (see the \"Extensions\" section below).",
"faq.paintEditorScratch3Title":"What are the new features in the Paint Editor?",
"faq.paintEditorScratch3Body":"The Paint Editor has been redesigned to provide powerful new features while also making it easier to use. Changes and new features include:",
"faq.paintEditorLayout":"New layout that makes available tools and options more visible",
"faq.paintEditorTools":"New tools such as an \"eraser\" that works in vector mode",
"faq.paintEditorColors":"More options for selecting and adjusting colors",
"faq.paintEditorVector":"More control over vector points (curve handles and point modes)",
"faq.paintEditorLayers":"Additional controls for ordering layers (\"bring to front\", \"move to back\", etc.)",
"faq.paintEditorGradients":"New gradient controls",
"faq.soundEditorScratch3Title":"What are the new features in the Sound Editor?",
"faq.soundEditorScratch3Body":"The Sound Editor has been redesigned to make it easier to record and manipulate sounds. It offers a number of new features:",
"faq.soundEditorRecording":"New recording system that is easier to use",
"faq.soundEditorTrimming":"New audio trimming system that is easier to use",
"faq.soundEditorEffects":"New sound effects (such as \"faster\", \"slower\", \"echo\", and \"robot\")",
"faq.tipsWindwScratch3Title":"What happened to the Scratch Tips Window?",
"faq.tipsWindowScratch3Body":"Instead of the Tips Window, Scratch 3.0 provides similar material through the Tutorials Library, which can be accessed through the <i>Tutorials</i> link in the top navigation bar in the programming editor. Youll find tutorials for entire projects (like \"Make a Chase Game\") or specific blocks and features (such as \"Record a Sound\" or \"Make it Spin\"). More tutorials will be added soon (such as \"Pong Game\" and \"Make It Fly\").",
"faq.remixDefinitionTitle":"What is a remix?",
"faq.remixDefinitionBody":"When a Scratcher makes a copy of someone elses project and modifies it to add their own ideas (for example, by changing scripts or costumes), the resulting project is called a \"remix\". Every project shared to the Scratch website can be remixed. We consider even a minor change to be a valid remix, as long as credit is given to the original project creator and others who made significant contributions to the remix.", "faq.remixDefinitionBody":"When a Scratcher makes a copy of someone elses project and modifies it to add their own ideas (for example, by changing scripts or costumes), the resulting project is called a \"remix\". Every project shared to the Scratch website can be remixed. We consider even a minor change to be a valid remix, as long as credit is given to the original project creator and others who made significant contributions to the remix.",
"faq.remixableTitle":"Why does the Scratch Team require that all projects be “remixable”?", "faq.remixableTitle":"Why does the Scratch Team require that all projects be “remixable”?",
"faq.remixableBody":"We believe that viewing and remixing interesting projects is a great way to learn to program, and leads to cool new ideas. Thats why the source code is visible for every project shared to the Scratch website.", "faq.remixableBody":"We believe that remixing other peoples projects is a great way to learn to program and to create interesting projects. Through remixing, creative ideas spread through the Scratch community, and everyone benefits. All projects shared on the Scratch website are covered by the “Creative Commons Share Alike” license, which means that you can remix any project you see on the Scratch website -- and everyone else can remix any of the projects that you share on the website.",
"faq.creativeCommonsTitle":"What if I dont want others to remix my projects?", "faq.creativeCommonsTitle":"What if I dont want others to remix my projects?",
"faq.creativeCommonsBody":"By publishing your project on the Scratch website, you agree to license it under a <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">Creative Commons Share Alike</a> license. If you dont want others to view and remix your creations, dont share them on the Scratch website.", "faq.creativeCommonsBody":"Remixing is an important part of the Scratch community. If you dont want others to view or remix your creations, you can still create projects on the Scratch website, but dont share them on the website.",
"faq.fairUseTitle":"Can I use images / sounds / media from the internet in my projects?", "faq.fairUseTitle":"Can I use images / sounds / media from the internet in my projects?",
"faq.fairUseBody":"It's important to respect the original creators wishes regarding remixing. If you choose to integrate someone elses work into your own, be sure to give them credit on the project “credits” section, and include a link back to the original. To find art / sounds that are already licensed for remixing, check out the <a href=\"http://search.creativecommons.org/\">Creative Commons search page</a>.", "faq.fairUseBody":"If you choose to integrate someone elses work into your own, be sure to give them credit on the project “credits” section, and include a link back to the original. To find art / sounds that are already licensed for remixing, check out the <a href=\"http://search.creativecommons.org/\">Creative Commons search page</a>.",
"faq.confirmedAccountTitle":"What is a “confirmed” Scratch account?", "faq.whyAccountTitle":"Why is it useful to have a Scratch account?",
"faq.confirmedAccountBody":"A confirmed account on Scratch lets you share projects, write comments, and create studios. Confirming your account also lets you receive email updates from the Scratch Team.", "faq.whyAccountBody":"Even without an account, you can play other peoples projects, read comments and forums, and even create your own projects. But you need an account to save and share projects, write comments and forum posts, and participate in other \"social\" activities in the community (like \"loving\" other peoples projects).",
"faq.createAccountTitle":"How can I create an account?",
"faq.createAccountBody":"Just click <i>Join</i> on the Scratch home page. Youll need to respond to a few questions, and provide an email address. It takes just a couple minutes, and its totally free!",
"faq.checkConfirmedTitle":"How can I check whether my account has been confirmed?", "faq.checkConfirmedTitle":"How can I check whether my account has been confirmed?",
"faq.checkConfirmedBody":"To check whether your account is confirmed, you must first log into your Scratch account in the top right of the screen. Once logged in, click on your username in the top right and select \"Account Settings\", then \"Email\" on the left hand side. Confirmed email addresses will show a small green checkmark. Otherwise, you will see the text \"Your email address is unconfirmed\" in orange.",
"faq.howToConfirmTitle":"How do I confirm my account?", "faq.howToConfirmTitle":"How do I confirm my account?",
"faq.howToConfirmBody":"After registering for Scratch, you will receive an email with a link to confirm your account. If you cannot find the email, check your Spam folder. To resend the email, go to your Account Settings, click the Email tab, and follow the instructions there. Please note that it may take up to an hour for the email to arrive. If you still don't see the email after an hour, <a href=\"/contact-us\">let us know</a>.", "faq.howToConfirmBody":"After you create a new account on Scratch, youll receive an email message with a link. Just click the link to confirm your account. Once you confirm your account, youll be able to share projects, write comments, and create studios. Confirming your account also lets you receive email updates from the Scratch Team. If you cannot find the email with the confirmation link, check your Spam folder. If you still cant find it, and want to receive another copy, go to your Account Settings, click the Email tab, and follow the instructions there. Please note that it may take up to an hour for the email to arrive. If you still don't see the email after an hour, <a href=\"/contact-us\">let us know</a>.",
"faq.checkConfirmedBody":"To check whether your account is confirmed, login to your Scratch account and go to your <a href=\"/accounts/email_change/\">Email Settings</a> page. Confirmed email addresses will show a small green checkmark. Otherwise, you will see the text \"Your email address is unconfirmed\" in orange.",
"faq.requireConfirmTitle":"Do I have to confirm my account?", "faq.requireConfirmTitle":"Do I have to confirm my account?",
"faq.requireConfirmBody":"You can still use many aspects of Scratch without confirming your account, including creating and saving projects (without sharing them). Note: If you created an account before February 11, 2015, then you can still use social features on Scratch without confirming your account.", "faq.requireConfirmBody":"You can still use many aspects of Scratch without confirming your account, including creating and saving projects (without sharing them).",
"faq.forgotPasswordTitle":"I forgot my password. How can I reset it?", "faq.forgotPasswordTitle":"I forgot my username or password. How can I reset it?",
"faq.forgotPasswordBody":"Enter your account name on the <a href=\"/accounts/password_reset/\">password reset page</a>. The website will send an email to the address associated with the account containing a link you can use to reset your password.", "faq.forgotPasswordBody":"Enter your username or email address on the <a href=\"/accounts/password_reset/\">Password Reset</a> page. The website will send an email to the address associated with your username and a link you can use to reset your password.",
"faq.changePasswordTitle":"How do I change my password?", "faq.changePasswordTitle":"How do I change my password?",
"faq.changePasswordBody":"Go to the Scratch website, login, and then click your username in the upper right corner of the window. Choose \"account settings\", and click the link to change your password.", "faq.changePasswordBody":"Login to your Scratch account, then visit our <a href=\"/accounts/password_change/\">Password Settings</a> page where you can change your password.",
"faq.changeEmailTitle":"How do I change my email address?", "faq.changeEmailTitle":"How do I change my email address?",
"faq.changeEmailBody":"Go to the Scratch website, login, and then click your username in the upper right corner of the window. Choose \"account settings\", and click the link to change your email.", "faq.changeEmailBody":"Login to your Scratch account, then visit our <a href=\"/accounts/email_change/\">Email Settings</a> page where you can change your email address.",
"faq.newScratcherTitle":"How do I transition from 'New Scratcher' to 'Scratcher'?", "faq.newScratcherTitle":"How do I transition from 'New Scratcher' to 'Scratcher'?",
"faq.newScratcherBody":"Make and share projects, comment helpfully on other Scratcher's projects, and be patient! After a few weeks of being active, a link will appear on your profile page inviting you to become a Scratcher. (Note that we don't promote New Scratchers to Scratcher on request - even when bribed with fancy chocolates.)", "faq.newScratcherBody":"When you create an account, youll be labelled as a “New Scratcher.” To make the transition to \"Scratcher\", you should make and share projects, comment helpfully on other Scratchers projects, and be patient! After youve met the requirements, a link will appear on your profile page inviting you to become a Scratcher, and youll have some additional capabilities on the Scratch website. (Note that we don't promote New Scratchers to Scratcher on request )",
"faq.multipleAccountTitle":"Can I have more than one account?", "faq.multipleAccountTitle":"Can I have more than one account?",
"faq.multipleAccountBody":"It's fine to have a few accounts on the Scratch website, as long as none of them are used to break the Community Guidelines. In that case, all related accounts may be blocked or deleted.", "faq.multipleAccountBody":"It's fine to have a few accounts on the Scratch website, as long as none of them are used to break the <a href=\"/community_guidelines\">Community Guidelines</a>. In that case, all related accounts may be blocked or deleted.",
"faq.multipleLoginTitle":"Is it OK to have more than one person logged into an account?", "faq.multipleLoginTitle":"Is it OK to have more than one person logged into an account?",
"faq.multipleLoginBody":"This is discouraged, because the website and project editor can easily get confused when more than one person is logged into the same account.", "faq.multipleLoginBody":"This is not allowed because the website and project editor can easily get confused when more than one person is logged in to the same account. When an account does something that violates the <a href=\"/community_guidelines\">Community Guidelines</a>, all related accounts may be blocked or deleted. If you share an account with someone who does something bad with it, this means your accounts can be blocked for what the other person did.",
"faq.changeUsernameTitle":"Can I change my username?", "faq.changeUsernameTitle":"Can I change my username?",
"faq.changeUsernameBody":"The structure of the Scratch website depends on having a consistent account name, so its not possible to change your username. If you really need to, you can make a new account - but you'll have to copy your projects over on your own.", "faq.changeUsernameBody":"The structure of the Scratch website depends on having a consistent account name, so its not possible to change your username. If you really need to switch to a new username, you can make a new account, but you'll have to copy your projects over to the new account on your own.",
"faq.shareInfoTitle":"What information can I share on / with my account?", "faq.shareInfoTitle":"What information can I share on / with my account?",
"faq.shareInfoBody":"Please dont share personal contact information, such as your physical address, email, phone number, or anything else that can be used to make contact outside of the Scratch website. Please report projects, comments, or forum posts that contain this kind of information so the Scratch team can remove it, and remind the author of our policy.", "faq.shareInfoBody":"Please dont share personal contact information, such as your physical address, email, phone number, or anything else that can be used to make contact outside of the Scratch website. Please report projects, comments, or forum posts that contain this kind of information, so the Scratch Team can remove the information, and remind the author of our policy against sharing personal contact information.",
"faq.deleteAccountTitle":"How do I delete my account?", "faq.deleteAccountTitle":"How do I delete my account?",
"faq.deleteAccountBody":"Log in to Scratch, and then click your username in the top right-hand corner. Select “Account Settings,” then click the <em>“I want to delete my account”</em> link at the bottom of the page.", "faq.deleteAccountBody":"Login to Scratch, and then click your username in the top right-hand corner. Select <i>Account Settings</i>, then click the <i>I want to delete my account</i> link at the bottom of the page. But you should only do this if you are absolutely sure that you want to delete your account.",
"faq.scratchFreeTitle":"Is Scratch free?", "faq.scratchFreeTitle":"Is Scratch free? Can I use it wherever I want?",
"faq.scratchFreeBody":"Yes! Scratch is available free of charge. You can use it in your school, and you can teach a course about it (even a course that costs money). You don't need to buy a license - it's free.", "faq.scratchFreeBody":"Yes! Scratch is available free of charge. You can use it in your school, and you can teach a course about it (even a course that costs money). You don't need to buy a license: it's free!",
"faq.scratchScreenshotTitle":"Can I use screenshots of Scratch in a book or presentation?", "faq.scratchScreenshotTitle":"Can I use screenshots of Scratch in a book or presentation?",
"faq.scratchScreenshotBody":"Yes, you can write a book or chapter about Scratch. You may create screenshots / images of the Scratch application and website, and consider them to be licensed under the <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">Creative Commons Attribution-ShareAlike license</a>. We ask that you include a note on your materials that says, \"Scratch is developed by the Lifelong Kindergarten Group at the MIT Media Lab. It is available for free at https://scratch.mit.edu\".", "faq.scratchScreenshotBody":"Yes, you can use screenshots / images of the Scratch application and website in a book or presentation, and consider them to be licensed under the <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">Creative Commons Attribution-ShareAlike</a> license. We ask that you include a note somewhere in your materials saying: \"Scratch is a project of the Scratch Foundation, in collaboration with the Lifelong Kindergarten Group at the MIT Media Lab. It is available for free at https://scratch.mit.edu\".",
"faq.scratchDescriptionTitle":"Can I include a description of Scratch in brochures or other materials?", "faq.scratchDescriptionTitle":"Can I include a description of Scratch in brochures or other materials?",
"faq.scratchDescriptionBody":"Sure! We recommend the following description: \"Scratch is a programming language and online community where you can create your own interactive stories, games, and animations -- and share your creations with others around the world. In the process of designing and programming Scratch projects, young people learn to think creatively, reason systematically, and work collaboratively. Scratch is a project of the Lifelong Kindergarten group at the MIT Media Lab. It is available for free at https://scratch.mit.edu\"", "faq.scratchDescriptionBody":"Sure! We recommend the following description: \"Scratch is a coding language and online community where you can create your own interactive stories, games, and animations -- and share your creations with others around the world. As young people create and share Scratch projects, they learn to think creatively, reason systematically, and work collaboratively. Scratch is a project of the <a href=\"https://www.scratchfoundation.org/\">Scratch Foundation</a> in collaboration with the Lifelong Kindergarten group at the MIT Media Lab. It is available for free at https://scratch.mit.edu\"",
"faq.presentScratchTitle":"Can I present Scratch at a conference?", "faq.presentScratchTitle":"Can I present Scratch at a conference?",
"faq.presentScratchBody":"Please feel free to make presentations about Scratch to educators or other groups. We grant our permission to make presentations.", "faq.presentScratchBody":"Please feel free to make presentations about Scratch to educators or other groups.",
"faq.supportMaterialTitle":"May I use / remix Scratch support materials, sprites, images, sounds or sample projects Ive found on the website?", "faq.supportMaterialTitle":"May I use / remix Scratch support materials, sprites, images, sounds or sample projects Ive found on the website?",
"faq.supportMaterialBody":"Yes - Scratch support materials made available on the Scratch website by the Scratch Team are available under the <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">Creative Commons Attribution-ShareAlike license</a>, with the exception of the Scratch Logo, Scratch Cat, Gobo, Pico, Nano, Giga, and Tera which are Scratch trademarks.", "faq.supportMaterialBody":"Yes: Most Scratch support materials on the Scratch website are available under the <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">Creative Commons Attribution-ShareAlike</a> license. There are a few exceptions: the Scratch Logo, Scratch Cat, Gobo, Pico, Nano, Giga, and Tera are Scratch trademarks, and can not be used without explicit permission from the Scratch Team.",
"faq.sellProjectsTitle":"Can I sell my Scratch projects?", "faq.sellProjectsTitle":"Can I sell my Scratch projects?",
"faq.sellProjectsBody":"Certainly - your project is your creation. Keep in mind that once you share your project on Scratch, everyone is free to download, remix, and reuse it as per the terms of the <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">CC-BY-SA 2.0 license</a>. So if you intend to sell your project, you may want to un-share it from Scratch.", "faq.sellProjectsBody":"Yes: Your Scratch project is your creation. But keep in mind that once you share your project on the Scratch website, everyone is free to download, remix, and reuse the project based on the terms of the <a href=\"http://creativecommons.org/licenses/by-sa/2.0/deed.en\">Creative Commons Attribution-ShareAlike</a> license. So if you intend to sell your project, you may want to un-share it from the Scratch website.",
"faq.sourceCodeTitle":"Where can I find the source code for Scratch?", "faq.sourceCodeTitle":"Where can I find the source code for Scratch?",
"faq.sourceCodeBody":"The source code for the Scratch 2 editor can be found on <a href=\"https://github.com/LLK/scratch-flash\">GitHub</a>. The source code for <a href=\"/scratch_1.4\">Scratch 1.4</a>, written in Squeak, is also available on <a href=\"https://github.com/LLK/Scratch_1.4\">GitHub</a>. For updated information on development projects relating to the Scratch website, please visit our <a href=\"/developers\">Developer Page</a>.", "faq.sourceCodeBody":"The source code for the Scratch programming editor can be found on <a href=\"https://github.com/LLK/scratch-gui\">GitHub</a>. The source code for <a href=\"https://github.com/LLK/scratch-flash\">Scratch 2.0</a> and <a href=\"https://github.com/LLK/Scratch_1.4\">Scratch 1.4</a>, are also available on GitHub. For updated information on development projects relating to the Scratch website, please visit our <a href=\"/developers\">Scratch Developer Page</a>.",
"faq.okayToShareTitle":"How do I know what is or isnt okay to share on the Scratch website?", "faq.okayToShareTitle":"How do I know what is or isnt okay to share on the Scratch website?",
"faq.okayToShareBody":"Check out the <a href=\"/community_guidelines\">Scratch community guidelines</a> - theyre brief and dont include a lot of legal stuff. Theres a link at the bottom of every page on Scratch.", "faq.okayToShareBody":"Check out the <a href=\"/community_guidelines\">Scratch community guidelines</a> - theyre brief and dont include a lot of legal stuff. Theres a link at the bottom of every page on Scratch.",
"faq.reportContentTitle":"What do I do if I see something thats inappropriate?", "faq.reportContentTitle":"What do I do if I see something thats inappropriate?",
"faq.reportContentBody":"You can click the link that says “report” on any project, comment, discussion post, or user page where you think something isn't ok for Scratch. If the situation is complicated, you can use the Contact Us link to explain. Be sure to include as much detail as you can, with links to relevant pages.", "faq.reportContentBody":"You can click the link that says <i>report</i> on any project, comment, discussion post, studio, or profile page where you see something that isn't ok for Scratch. If the situation is complicated, you can use the <a href=\"/contact-us\">Contact Us</a> link (available at the bottom of every page) to explain. Be sure to include as much detail as you can, with links to relevant pages.",
"faq.noFlameTitle":"What do I do if I see someone being mean or disrespectful?", "faq.noFlameTitle":"What do I do if I see someone being mean or disrespectful?",
"faq.noFlameBody":"Dont add to the flames! Responding to mean comments with more mean comments just makes things worse, and could result in your account being blocked. Instead, simply report anything that is disrespectful or unconstructive, and well follow up with the author. We check reports every day, multiple times per day - so rest assured, we'll sort things out.", "faq.noFlameBody":"Dont add to the flames! Responding to mean comments with more mean comments just makes things worse, and could result in your account being blocked. Instead, simply report anything that is disrespectful or unconstructive, and well follow up with the author. We check reports every day, multiple times per day - so rest assured, we'll sort things out.",
"faq.reviewContentTitle":"What does the Scratch team do when something is reported or flagged?", "faq.reviewContentTitle":"What does the Scratch team do when something is reported or flagged?",
"faq.reviewContentBody":"The Scratch Team reviews reported comments and projects every day. If something breaks the Scratch community guidelines, we may remove it and send a warning to the account. Depending on how bad it is (or if weve already warned the account), we may also block the accounts or networks that were used to share it.", "faq.reviewContentBody":"The Scratch Team reviews reported comments and projects every day. If something breaks the <a href=\"/community_guidelines\">Scratch Community Guidelines</a>, we will remove it and send a warning to the account. We may also block the accounts or networks that were used to share it, depending on what was shared and if the person has been sent warnings before",
"faq.blockedAccountTitle":"What happens when an account is blocked?", "faq.blockedAccountTitle":"What happens when an account is blocked?",
"faq.blockedAccountBody":"When an account is blocked, the owner can no longer access it, or use it to create projects or comments. When they login, they see a page that explains why the account was blocked with a web form they can use to request to be unblocked. If the owner can show that they understand why their account was blocked, and promises to follow the community guidelines in the future, the Scratch Team will review their case. Accounts will only be unblocked in cases where the account owners word can be trusted. Otherwise, the account (and most likely other accounts owned or created by that person) may be blocked permanently.", "faq.blockedAccountBody":"When an account is blocked, the owner can no longer access their account, use it to create projects, or post new comments. When they login, they see a page that explains why the account was blocked, along with a web form they can use to request to be unblocked. If the owner can show that they understand why their account was blocked, and promises to follow the <a href=\"/community_guidelines\">Scratch Community Guidelines</a> in the future, they will be unblocked.",
"faq.stolenAccountTitle":"My mean brother / Kaj / some other bad guy stole my account and got it banned, what do I do?", "faq.stolenAccountTitle":"Someone got access to my account and got my account blocked. What do I do?",
"faq.stolenAccountBody":"You are responsible for keeping your password secure. If someone in real life takes control of your account and does bad stuff, tell the adults in charge of the computers. If you think someone you dont know got access to your account, change the password and / or use the contact us link to explain the situation. If you got blocked for doing something that broke the community guidelines, don't just say you got hacked. If we can't trust you, we won't unblock you.", "faq.stolenAccountBody":"You are responsible for keeping your password secure. If someone you know took control of your account and did bad things, tell the adults in charge of the computer they used. If you think someone you dont know has access to your account, change the password and / or use the <a href=\"/contact-us\">Contact Us</a> link to explain the situation. If your account was blocked for doing something that you did which broke the <a href=\"/community_guidelines\">Scratch Community Guidelines</a>, please dont tell us that someone else did it. When people tell us someone else used their account to do something bad, we then need to try and talk to that person before we can restore the account. This means your account will just stay blocked for a lot longer than if you are honest with us about what happened.",
"faq.cloudDataInfoTitle":"What is cloud data?", "faq.aboutExtensionsTitle":"What are extensions?",
"faq.cloudDataInfoBody":"Cloud data is a feature in Scratch 2 that allows for data from a project to be saved and shared online. You can use cloud data to make surveys and other projects that store numbers over time.", "faq.aboutExtensionsBody":"In the Scratch editor, you can add collections of extra blocks called \"extensions.\" For example, there are extensions that enable you to program physical devices (such as micro:bit and LEGO robotics kits) and to translate text within your Scratch projects. We will continue to add new extensions over time, so what you can do with Scratch will continue to grow over time. ",
"faq.storedCloudInfoTitle":"Who can see the data stored in cloud data?", "faq.howToAddExtensionsTitle":"How do I add an extension to a project?",
"faq.storedCloudInfoBody":"When you interact with a project using cloud data blocks, your information can be stored along with your username, and others can view it. Each project keeps a log of who interacted with it and any data they shared.", "faq.howToAddExtensionsBody":"If you click on the <i>Extensions</i> button in the bottom left corner of the Scratch programming editor, you will see a listing of all Scratch Extensions. When you select one of the extensions, a new category of blocks will be added to your project. The extension will be automatically loaded each time your project is opened. You can add multiple extensions to the same project.",
"faq.onlyNumbersTitle":"Why is cloud data currently limited to only numbers -- with no strings or lists?", "faq.createExtensionsTitle":"How do I create my own extension for Scratch",
"faq.onlyNumbersBody":"The current site is limited to numbers in variables as an initial step to work out any issues with their use on the site. We plan to roll out cloud data features incrementally. If the infrastructure is working well, we plan to add other features (cloud lists, support for strings, etc.).", "faq.createExtensionsBody":"The Scratch Team will be publishing specifications and guidelines for extensions in the future. Once available, you will be able to submit extensions to the Scratch Team for consideration in the official Scratch 3.0 extensions library. Well also provide guidelines for developing and distributing \"experimental\" extensions, which can be used to create projects on individual computers, but not shared in the Scratch online community.",
"faq.reportCloudTitle":"If I see someone post inappropriate content using cloud data, how do I report it?", "faq.scratchXTitle":"What will happen to the ScratchX website?",
"faq.reportCloudBody":"Click the \"Report this\" button (under on the project player) to report inappropriate content in cloud data. The report form includes a link to a log of all cloud data in that project and who left it - you may want to take look at it before sending your report. Make sure that you mention \"cloud data\" when you type your reason in the report.", "faq.scratchXBody":"The ScratchX website (scratchx.org) was an experimental testbed for extensions. Extensions created for ScratchX are not compatible with Scratch 3.0. Once experimental extensions are fully supported in Scratch we will discontinue support for ScratchX and provide developers and users time to transition off of ScratchX to the new extensions platform.",
"faq.chatRoomTitle":"Can I make chat rooms with cloud data?", "faq.cloudDataInfoTitle":"What are cloud variables?",
"faq.chatRoomBody":"While it is technically possible to create chat rooms with cloud data, they are not currently allowed. We will reconsider this policy once we have a better sense of our capability for moderating and managing reports on cloud data.", "faq.cloudDataInfoBody":"Cloud variables allow for data from a project to be saved and shared with other people in the Scratch community. You can use cloud variables to make surveys and other projects where others in the community to access and modify the data over time.",
"faq.makeCloudVarTitle":"How do I add a cloud variable when I'm making a project?", "faq.makeCloudVarTitle":"How can I make a cloud variable?",
"faq.makeCloudVarBody":"When you make a variable, you can check the box that says \"Cloud variable\". Any data you store will be saved on the server and visible to others.", "faq.makeCloudVarBody":"Go to the <i>Variables</i> section of the blocks palette, select <i>Make a Variable</i>, and then click the checkbox next to <i>Cloud variable (stored on server)</i>. The data associated with your cloud variable will be stored on the server, preserved over time, and accessible to anyone who opens the project.",
"faq.onlyNumbersTitle":"What types of data can be stored in cloud variables?",
"faq.onlyNumbersBody":"Only numbers can be stored in cloud variables.",
"faq.storedCloudInfoTitle":"Who can see the data stored in cloud variables?",
"faq.storedCloudInfoBody":"When you interact with a project using cloud variables, the data associated with your interactions can be stored along with your username, and others can view it.",
"faq.reportCloudTitle":"If I see someone post inappropriate content using cloud variables, how do I report it?",
"faq.reportCloudBody":"Click the <i>Report this</i> button (under on the project player on the project page) to report inappropriate content in cloud variables. Make sure that you mention \"cloud variables\" when you type your reason in the report.",
"faq.chatRoomTitle":"Can I make chat rooms with cloud variables?",
"faq.chatRoomBody":"While it is technically possible to create chat rooms with cloud variables, they are not allowed on the Scratch website.",
"faq.changeCloudVarTitle":"Who can change the information in a cloud variable?", "faq.changeCloudVarTitle":"Who can change the information in a cloud variable?",
"faq.changeCloudVarBody":"Only your project can store data in its cloud variable. If people change or remix your code, it creates a different variable in their project with the same name.", "faq.changeCloudVarBody":"Only you and viewers of your project can store data in your projects cloud variables. If people <i>see inside</i> or remix your code, it creates a copy of the variable and does not affect or change the original variable.",
"faq.newScratcherCloudTitle":"I am logged in, but I still cannot use projects with cloud data. What is going on?", "faq.newScratcherCloudTitle":"I am logged in, but I cannot use projects with cloud variables What is going on?",
"faq.newScratcherCloudBody":"You need to have become a \"Scratcher\" on the website to have access to cloud data. You can become a Scratcher through actively participating on the website.", "faq.newScratcherCloudBody":"If you are still a \"New Scratcher\" on the website, you will not be able to use projects with cloud variables. You need to become a \"Scratcher\" to have access to cloud variables. See the Accounts section (above) for more information about the transition from “New Scratcher” to \"Scratcher\".",
"faq.multiplayerTitle":"Is it possible to make multiplayer games with cloud data?", "faq.multiplayerTitle":"Is it possible to make multiplayer games with cloud variables?",
"faq.multiplayerBody":"Multiplayer games may be difficult to create, due to network speed and synchronization issues. However, some Scratchers are coming up with creative ways to use the cloud data for turn-by-turn and other games.", "faq.multiplayerBody":"Multiplayer games may be difficult to create, due to network speed and synchronization issues. However, some Scratchers are coming up with creative ways to use the cloud variables for turn-by-turn and other types of games.",
"faq.cloudLagTitle":"How long does it take for cloud data to reach another Scratcher?",
"faq.cloudLagBody":"It depends. If both Scratchers have a reasonably fast Internet connection (DSL/Cable), and there are no restrictive firewalls on the computers/network, updates should be transmitted in milliseconds. However, a lot of computers have firewall software running in them, and if the firewall software blocks outgoing connections to TCP port 531 and TCP port 843, the time-lag becomes one-second. We are currently trying to figure out ways in which we can work around this limitation.",
"faq.schoolsTitle":"Scratch in Schools", "faq.schoolsTitle":"Scratch in Schools",
"faq.howTitle":"How is Scratch used in schools?", "faq.howTitle":"How is Scratch used in schools?",
"faq.howBody":"Scratch is used in thousands of schools around the world, in many different subject areas (including language arts, science, history, math, and computer science). You can learn more about strategies and resources for using Scratch in schools and other learning environments (such as museums, libraries, and community centers) on our <a href=\"/educators\">Educators Page</a>. You can also join the <a href=\"http://scratched.gse.harvard.edu/\">ScratchEd</a> online community for educators, which is managed by our friends at the Harvard Graduate School of Education.", "faq.howBody":"Scratch is used in hundreds of thousands of schools around the world, in many different subject areas (including language arts, science, history, math, and computer science). You can learn more about strategies and resources for using Scratch in schools and other learning environments (such as museums, libraries, and community centers) on our <a href=\"/educators\">Educators Page</a>.",
"faq.ageTitle":"What is the age range for Scratch?",
"faq.ageBody":"Scratch was developed especially for young people 8 to 16 years old, so it is used most often in elementary schools and middle schools, but people of all ages create and share Scratch projects. Scratch is even used in some introductory computer-science courses in colleges. Younger children may want to try <a href=\"//www.scratchjr.org/\">ScratchJr</a>, a simplified version of Scratch designed for ages 5 to 7.",
"faq.noInternetTitle":"Is there a way for students to use Scratch without an internet connection?", "faq.noInternetTitle":"Is there a way for students to use Scratch without an internet connection?",
"faq.noInternetBody":"Yes. The Scratch <a href=\"/scratch2download\">Offline Editor</a> is a version of Scratch that runs on a desktop or laptop computer. Currently, the Offline Editor is available for Mac and Windows machines.", "faq.noInternetBody":"Yes. <a href=\"/download\">Scratch Desktop</a> is a version of Scratch that runs on a desktop or laptop computer. Currently, Scratch Desktop is available for Mac and Windows machines.",
"faq.communityTitle":"Can I turn off the online community for my students?", "faq.communityTitle":"Can I turn off the online community for my students?",
"faq.communityBody":"The Scratch online community provides a way for young people to share, collaborate, and learn with their peers within a moderated community governed by Community Guidelines. However, we understand that some educators prefer that their students not participate in an online community. These educators may wish to install the Scratch Offline Editor, which runs offline and locally on a desktop or laptop computer.", "faq.communityBody":"The Scratch online community provides a way for young people to share, collaborate, and learn with their peers within a moderated community governed by the <a href=\"/community_guidelines\">Scratch Community Guidelines</a>. However, we understand that some educators prefer that their students not participate in an online community. These educators may wish to install Scratch Desktop, which runs offline and locally on a desktop or laptop computer.",
"faq.teacherAccountTitle":"What is a Scratch Teacher Account?", "faq.teacherAccountTitle":"What is a Scratch Teacher Account?",
"faq.teacherAccountBody":"A Scratch Teacher Account provides teachers and other educators with additional features to manage student participation on Scratch, including the ability to create student accounts, organize student projects into studios, and monitor student comments.", "faq.teacherAccountBody":"A Scratch Teacher Account provides teachers and other educators with additional features to manage student participation on Scratch, including the ability to create student accounts, organize student projects into studios, and monitor student comments. For more information on Scratch Teacher Accounts, see the <a href=\"/educators/faq\">Scratch Teacher Account FAQ</a>.",
"faq.requestTitle":"How do I request a Scratch Teacher Account?", "faq.requestTitle":"How do I request a Scratch Teacher Account?",
"faq.requestBody":"You may request a Scratch Teacher Account from the <a href=\"/educators\">Educators Page</a> on Scratch. We ask for additional information during the registration process in order to verify your role as an educator.", "faq.requestBody":"You may request a Scratch Teacher Account from the <a href=\"/educators\">Educators Page</a> on Scratch. We ask for additional information during the registration process in order to verify your role as an educator.",
"faq.edTitle":"What is the difference between a Scratch Teacher Account and a ScratchEd Account?",
"faq.edBody":"Scratch Teacher Accounts are special user accounts on Scratch that have access to additional features to facilitate the creation and management of student accounts. ScratchEd Accounts are accounts on the <a href=\"http://scratched.gse.harvard.edu/\">ScratchEd community</a>, a separate website (managed by the Harvard Graduate School of Education) where educators share stories, exchange resources, ask questions, and meet other Scratch educators.",
"faq.dataTitle":"What data does Scratch collect about students?", "faq.dataTitle":"What data does Scratch collect about students?",
"faq.dataBody":"When a student first signs up on Scratch, we ask for basic demographic data including gender, age (birth month and year), country, and an email address for verification. This data is used (in aggregated form) in research studies intended to improve our understanding of how people learn with Scratch. When an educator uses a Scratch Teacher Account to create student accounts in bulk, students are not required to provide an email address for account setup.", "faq.dataBody":"When a student first signs up on Scratch, we ask for basic demographic data including gender, age (birth month and year), country, and an email address for verification. This data is used (in aggregated form) in research studies intended to improve our understanding of how people learn with Scratch. When an educator uses a Scratch Teacher Account to create student accounts in bulk, students are not required to provide an email address for account setup.",
"faq.lawComplianceTitle":"Is Scratch 2.0 (online version) compliant with United States local and federal data privacy laws?", "faq.lawComplianceTitle":"Is Scratch (online version) compliant with United States local and federal data privacy laws?",
"faq.lawComplianceBody":"Scratch cares deeply about the privacy of students and of all individuals who use our platform. We have in place physical and electronic procedures to protect the information we collect on the Scratch website. Although we are not in a position to offer contractual guarantees with each entity that uses our free educational product, we are in compliance with all United States federal laws that are applicable to MIT, a 501(c)(3) organization and the entity that created and maintains Scratch. We encourage you to read the Scratch Privacy Policy for more information.", "faq.lawComplianceBody":"Scratch cares deeply about the privacy of students and of all individuals who use our platform. We have in place physical and electronic procedures to protect the information we collect on the Scratch website. Although we are not in a position to offer contractual guarantees with each entity that uses our free educational product, we are in compliance with all United States federal laws that are applicable to MIT and the Scratch Foundation, the organizations that have created and maintained Scratch. We encourage you to read the Scratch Privacy Policy for more information.<br /><br />If you would like to build projects with Scratch without submitting any Personal Information to us, you can download <a href=\"/download\">Scratch Desktop</a>. Projects created in Scratch Desktop are not accessible by the Scratch Team, and using Scratch Desktop does not disclose any personally identifying information to Scratch unless you upload these projects to the Scratch online community.</p>"
"faq.schoolsMoreInfo":"For more questions about Teacher Accounts, see the <a href=\"/educators/faq\">Teacher Account FAQ</a>"
} }

252
src/views/ideas/ideas.jsx Normal file
View file

@ -0,0 +1,252 @@
const bindAll = require('lodash.bindall');
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage;
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const React = require('react');
const Button = require('../../components/forms/button.jsx');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const MasonryGrid = require('../../components/masonrygrid/masonrygrid.jsx');
const TitleBanner = require('../../components/title-banner/title-banner.jsx');
const TTTModal = require('../../components/modal/ttt/modal.jsx');
const TTTTile = require('../../components/ttt-tile/ttt-tile.jsx');
const Page = require('../../components/page/www/page.jsx');
const render = require('../../lib/render.jsx');
const Tiles = require('./ttt.json');
require('./ideas.scss');
class Ideas extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleShowTTTModal',
'handleHideTTTModal',
'renderTiles'
]);
this.state = {
currentTile: Tiles[0],
TTTModalOpen: false
};
}
handleShowTTTModal (tile) {
// expects translated tile
this.setState({
currentTile: tile,
TTTModalOpen: true
});
}
handleHideTTTModal () {
this.setState({
TTTModalOpen: false
});
}
renderTiles () {
return Tiles.map((tile, key) => {
const translatedTile = {
tutorialUrl: `/projects/editor/?tutorial=${tile.tutorialUrl}`,
modalImage: tile.modalImage,
description: this.props.intl.formatMessage({id: tile.description}),
guideUrl: this.props.intl.formatMessage({id: tile.guideUrl}),
thumbImage: tile.thumbImage,
title: this.props.intl.formatMessage({id: tile.title}),
cardsUrl: this.props.intl.formatMessage({id: tile.cardsUrl})
};
return (
<TTTTile
key={key}
onClick={() => { // eslint-disable-line react/jsx-no-bind
this.handleShowTTTModal(translatedTile);
}}
{...translatedTile}
/>
);
});
}
render () {
return (
<div>
<div className="banner-wrapper">
<TitleBanner className="masthead ideas-banner">
<div className="title-banner-p">
<img src="/images/ideas/masthead-illustration.svg" />
<h1 className="title-banner-h1">
<FormattedMessage id="ideas.headerMessage" />
</h1>
<a href="/projects/editor/?tutorial=all">
<Button className="ideas-button">
<img src="/images/ideas/bulb-icon.svg" />
<FormattedMessage id="ideas.headerButtonMessage" />
</Button>
</a>
</div>
</TitleBanner>
</div>
<div className="tips-getting-started">
<div className="inner">
<FlexRow
as="section"
className="tips-info-section tips-left"
>
<div className="ideas-image">
<img src="images/ideas/getting-started-illustration.svg" />
</div>
<div>
<h2>
<FormattedMessage id="ideas.gettingStartedTitle" />
</h2>
<p>
<FormattedHTMLMessage id="ideas.gettingStartedText" />
</p>
<a href="/projects/editor/?tutorial=getStarted">
<Button className="ideas-button">
<img src="/images/ideas/try-it-icon.svg" />
<FormattedMessage id="ideas.tryIt" />
</Button>
</a>
</div>
</FlexRow>
</div>
</div>
<div className="tips-activity-guides">
<div className="inner">
<section className="ttt-section">
<div className="ttt-head">
<h2>
<FormattedMessage id="ideas.activityGuidesTitle" />
</h2>
<p>
<FormattedHTMLMessage id="ideas.activityGuidesText" />
</p>
</div>
<MasonryGrid >
{this.renderTiles()}
</MasonryGrid>
<TTTModal
isOpen={this.state.TTTModalOpen}
onRequestClose={this.handleHideTTTModal}
{...this.state.currentTile}
/>
<a
className="wide-button"
href="/projects/editor/?tutorial=all"
>
<Button className="ideas-button wide-button">
<FormattedMessage id="ideas.seeAllTutorials" />
</Button>
</a>
</section>
</div>
</div>
<div>
<div className="inner">
<FlexRow
as="section"
className="tips-info-section cards-info ideas-all-cards"
>
<div className="tips-info-body">
<h2>
<FormattedMessage id="ideas.cardsTitle" />
</h2>
<p>
<FormattedHTMLMessage id="ideas.cardsText" />
</p>
<a
href={this.props.intl.formatMessage({
id: 'cards.scratch-cards-allLink'
})}
target="_blank"
>
<Button className="ideas-button">
<img src="/images/ideas/download-icon.svg" />
<FormattedMessage id="ideas.downloadPDF" />
</Button>
</a>
</div>
<div className="tips-info-body tips-illustration">
<img src="/images/ideas/cards-illustration.svg" />
</div>
</FlexRow>
</div>
</div>
<div className="inner">
<div className="tips-divider" />
</div>
<div>
<div className="inner">
<FlexRow
as="section"
className="ideas-starter tips-info-section tips-left"
>
<div className="ideas-image">
<img
src="/images/ideas/starter-projects-illustration.svg"
/>
</div>
<div className="tips-info-body">
<h2>
<FormattedMessage id="ideas.starterProjectsTitle" />
</h2>
<p>
<FormattedHTMLMessage id="ideas.starterProjectsText" />
</p>
<p>
<a href="/starter_projects">
<Button className="ideas-button">
<FormattedMessage id="ideas.starterProjectsButton" />
</Button>
</a>
</p>
</div>
</FlexRow>
</div>
</div>
<div className="gray-area">
<div className="inner">
<FlexRow
as="section"
className="tips-info-section mod-align-top"
>
<div className="tips-info-body mod-narrow">
<img
className="tips-icon"
src="/images/tips/download-icon.svg"
/>
<h3>
<FormattedMessage id="ideas.desktopEditorHeader" />
</h3>
<p>
<FormattedHTMLMessage id="ideas.desktopEditorBody" />
</p>
</div>
<div className="tips-info-body mod-narrow">
<img
className="tips-icon"
src="/images/tips/question-icon.svg"
/>
<h3>
<FormattedMessage id="ideas.questionsHeader" />
</h3>
<p>
<FormattedHTMLMessage id="ideas.questionsBody" />
</p>
</div>
</FlexRow>
</div>
</div>
</div>
);
}
}
Ideas.propTypes = {
intl: intlShape
};
const WrappedIdeas = injectIntl(Ideas);
render(
<Page><WrappedIdeas /></Page>, document.getElementById('app'));

249
src/views/ideas/ideas.scss Normal file
View file

@ -0,0 +1,249 @@
@import "../../colors";
@import "../../frameless";
$base-bg: $ui-white;
#view {
background-color: $ui-white;
padding: 0;
}
.banner-wrapper {
background: $ui-yellow bottom right url("/images/ideas/right-juice.png") no-repeat;
}
.ideas-banner {
margin-bottom: 0;
background: bottom left url("/images/ideas/left-juice.png") no-repeat;
}
.ttt-section {
display: flex;
margin: 0 auto;
text-align: center;
justify-content: center;
flex-wrap: wrap;
align-items: center;
}
.tips-divider {
border-top: 1px solid $ui-gray;
width: 100%;
}
.tips-banner-image {
max-width: calc(100% - 2rem);
}
.ideas-button {
margin-right: .75rem;
background-color: $ui-blue;
color: $ui-white;
font-size: 1rem;
img {
margin-right: 1rem;
height: 1.5rem;
vertical-align: middle;
}
a {
color: $ui-white;
}
span {
vertical-align: middle;
}
}
.wide-button {
width: 100%;
}
.ideas-all-cards {
padding: 5rem 0 !important;
}
.ideas-starter {
padding: 5rem 0 !important;
}
.tips-getting-started {
background-color: $ui-light-gray;
padding-top: 2.5rem;
}
.tips-left {
justify-content: flex-start;
}
.ideas-image {
margin-right: 2rem;
}
.tips-activity-guides {
background-color: $ui-light-gray;
padding-bottom: 2rem;
}
.purchase-button {
img {
margin-right: 0;
margin-left: .75rem;
width: 1rem;
vertical-align: baseline;
}
}
.tips-info-section {
padding: 2.5rem 0;
width: 100%;
flex-wrap: nowrap;
}
.tips-info-body {
text-align: left;
}
.tips-cards-buttons {
a {
white-space: normal;
}
}
.gray-area {
background-color: $ui-gray;
}
img.tips-icon {
height: 1.75rem;
}
//4 columns
@media #{$small} {
.title-banner {
&.masthead {
padding-bottom: 1.25rem;
p {
max-width: $cols4;
}
}
}
.ttt-head {
p {
max-width: $cols4;
}
}
//put the image first if in 4-column
.tips-info-body {
max-width: $cols4;
text-align: center;
&.tips-illustration {
order: -1;
img {
width: $cols4;
}
}
.button {
width: 100%;
}
}
}
//6 columns
@media #{$medium} {
.title-banner {
&.masthead {
p {
max-width: $cols6;
}
}
}
.ttt-head {
p {
max-width: $cols6;
}
}
.tips-info-body.tips-illustration {
order: -1;
img {
width: $cols4;
}
}
.tips-info-body {
max-width: $cols4;
text-align: center;
}
}
//8 columns
@media #{$intermediate} {
.title-banner {
&.masthead {
padding-bottom: 2rem;
p {
max-width: $cols6;
}
}
}
.ttt-head {
p {
max-width: $cols6;
}
}
.tips-info-section {
&.mod-align-top {
align-items: flex-start;
}
}
.tips-info-body {
max-width: $cols4;
}
}
// 12 columns
@media #{$big} {
.title-banner {
&.masthead {
padding-bottom: 1.25rem;
p {
max-width: $cols8;
}
}
}
.ttt-head {
p {
max-width: $cols8;
}
}
.tips-info-section {
&.mod-align-top {
align-items: flex-start;
}
}
.tips-info-body {
max-width: $cols6;
&.mod-narrow {
max-width: $cols5;
}
}
}

View file

@ -0,0 +1,15 @@
{
"cards.scratch-cards-allLink": "https://resources.scratch.mit.edu/www/cards/en/scratch-cards-all.pdf",
"cards.name-cardsLink": "https://resources.scratch.mit.edu/www/cards/en/name-cards.pdf",
"cards.animation-cardsLink": "https://resources.scratch.mit.edu/www/cards/en/animation-cards.pdf",
"cards.music-cardsLink": "https://resources.scratch.mit.edu/www/cards/en/music-cards.pdf",
"cards.story-cardsLink": "https://resources.scratch.mit.edu/www/cards/en/story-cards.pdf",
"cards.chase-cardsLink": "https://resources.scratch.mit.edu/www/cards/en/chase-cards.pdf",
"cards.video-cardsLink": "https://resources.scratch.mit.edu/www/cards/en/video-cards.pdf",
"guides.NameGuideLink": "https://resources.scratch.mit.edu/www/guides/en/NameGuide.pdf",
"guides.AnimateGuideLink": "https://resources.scratch.mit.edu/www/guides/en/AnimateGuide.pdf",
"guides.MusicGuideLink": "https://resources.scratch.mit.edu/www/guides/en/MusicGuide.pdf",
"guides.StoryGuideLink": "https://resources.scratch.mit.edu/www/guides/en/StoryGuide.pdf",
"guides.ChaseGuideLink": "https://resources.scratch.mit.edu/www/guides/en/ChaseGuide.pdf",
"guides.VideoGuideLink": "https://resources.scratch.mit.edu/www/guides/en/VideoGuide.pdf"
}

53
src/views/ideas/l10n.json Normal file
View file

@ -0,0 +1,53 @@
{
"ideas.headerMessage": "What will you create?",
"ideas.headerButtonMessage": "Choose a tutorial",
"ideas.gettingStartedTitle": "Getting Started",
"ideas.gettingStartedText": "New to Scratch? Try the Getting Started tutorial.",
"ideas.tryIt": "Try it!",
"ideas.activityGuidesTitle": "Activity Guides",
"ideas.activityGuidesText": "What do you want to make with Scratch? For each activity, you can try the Tutorial, download a set of Coding Cards, or view the Educator Guide.",
"ideas.animateANameTitle": "Animate a Name",
"ideas.animateANameDescription": "Animate the letters of your name, initials, or favorite word.",
"ideas.animateACharacterTitle": "Animate a Character",
"ideas.animateACharacterDescription": "Bring characters to life with animation.",
"ideas.makeMusicTitle": "Make Music",
"ideas.makeMusicDescription": "Choose instruments, add sounds, and press keys to play music.",
"ideas.createAStoryTitle": "Create a Story",
"ideas.createAStoryDescription": "Choose characters, add conversation, and bring your story to life.",
"ideas.chaseGameTitle": "Make a Chase Game",
"ideas.chaseGameDescription": "Make a game where you chase a character to score points.",
"ideas.videoSensingTitle": "Video Sensing",
"ideas.videoSensingDescription": "Interact with a project using the Video Sensing extension.",
"ideas.seeAllTutorials": "See All Tutorials",
"ideas.cardsTitle": "Get the Entire Collection of Coding Cards",
"ideas.cardsText": "With the Scratch Coding Cards, you can learn to create interactive games, stories, music, animations, and more!",
"ideas.downloadPDF": "Download PDF",
"ideas.starterProjectsTitle": "Starter Projects",
"ideas.starterProjectsText": "You can play with Starter Projects and remix them to make your own creations.",
"ideas.starterProjectsButton": "Explore Starter Projects",
"ideas.tryTheTutorial": "Try the tutorial",
"ideas.codingCards": "Coding Cards",
"ideas.educatorGuide": "Educator Guide",
"ideas.desktopEditorHeader": "Scratch Desktop Download",
"ideas.desktopEditorBody": "To create projects without an Internet connection, you can <a href=\"/download\">download Scratch Desktop</a>.",
"ideas.questionsHeader": "Questions",
"ideas.questionsBody": "Have more questions? See the <a href=\"/info/faq\">Frequently Asked Questions</a> or visit the <a href=\"/discuss/7/\">Help with Scripts Forum</a>.",
"ideas.cardsPurchase": "Purchase Printed Set",
"ideas.MakeItFlyTitle": "Make It Fly",
"ideas.MakeItFlyDescription": "Animate the Scratch Cat, The Powerpuff Girls, or even a taco!",
"ideas.RaceTitle": "Race to the Finish",
"ideas.RaceDescription": "Make a game where two characters race each other.",
"ideas.HideAndSeekTitle": "Hide and Seek",
"ideas.HideAndSeekDescription": "Make a hide-and-seek game with characters that appear and disappear.",
"ideas.FashionTitle": "Fashion Game",
"ideas.FashionDescription": "Make a game where you dress a character with different clothes and styles.",
"ideas.PongTitle": "Pong Game",
"ideas.PongDescription": "Make a bouncing ball game with sounds, points, and other effects.",
"ideas.DanceTitle": "Let's Dance",
"ideas.DanceDescription": "Design an animated dance scene with music and dance moves.",
"ideas.CatchTitle": "Catch Game",
"ideas.CatchDescription": "Make a game where you catch things falling from the sky.",
"ideas.VirtualPetTitle": "Virtual Pet",
"ideas.VirtualPetDescription": "Create an interactive pet that can eat, drink, and play."
}

56
src/views/ideas/ttt.json Normal file
View file

@ -0,0 +1,56 @@
[
{
"title": "ideas.animateANameTitle",
"description": "ideas.animateANameDescription",
"thumbImage": "/images/ideas/activities/animate-a-name-thumb.jpg",
"modalImage": "/images/ideas/activities/animate-a-name-modal.jpg",
"tutorialUrl": "name",
"cardsUrl": "cards.name-cardsLink",
"guideUrl": "guides.NameGuideLink"
},
{
"title": "ideas.animateACharacterTitle",
"description": "ideas.animateACharacterDescription",
"thumbImage": "/images/ideas/activities/animate-a-character-thumb.jpg",
"modalImage": "/images/ideas/activities/animate-a-character-modal.jpg",
"tutorialUrl": "animate-a-character",
"cardsUrl": "cards.animation-cardsLink",
"guideUrl": "guides.AnimateGuideLink"
},
{
"title": "ideas.makeMusicTitle",
"description": "ideas.makeMusicDescription",
"thumbImage": "/images/ideas/activities/make-music-thumb.jpg",
"modalImage": "/images/ideas/activities/make-music-modal.jpg",
"tutorialUrl": "music",
"cardsUrl": "cards.music-cardsLink",
"guideUrl": "guides.MusicGuideLink"
},
{
"title": "ideas.createAStoryTitle",
"description": "ideas.createAStoryDescription",
"thumbImage": "/images/ideas/activities/create-a-story-thumb.jpg",
"modalImage": "/images/ideas/activities/create-a-story-modal.jpg",
"tutorialUrl": "tell-a-story",
"cardsUrl": "cards.story-cardsLink",
"guideUrl": "guides.StoryGuideLink"
},
{
"title": "ideas.chaseGameTitle",
"description": "ideas.chaseGameDescription",
"thumbImage": "/images/ideas/activities/chase-game-thumb.jpg",
"modalImage": "/images/ideas/activities/chase-game-modal.jpg",
"tutorialUrl": "chase-game",
"cardsUrl": "cards.chase-cardsLink",
"guideUrl": "guides.ChaseGuideLink"
},
{
"title": "ideas.videoSensingTitle",
"description": "ideas.videoSensingDescription",
"thumbImage": "/images/ideas/activities/video-sensing-thumb.jpg",
"modalImage": "/images/ideas/activities/video-sensing-modal.jpg",
"tutorialUrl": "video-sensing",
"cardsUrl": "cards.video-cardsLink",
"guideUrl": "guides.VideoGuideLink"
}
]

View file

@ -26,6 +26,8 @@ const Jobs = () => (
<div className="bottom"> <div className="bottom">
<div className="inner"> <div className="inner">
<h3><FormattedMessage id="jobs.openings" /></h3> <h3><FormattedMessage id="jobs.openings" /></h3>
<FormattedMessage id="jobs.nojobs" />
{/*
<ul> <ul>
<li> <li>
<a href="https://www.media.mit.edu/about/job-opportunities/full-stack-engineer-lifelong-kindergarten/"> <a href="https://www.media.mit.edu/about/job-opportunities/full-stack-engineer-lifelong-kindergarten/">
@ -36,6 +38,7 @@ const Jobs = () => (
</span> </span>
</li> </li>
</ul> </ul>
*/}
</div> </div>
</div> </div>
</div> </div>

View file

@ -3,5 +3,6 @@
"jobs.joinScratchTeam": "Join the Scratch Team!", "jobs.joinScratchTeam": "Join the Scratch Team!",
"jobs.openings": "Current Job Openings", "jobs.openings": "Current Job Openings",
"jobs.titleQuestion": "Want to work on an innovative project that is transforming the ways young people create, share, and learn?", "jobs.titleQuestion": "Want to work on an innovative project that is transforming the ways young people create, share, and learn?",
"jobs.workEnvironment":"Were seeking curious and motivated people to join our Scratch Team at the MIT Media Lab. We're a diverse group of educators, designers, and engineers, who work together in a playful, creative environment full of LEGO bricks, craft materials, and maker tools. We strongly value diversity, collaboration, and respect in the workplace." "jobs.workEnvironment":"Were seeking curious and motivated people to join our Scratch Team at the MIT Media Lab. We're a diverse group of educators, designers, and engineers, who work together in a playful, creative environment full of LEGO bricks, craft materials, and maker tools. We strongly value diversity, collaboration, and respect in the workplace.",
"jobs.nojobs":"We don't have any open positions at this time. Please check back soon for opportunities!"
} }

View file

@ -10,6 +10,7 @@ const React = require('react');
const Comment = require('../../../components/comment/comment.jsx'); const Comment = require('../../../components/comment/comment.jsx');
const FlexRow = require('../../../components/flex-row/flex-row.jsx'); const FlexRow = require('../../../components/flex-row/flex-row.jsx');
const SocialMessage = require('../../../components/social-message/social-message.jsx'); const SocialMessage = require('../../../components/social-message/social-message.jsx');
const thumbnailUrl = require('../../../lib/user-thumbnail');
class CommentMessage extends React.Component { class CommentMessage extends React.Component {
constructor (props) { constructor (props) {
@ -164,7 +165,7 @@ class CommentMessage extends React.Component {
<img <img
alt={`${this.props.actorUsername}'s avatar`} alt={`${this.props.actorUsername}'s avatar`}
className="comment-message-info-img" className="comment-message-info-img"
src={`https://cdn2.scratch.mit.edu/get_image/user/${this.props.actorId}_32x32.png`} src={thumbnailUrl(this.props.actorId)}
/> />
</a> </a>
<Comment <Comment

View file

@ -24,7 +24,7 @@ const UserJoinMessage = props => (
</a> </a>
), ),
makeProjectLink: ( makeProjectLink: (
<a href="/projects/editor/?tip_bar=getStarted"> <a href="/projects/editor/?tutorial=getStarted">
{props.intl.formatMessage({id: 'messages.userJoinMakeProject'})} {props.intl.formatMessage({id: 'messages.userJoinMakeProject'})}
</a> </a>
) )

View file

@ -23,6 +23,10 @@
"microbit.oceanAdventure": "Ocean Adventure", "microbit.oceanAdventure": "Ocean Adventure",
"microbit.oceanAdventureDescription": "Build your own controller and swim toward the saxophones.", "microbit.oceanAdventureDescription": "Build your own controller and swim toward the saxophones.",
"microbit.troubleshootingTitle": "Troubleshooting", "microbit.troubleshootingTitle": "Troubleshooting",
"microbit.checkOSVersionTitle": "Make sure your operating system is compatible with Scratch Link",
"microbit.checkOSVersionText": "The minimum operating system versions are listed at the top of this page. See instructions for checking your version of {winOSVersionLink} or {macOSVersionLink}.",
"microbit.winOSVersionLinkText": "Windows",
"microbit.macOSVersionLinkText": "Mac OS",
"microbit.closeScratchCopiesTitle": "Close other copies of Scratch", "microbit.closeScratchCopiesTitle": "Close other copies of Scratch",
"microbit.closeScratchCopiesText": "Only one copy of Scratch can connect with the micro:bit at a time. If you have Scratch open in other browser tabs, close it and try again.", "microbit.closeScratchCopiesText": "Only one copy of Scratch can connect with the micro:bit at a time. If you have Scratch open in other browser tabs, close it and try again.",
"microbit.otherComputerConnectedTitle": "Make sure no other computer is connected to your micro:bit", "microbit.otherComputerConnectedTitle": "Make sure no other computer is connected to your micro:bit",

View file

@ -27,65 +27,69 @@ require('../../components/extension-landing/extension-landing.scss');
require('./microbit.scss'); require('./microbit.scss');
class MicroBit extends ExtensionLanding { class MicroBit extends ExtensionLanding {
render () { render () {
return ( return (
<div className="extension-landing microbit"> <div className="extension-landing microbit">
<ExtensionHeader <ExtensionHeader
imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltMicrobitIllustration'})} renderCopy={
imageSrc="/images/microbit/microbit-heart.png" <FlexRow className="extension-copy">
> <h1><img
<FlexRow className="column extension-copy">
<h1><img
alt=""
src="/images/microbit/microbit.svg"
/>micro:bit</h1>
<FormattedMessage
id="microbit.headerText"
values={{
microbitLink: (
<a
href="http://microbit.org/"
rel="noopener noreferrer"
target="_blank"
>
micro:bit
</a>
)
}}
/>
</FlexRow>
<ExtensionRequirements>
<span>
<img
alt="" alt=""
src="/svgs/extensions/windows.svg" src="/images/microbit/microbit.svg"
/>micro:bit</h1>
<FormattedMessage
id="microbit.headerText"
values={{
microbitLink: (
<a
href="http://microbit.org/"
rel="noopener noreferrer"
target="_blank"
>
micro:bit
</a>
)
}}
/> />
Windows 10+ </FlexRow>
</span> }
<span> renderImage={<img
<img alt={this.props.intl.formatMessage({id: 'microbit.imgAltMicrobitIllustration'})}
alt="" src="/images/microbit/microbit-heart.png"
src="/svgs/extensions/mac.svg" />}
/> renderRequirements={
macOS 10.13+ <ExtensionRequirements>
</span> <span>
<span> <img
<img alt=""
alt="" src="/svgs/extensions/windows.svg"
src="/svgs/extensions/bluetooth.svg" />
/> Windows 10 version 1709+
Bluetooth 4.0 </span>
</span> <span>
<span> <img
<img alt=""
alt="" src="/svgs/extensions/mac.svg"
src="/svgs/extensions/scratch-link.svg" />
/> macOS 10.13+
Scratch Link </span>
</span> <span>
</ExtensionRequirements> <img
</ExtensionHeader> alt=""
src="/svgs/extensions/bluetooth.svg"
/>
Bluetooth 4.0
</span>
<span>
<img
alt=""
src="/svgs/extensions/scratch-link.svg"
/>
Scratch Link
</span>
</ExtensionRequirements>
}
/>
<OSChooser <OSChooser
currentOS={this.state.OS} currentOS={this.state.OS}
handleSetOS={this.onSetOS} handleSetOS={this.onSetOS}
@ -119,7 +123,7 @@ class MicroBit extends ExtensionLanding {
<a <a
download download
className="download" className="download"
href="https://downloads.scratch.mit.edu/microbit/scratch-microbit-1.0.hex.zip" href="https://downloads.scratch.mit.edu/microbit/scratch-microbit-1.1.0.hex.zip"
> >
<FormattedMessage id="microbit.downloadHex" /> <FormattedMessage id="microbit.downloadHex" />
</a> </a>
@ -166,11 +170,11 @@ class MicroBit extends ExtensionLanding {
values={{ values={{
scratch3Link: ( scratch3Link: (
<a <a
href="https://beta.scratch.mit.edu/" href="/projects/editor/"
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Scratch 3.0 Scratch
</a> </a>
) )
}} }}
@ -243,21 +247,21 @@ class MicroBit extends ExtensionLanding {
<h3><FormattedMessage id="microbit.starterProjects" /></h3> <h3><FormattedMessage id="microbit.starterProjects" /></h3>
<Steps> <Steps>
<ProjectCard <ProjectCard
cardUrl="https://beta.scratch.mit.edu/#239075756" cardUrl="/projects/239075756/editor"
description={this.props.intl.formatMessage({id: 'microbit.heartBeatDescription'})} description={this.props.intl.formatMessage({id: 'microbit.heartBeatDescription'})}
imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltHeartBeat'})} imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltHeartBeat'})}
imageSrc="/images/microbit/starter-heart.png" imageSrc="/images/microbit/starter-heart.png"
title={this.props.intl.formatMessage({id: 'microbit.heartBeat'})} title={this.props.intl.formatMessage({id: 'microbit.heartBeat'})}
/> />
<ProjectCard <ProjectCard
cardUrl="https://beta.scratch.mit.edu/#239075950" cardUrl="/projects/239075950/editor"
description={this.props.intl.formatMessage({id: 'microbit.tiltGuitarDescription'})} description={this.props.intl.formatMessage({id: 'microbit.tiltGuitarDescription'})}
imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltTiltGuitar'})} imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltTiltGuitar'})}
imageSrc="/images/microbit/starter-guitar.png" imageSrc="/images/microbit/starter-guitar.png"
title={this.props.intl.formatMessage({id: 'microbit.tiltGuitar'})} title={this.props.intl.formatMessage({id: 'microbit.tiltGuitar'})}
/> />
<ProjectCard <ProjectCard
cardUrl="https://beta.scratch.mit.edu/#239075973" cardUrl="/projects/239075973/editor"
description={this.props.intl.formatMessage({id: 'microbit.oceanAdventureDescription'})} description={this.props.intl.formatMessage({id: 'microbit.oceanAdventureDescription'})}
imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltOceanAdventure'})} imageAlt={this.props.intl.formatMessage({id: 'microbit.imgAltOceanAdventure'})}
imageSrc="/images/microbit/starter-fish.png" imageSrc="/images/microbit/starter-fish.png"
@ -267,6 +271,32 @@ class MicroBit extends ExtensionLanding {
</ExtensionSection> </ExtensionSection>
<ExtensionSection className="faq"> <ExtensionSection className="faq">
<h2><FormattedMessage id="microbit.troubleshootingTitle" /></h2> <h2><FormattedMessage id="microbit.troubleshootingTitle" /></h2>
<h3 className="faq-title"><FormattedMessage id="microbit.checkOSVersionTitle" /></h3>
<p>
<FormattedMessage
id="microbit.checkOSVersionText"
values={{
winOSVersionLink: (
<a
href="https://support.microsoft.com/en-us/help/13443/windows-which-operating-system"
rel="noopener noreferrer"
target="_blank"
>
<FormattedMessage id="microbit.winOSVersionLinkText" />
</a>
),
macOSVersionLink: (
<a
href="https://support.apple.com/en-us/HT201260"
rel="noopener noreferrer"
target="_blank"
>
<FormattedMessage id="microbit.macOSVersionLinkText" />
</a>
)
}}
/>
</p>
<h3 className="faq-title"><FormattedMessage id="microbit.closeScratchCopiesTitle" /></h3> <h3 className="faq-title"><FormattedMessage id="microbit.closeScratchCopiesTitle" /></h3>
<p> <p>
<FormattedMessage id="microbit.closeScratchCopiesText" /> <FormattedMessage id="microbit.closeScratchCopiesText" />

View file

@ -5,15 +5,6 @@
.extension-header { .extension-header {
background-color: $ui-mint-green; background-color: $ui-mint-green;
background-image: url("/images/microbit/mbit-pattern.svg"); background-image: url("/images/microbit/mbit-pattern.svg");
.extension-info {
padding-right: $cols1;
max-width: $cols7 + ($gutter / $em);
}
.extension-image {
max-width: $cols4;
}
} }
.things-to-try { .things-to-try {

View file

@ -1,714 +0,0 @@
{
"title":"Make Some Art",
"description":[
"Create your own art project with Scratch.",
"Check out projects by others for inspiration,",
"communicate in the forum and join the challenges!"
],
"microworld_project_id":"133865435",
"starter_projects":[
{
"title":"Architecture Stamps Starter Project",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2445/6318.png",
"creator":"CSFirst",
"id":24456318
},
{
"title":"Digital Art Starter Project",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2513/9098.png",
"creator":"CSFirst",
"id":25139098
},
{
"title":"Graffiti Starter Project",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2546/8311.png",
"creator":"CSFirst",
"id":25468311
},
{
"title":"Paint with Tera Starter ",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2743/2322.png",
"creator":"CSFirst",
"id":27432322
},
{
"title":"Interactive Art Starter Project",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2501/4570.png",
"creator":"CSFirst",
"id":25014570
},
{
"title":"Interactive Art Starter Project - Kuniyoshi Start",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2482/0113.png",
"creator":"CSFirst",
"id":24820113
},
{
"title":"Interactive Art Starter Project - American Gothic",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2445/4633.png",
"creator":"CSFirst",
"id":24454633
},
{
"title":"Interactive Art Starter Project - The Scream",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2481/8944.png",
"creator":"CSFirst",
"id":24818944
},
{
"title":"Animation Starter Project - Penguin",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2395/6722.png",
"creator":"CSFirst",
"id":23956722
},
{
"title":"Animation Starter Project - Gobo",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2395/7767.png",
"creator":"CSFirst",
"id":23957767
},
{
"title":"Animation Starter Project - Ghost",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2395/7153.png",
"creator":"CSFirst",
"id":23957153
},
{
"title":"Animation Starter Project - Crab",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2395/6837.png",
"creator":"CSFirst",
"id":23956837
},
{
"title":"Intro to Art Starter Project",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2420/9090.png",
"creator":"CSFirst",
"id":24209090
}
],
"community_projects":{
"featured_projects":[
{
"title":"Change color effect by-function",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/141/3159.png",
"creator":"dapontes",
"id":1413159
},
{
"title":"CobwebMaker",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/133/0100.png",
"creator":"-Scratcher-",
"id":1330100
},
{
"title":"QuadraticMap3_Attractor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/136/2772.png",
"creator":"mathjp",
"id":1362772
},
{
"title":"Plants_Jp1",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/131/8150.png",
"creator":"mathjp",
"id":1318150
},
{
"title":"TreeMaker",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/131/5337.png",
"creator":"-Scratcher-",
"id":1315337
},
{
"title":"3D Curve art",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/128/7436.png",
"creator":"nasami",
"id":1287436
},
{
"title":"pen art maker",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/115/3338.png",
"creator":"cooljj100",
"id":1153338
},
{
"title":"e-lisa-avo",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/64/1173.png",
"creator":"gerhardmb",
"id":641173
},
{
"title":"Pyramid_IFS_Fractal",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/129/4615.png",
"creator":"mathjp",
"id":1294615
},
{
"title":"3D Snail",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/127/0157.png",
"creator":"mathjp",
"id":1270157
},
{
"title":"Fractile Shape Maker 1S 1S",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/115/5121.png",
"creator":"recycle49",
"id":1155121
},
{
"title":"Mosaik",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/110/3305.png",
"creator":"frcroth",
"id":1103305
},
{
"title":"QuadraticMap2_Attractor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/109/9424.png",
"creator":"mathjp",
"id":1099424
},
{
"title":"3D Cube",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/105/2958.png",
"creator":"VilceGT",
"id":1052958
},
{
"title":"Fractal_CarpetsV1",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/105/9322.png",
"creator":"mathjp",
"id":1059322
},
{
"title":"QuadraticMap1_Attractor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/100/1796.png",
"creator":"mathjp",
"id":1001796
},
{
"title":"Pattern/Shape Generator 1S 1S",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/94/6911.png",
"creator":"recycle49",
"id":946911
},
{
"title":"Sweet Rainbow Kaliedoscope Attractor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/94/0283.png",
"creator":"Venazard",
"id":940283
},
{
"title":"Scratch3_Attractor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/94/6973.png",
"creator":"mathjp",
"id":946973
},
{
"title":"Peter_de_Jong_Attractor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/85/3644.png",
"creator":"mathjp",
"id":853644
},
{
"title":"Invertable",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/53/6764.png",
"creator":"itsEMILagain",
"id":536764
},
{
"title":"Chalkboard designs",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/66/7803.png",
"creator":"Targethero",
"id":667803
},
{
"title":"Blades of grass",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/82/2114.png",
"creator":"AddZero",
"id":822114
},
{
"title":"Flexible Line",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/72/8858.png",
"creator":"Paddle2See",
"id":728858
}
],
"newest_projects":[
{
"title":"Pixel Art - Emerald ore",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8681/8843.png",
"creator":"SebastianLavers",
"id":86818843
},
{
"title":"Untitled-10",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8720/4697.png",
"creator":"SebastianLavers",
"id":87204697
},
{
"title":"pixel art - trayne",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8720/5631.png",
"creator":"SebastianLavers",
"id":87205631
},
{
"title":"MY STAR WARS PIXEL ICONS",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8294/4668.png",
"creator":"DevG2857",
"id":82944668
},
{
"title":"[Pixel Art] Bomb",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7663/8750.png",
"creator":"-PixelArt-",
"id":76638750
},
{
"title":"[Pixel Art] Pizza",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7652/8188.png",
"creator":"-PixelArt-",
"id":76528188
},
{
"title":"[Pixel Art] Ancient Book",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7652/9284.png",
"creator":"-PixelArt-",
"id":76529284
},
{
"title":"[Pixel Art] Grass Tile #2",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7567/6352.png",
"creator":"-PixelArt-",
"id":75676352
},
{
"title":"Millennium Falcon",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4829/2520.png",
"creator":"HD_Pixel_Squid",
"id":48292520
},
{
"title":"Pixel Art Scene",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/5076/2664.png",
"creator":"AgentCNF",
"id":50762664
},
{
"title":"Sunset Pixel Art - By JK102",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7332/8110.png",
"creator":"jk102",
"id":73328110
},
{
"title":"Dragon Ball Z Pixel Art",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7225/3242.png",
"creator":"agentmcguffin",
"id":72253242
},
{
"title":"Pixel Art - Award",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7260/3768.png",
"creator":"Pixels-",
"id":72603768
},
{
"title":"PixelMoltenArmor",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6927/7136.png",
"creator":"pixelart5",
"id":69277136
},
{
"title":"Fishing (Art)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/1901/6045.png",
"creator":"IsoPixel",
"id":19016045
},
{
"title":"Placid Pool Simulation",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4696/9638.png",
"creator":"RememberNovember",
"id":46969638
},
{
"title":"[Pixel Art] Mountain Background",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7558/6228.png",
"creator":"-PixelArt-",
"id":75586228
},
{
"title":"[Pixel Art] Log",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7558/0582.png",
"creator":"-PixelArt-",
"id":75580582
},
{
"title":"[Pixel Art] Healthbar",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7468/7698.png",
"creator":"-PixelArt-",
"id":74687698
},
{
"title":"[Pixel Art] Food",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7450/4518.png",
"creator":"-PixelArt-",
"id":74504518
},
{
"title":"[Pixel Art] Starfield",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7450/3672.png",
"creator":"-PixelArt-",
"id":74503672
},
{
"title":"[Pixel Art] Nature Scene",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7449/9686.png",
"creator":"-PixelArt-",
"id":74499686
},
{
"title":"[Pixel Art] Clouds",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7450/1794.png",
"creator":"-PixelArt-",
"id":74501794
},
{
"title":"[Pixel Art] Medieval Door",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7333/1288.png",
"creator":"-PixelArt-",
"id":73331288
},
{
"title":"[Pixel Art] Sun and Moon",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7443/2594.png",
"creator":"-PixelArt-",
"id":74432594
},
{
"title":"[Pixel Art] Soda Can",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7333/0734.png",
"creator":"-PixelArt-",
"id":73330734
},
{
"title":"[Pixel Art] Rock Pack",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7324/3096.png",
"creator":"-PixelArt-",
"id":73243096
},
{
"title":"[Pixel Art] Grass Tile",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7321/3098.png",
"creator":"-PixelArt-",
"id":73213098
},
{
"title":"[Pixel Art] Animated Coin",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7321/2898.png",
"creator":"-PixelArt-",
"id":73212898
},
{
"title":"[Pixel Art] Sword",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7294/4390.png",
"creator":"-PixelArt-",
"id":72944390
}
]
},
"design_challenge":{
"project_id":"89144801",
"studio_id":"1728540",
"studio1":[
{
"gallery_id":1728540,
"creator":"mathjp",
"remixers_count":8,
"gallery_title":"Arts Design Challenge",
"love_count":28,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/326/6979.png",
"title":"Flowers_Creator",
"type":"project",
"id":3266979
},
{
"gallery_id":1728540,
"creator":"-Scratcher-",
"remixers_count":2,
"gallery_title":"Arts Design Challenge",
"love_count":9,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/131/5337.png",
"title":"TreeMaker",
"type":"project",
"id":1315337
},
{
"title":"a beautiful day with a flower",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/326/7716.png",
"creator":"Sakura102",
"id":3267716
},
{
"title":"A Walk in the Dream Park",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2032/9589.png",
"creator":"JoeTheMan18",
"id":20329589
},
{
"title":"Drawing with Shapes",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7700/9574.png",
"creator":"morant",
"id":77009574
},
{
"title":"pretty flower",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/271/1834.png",
"creator":"leszpio",
"id":2711834
},
{
"title":"Garden Secret",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/1045/1607.png",
"creator":"Eddie101101",
"id":10451607
}
],
"studio2":[
{
"title":"Garden Secret",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/1045/1607.png",
"creator":"Eddie101101",
"id":10451607
},
{
"title":"The Park",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2658/0310.png",
"creator":"taliapanda01",
"id":26580310
}
]
},
"show_forum":true
}

View file

@ -1,10 +0,0 @@
const React = require('react'); // eslint-disable-line
const Microworld = require('../../../components/microworld/microworld.jsx');
const Page = require('../../../components/page/www/page.jsx');
const render = require('../../../lib/render.jsx');
const microworldData = require('./art.json');
render(<Page><Microworld microworldData={microworldData} /></Page>, document.getElementById('app'));

View file

@ -1,475 +0,0 @@
{
"title":"Fashion",
"description":[
"Do you like fashion?",
"Watch this video about making fashion projects.",
"Then see what you can do with the dress-up game below.",
"Explore other fashion projects and make your own!"
],
"videos":[
{
"image":"https://i.vimeocdn.com/video/528845372.webp?mw=900&amp;mh=583&amp;q=70",
"link":"//player.vimeo.com/video/134864477?title=0&byline=0&portrait=0"
}
],
"microworld_project_id":"133865474",
"tips":[
{
"title":"Click on blocks to see what they do",
"thumbnails":[
{
"type":"tip",
"title":" Try clicking this block ",
"thumbnailUrl":"/images/microworlds/fashion/click-block-color.gif"
},
{
"type":"tip",
"title":" Or this block",
"thumbnailUrl":"/images/microworlds/fashion/click-block-costume.gif"
}
]
},
{
"title":"Try changing colors",
"thumbnails":[
{
"type":"tip",
"title":" First, select a clothing item ",
"thumbnailUrl":"/images/microworlds/fashion/shirts-sprite.png"
},
{
"type":"tip",
"title":" Then, try this script",
"thumbnailUrl":"/images/microworlds/fashion/when-clicked-color.gif"
},
{
"type":"tip",
"title":" Test it out!",
"thumbnailUrl":"/images/microworlds/fashion/click-shirt.gif"
}
]
},
{
"title":"Try changing costumes",
"thumbnails":[
{
"type":"tip",
"title":"Select a piece of clothing ",
"thumbnailUrl":"/images/microworlds/fashion/hats-sprite.png"
},
{
"type":"tip",
"title":"Then, switch costumes",
"thumbnailUrl":"/images/microworlds/fashion/when-clicked-costume.gif"
},
{
"type":"tip",
"title":" Now, click it!",
"thumbnailUrl":"/images/microworlds/fashion/click-hat.gif"
}
]
},
{
"title":"Say hello",
"thumbnails":[
{
"type":"tip",
"title":"Select the person",
"thumbnailUrl":"/images/microworlds/fashion/person-sprite.png"
},
{
"type":"tip",
"title":"Type in a phrase",
"thumbnailUrl":"/images/microworlds/fashion/say-something.gif"
},
{
"type":"tip",
"title":"Then, try this script",
"thumbnailUrl":"/images/microworlds/fashion/when-clicked-say.gif"
}
]
},
{
"title":"Move the sprites",
"thumbnails":[
{
"type":"tip",
"title":"Select an accessory",
"thumbnailUrl":"/images/microworlds/fashion/accessories-sprite.png"
},
{
"type":"tip",
"title":"Tell it where to go",
"thumbnailUrl":"/images/microworlds/fashion/when-clicked-goto.gif"
}
]
},
{
"title":"Other things to try",
"thumbnails":[
{
"type":"tip",
"title":"Add a sound ",
"thumbnailUrl":"/images/microworlds/fashion/play-drum.png"
},
{
"type":"tip",
"title":" Explore other costumes ",
"thumbnailUrl":"/images/microworlds/fashion/next-costume.png"
},
{
"type":"tip",
"title":"Make longer scripts ",
"thumbnailUrl":"/images/microworlds/fashion/block-stack.png"
}
]
}
],
"community_projects":{
"featured_projects":[
{
"title":"☆Mystica Dress Up Game☆",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7135/4508.png",
"creator":"xVanyx",
"id":71354508
},
{
"title":"Design a bag Contest! Round two! remix",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6762/5700.png",
"creator":"walterwolf",
"id":67625700
},
{
"title":"Paint Nails! ~ [Pinta las uñas]",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2465/4259.png",
"creator":"aguchita",
"id":24654259
},
{
"title":"★1990s Inspired Dress Up★",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6464/1106.png",
"creator":"amee-",
"id":64641106
},
{
"title":"Minion Dress up Game",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/1205/3016.png",
"creator":"Dobbby",
"id":12053016
},
{
"title":"Mabel's Dress Up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2579/6804.png",
"creator":"MagicianCat",
"id":25796804
},
{
"title":"Jeremy's Dressup",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4110/6638.png",
"creator":"ipzy",
"id":41106638
},
{
"title":"Elsa Dress-Up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2130/5521.png",
"creator":"elsaunikitty",
"id":21305521
}
],
"newest_projects":[
{
"title":"Purse Land",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9349/4126.png",
"creator":"punkbass",
"id":93494126
},
{
"title":"Lilly's Fashion Salon! ",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9363/9916.png",
"creator":"cs54016",
"id":93639916
},
{
"title":"Lilly's Fashion Salon! ",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9363/9916.png",
"creator":"cs54016",
"id":93639916
},
{
"title":"dress up game (my characters/ bff characters)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9363/5245.png",
"creator":"lockeythekey",
"id":93635245
},
{
"title":"Anime Dress Up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9361/1094.png",
"creator":"Alyanda",
"id":93611094
},
{
"title":"Stick Man/Woman Dress Up!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9357/7986.png",
"creator":"loopey7890",
"id":93577986
},
{
"title":"2-D Dress Up!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9361/3207.png",
"creator":"Arkoarsenic",
"id":93613207
},
{
"title":"Stickbro Dress Up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9356/4550.png",
"creator":"Discord21",
"id":93564550
},
{
"title":"Bear Dress Up remix",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9361/2027.png",
"creator":"cssuperfudge",
"id":93612027
},
{
"title":"dress up Lucy",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9360/8879.png",
"creator":"123showbiz",
"id":93608879
},
{
"title":"Hair Play",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9181/0572.png",
"creator":"Aphrodite369",
"id":91810572
},
{
"title":"Warrior Cat Maker",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9357/0484.png",
"creator":"Nikinoo42",
"id":93570484
},
{
"title":"Bearie Dress Up remix",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9358/0802.png",
"creator":"SRajput",
"id":93580802
},
{
"title":"Chibi Cute Bear Dress Up :D",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9355/9967.png",
"creator":"UnicornAnna",
"id":93559967
},
{
"title":"Laura beach dress up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9356/5520.png",
"creator":"rozyczka2122004",
"id":93565520
},
{
"title":"Dress Up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9354/8643.png",
"creator":"rwd05",
"id":93548643
},
{
"title":"dress up scratch cat!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9356/1200.png",
"creator":"CONFIDENTDRAGON",
"id":93561200
},
{
"title":"Dress Up Olive",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9276/7275.png",
"creator":"rozyczka2122004",
"id":92767275
},
{
"title":"Bear Dress Up remix",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9354/5576.png",
"creator":"pixiepants14",
"id":93545576
},
{
"title":"Dress up Nano and Giga",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8681/5299.png",
"creator":"awesomesauce1243",
"id":86815299
}
]
},
"design_challenge":{
"studio_id":"1424746",
"studio1":[
{
"title":" BIG cool dress up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/5027/9238.png",
"creator":"Ratties123",
"id":50279238
},
{
"title":"~*Dressup*~ (40+ clothes and acessories)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4966/3352.png",
"creator":"NinniV",
"id":49663352
},
{
"title":"Dress up Bun-bun",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7047/3464.png",
"creator":"LillyMoon15",
"id":70473464
},
{
"title":"Dress Up Pikachu",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/1189/5141.png",
"creator":"poke10",
"id":11895141
},
{
"title":"dress up",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6261/8658.png",
"creator":"peachycream1",
"id":62618658
}
],
"studio2":[
{
"title":"Dress Up Fun!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6289/6096.png",
"creator":"sapphire-grace",
"id":62896096
},
{
"title":"Finicky Fashionista",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7210/8732.png",
"creator":"Bex36",
"id":72108732
},
{
"title":"Dress Up! :D",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6/2256.png",
"creator":"angelical",
"id":62256
},
{
"title":"Dress Up Tera",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/1165/6680.png",
"creator":"Scratchteam",
"id":11656680
}
]
},
"show_forum":false
}

View file

@ -1,10 +0,0 @@
const React = require('react'); // eslint-disable-line
const Microworld = require('../../../components/microworld/microworld.jsx');
const Page = require('../../../components/page/www/page.jsx');
const render = require('../../../lib/render.jsx');
const microworldData = require('./fashion.json');
render(<Page><Microworld microworldData={microworldData} /></Page>, document.getElementById('app'));

View file

@ -1,532 +0,0 @@
{
"title":"Hip Hop",
"description":[
"Do you like hip-hop?",
"Watch a video about making hip-hop projects.",
"Then, create your own dance scene!",
"Check out projects by others for inspiration."
],
"videos":[
{
"image":"https://i.vimeocdn.com/video/521248373.webp?mw=900&mh=583&q=70",
"link":"//player.vimeo.com/video/124055657?title=0&byline=0&portrait=0"
}
],
"microworld_project_id":"133865050",
"tips":[
{
"title":"Start Dancing",
"thumbnails":[
{
"type":"tip",
"title":"First, select a sprite",
"thumbnailUrl":"/images/microworlds/hiphop/dancer-sprite.png"
},
{
"type":"tip",
"title":"Then, try this script",
"thumbnailUrl":"/images/microworlds/hiphop/switch-wait.gif"
},
{
"type":"tip",
"title":"Start it!",
"thumbnailUrl":"/images/microworlds/hiphop/green-flag.gif"
}
]
},
{
"title":"Repeat the Dance",
"thumbnails":[
{
"type":"tip",
"title":"Add another \"wait\"",
"thumbnailUrl":"/images/microworlds/hiphop/add-wait.gif"
},
{
"type":"tip",
"title":"Drag this block over",
"thumbnailUrl":"/images/microworlds/hiphop/add-repeat.gif"
},
{
"type":"tip",
"title":"Start it",
"thumbnailUrl":"/images/microworlds/hiphop/green-flag.gif"
}
]
},
{
"title":"Play Music",
"thumbnails":[
{
"type":"tip",
"title":"Add music that repeats",
"thumbnailUrl":"/images/microworlds/hiphop/add-play-sound.gif"
},
{
"type":"tip",
"title":"Start it",
"thumbnailUrl":"/images/microworlds/hiphop/green-flag.gif"
}
]
},
{
"title":"Shadow Dance",
"thumbnails":[
{
"type":"tip",
"title":"Add this block",
"thumbnailUrl":"/images/microworlds/hiphop/shadow-dance.gif"
},
{
"type":"tip",
"title":"Start it",
"thumbnailUrl":"/images/microworlds/hiphop/green-flag.gif"
},
{
"type":"tip",
"title":"Click the stop sign to reset",
"thumbnailUrl":"/images/microworlds/hiphop/stop.gif"
}
]
},
{
"title":"More things to try",
"thumbnails":[
{
"type":"tip",
"title":"Try different dance moves",
"thumbnailUrl":"/images/microworlds/hiphop/change-dance-moves.gif"
},
{
"type":"tip",
"title":"Add more moves",
"thumbnailUrl":"/images/microworlds/hiphop/long-dance-script.png"
},
{
"type":"tip",
"title":"Change the timing",
"thumbnailUrl":"/images/microworlds/hiphop/change-dance-timing.png"
}
]
}
],
"community_projects":{
"featured_projects":[
{
"title":"tuting spins",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4827/0148.png",
"creator":"LHB97",
"id":48270148
},
{
"title":"Top Rock Giga",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4048/8688.png",
"creator":"designerd",
"id":40488688
},
{
"title":"EpicDance",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/4819/7838.png",
"creator":"codamax",
"id":48197838
},
{
"title":"Top Rockin in LA",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/3848/8304.png",
"creator":"sleggss",
"id":38488304
},
{
"title":"Silhouette Dance",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/2758/2882.png",
"creator":"natalie",
"id":27582882
}
],
"newest_projects":[
{
"title":"Crash Team Racing - Oxide Station Music (musica)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9331/8865.png",
"creator":"golden_freddy_fnaf5",
"id":93318865
},
{
"title":"DANCE OFF!!!!!!!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9287/4306.png",
"creator":"fjoyce11",
"id":92874306
},
{
"title":"hip hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9301/0585.png",
"creator":"Graystripe436",
"id":93010585
},
{
"title":"Hip hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9100/9512.png",
"creator":"krivas57",
"id":91009512
},
{
"title":"ElectroKill",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9039/0194.png",
"creator":"Snipeshot621",
"id":90390194
},
{
"title":"Breakbeat Mayhem",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9033/9020.png",
"creator":"Snipeshot621",
"id":90339020
},
{
"title":"(GetUpMusic)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8848/1759.png",
"creator":"XavierTheBrave",
"id":88481759
},
{
"title":"Hip Hop Dance",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8864/4804.png",
"creator":"kawaiigroovycat15",
"id":88644804
},
{
"title":"lezione hip hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8840/9021.png",
"creator":"MartinaStrazzer",
"id":88409021
},
{
"title":"Hip Hop Peeps",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8834/4657.png",
"creator":"dhajacob",
"id":88344657
},
{
"title":"Hiphop (voorbeeld signalen)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8812/7565.png",
"creator":"Juf-Pinky",
"id":88127565
},
{
"title":"Flashback: 1990",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8645/1526.png",
"creator":"Splo",
"id":86451526
},
{
"title":"Focus by Ariana Grande",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8687/1578.png",
"creator":"musical11",
"id":86871578
},
{
"title":"Clock",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8640/1798.png",
"creator":"IlikeMario5",
"id":86401798
},
{
"title":"Nice Hip Hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6195/5882.png",
"creator":"FireyDeath4",
"id":61955882
},
{
"title":"SUPRISE!!!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8629/4705.png",
"creator":"Jungster31",
"id":86294705
},
{
"title":"Harold Hip-Hop's Big Adventure",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8536/8362.png",
"creator":"Will64",
"id":85368362
},
{
"title":"epic dance(add your own dancers)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8308/2812.png",
"creator":"Zstrap10",
"id":83082812
},
{
"title":"Hip-Hop VS. Bad photoshop! [Hallowen update!]",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7579/4280.png",
"creator":"konradel",
"id":75794280
},
{
"title":"hip hop is in the air",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7653/2008.png",
"creator":"millamarwick",
"id":76532008
}
]
},
"design_challenge":{
"studio_id":"1065372",
"studio1":[
{
"title":"Crash Team Racing - Oxide Station Music (musica)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9331/8865.png",
"creator":"golden_freddy_fnaf5",
"id":93318865
},
{
"title":"DANCE OFF!!!!!!!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9287/4306.png",
"creator":"fjoyce11",
"id":92874306
},
{
"title":"hip hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9301/0585.png",
"creator":"Graystripe436",
"id":93010585
},
{
"title":"Hip hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9100/9512.png",
"creator":"krivas57",
"id":91009512
},
{
"title":"ElectroKill",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9039/0194.png",
"creator":"Snipeshot621",
"id":90390194
},
{
"title":"Breakbeat Mayhem",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/9033/9020.png",
"creator":"Snipeshot621",
"id":90339020
},
{
"title":"(GetUpMusic)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8848/1759.png",
"creator":"XavierTheBrave",
"id":88481759
},
{
"title":"Hip Hop Dance",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8864/4804.png",
"creator":"kawaiigroovycat15",
"id":88644804
},
{
"title":"lezione hip hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8840/9021.png",
"creator":"MartinaStrazzer",
"id":88409021
},
{
"title":"Hip Hop Peeps",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8834/4657.png",
"creator":"dhajacob",
"id":88344657
},
{
"title":"Hiphop (voorbeeld signalen)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8812/7565.png",
"creator":"Juf-Pinky",
"id":88127565
},
{
"title":"Flashback: 1990",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8645/1526.png",
"creator":"Splo",
"id":86451526
},
{
"title":"Focus by Ariana Grande",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8687/1578.png",
"creator":"musical11",
"id":86871578
},
{
"title":"Clock",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8640/1798.png",
"creator":"IlikeMario5",
"id":86401798
},
{
"title":"Nice Hip Hop",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/6195/5882.png",
"creator":"FireyDeath4",
"id":61955882
},
{
"title":"SUPRISE!!!",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8629/4705.png",
"creator":"Jungster31",
"id":86294705
}
],
"studio2":[
{
"title":"Harold Hip-Hop's Big Adventure",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8536/8362.png",
"creator":"Will64",
"id":85368362
},
{
"title":"epic dance(add your own dancers)",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/8308/2812.png",
"creator":"Zstrap10",
"id":83082812
},
{
"title":"Hip-Hop VS. Bad photoshop! [Hallowen update!]",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7579/4280.png",
"creator":"konradel",
"id":75794280
},
{
"title":"hip hop is in the air",
"type":"project",
"remixers_count":168,
"love_count":3062,
"thumbnail_url":"//cdn.scratch.mit.edu/static/site/projects/thumbnails/7653/2008.png",
"creator":"millamarwick",
"id":76532008
}
]
},
"show_forum":false
}

View file

@ -1,10 +0,0 @@
const React = require('react'); // eslint-disable-line
const Microworld = require('../../../components/microworld/microworld.jsx');
const Page = require('../../../components/page/www/page.jsx');
const render = require('../../../lib/render.jsx');
const microworldData = require('./hiphop.json');
render(<Page><Microworld microworldData={microworldData} /></Page>, document.getElementById('app'));

View file

@ -1,8 +0,0 @@
{
"title":"Soccer",
"description":[
"Make your own soccer animation or game!"
],
"microworld_project_id":"133865271",
"show_forum":false
}

View file

@ -1,10 +0,0 @@
const React = require('react'); // eslint-disable-line
const Microworld = require('../../../components/microworld/microworld.jsx');
const Page = require('../../../components/page/www/page.jsx');
const render = require('../../../lib/render.jsx');
const microworldData = require('./soccer.json');
render(<Page><Microworld microworldData={microworldData} /></Page>, document.getElementById('app'));

View file

@ -1,13 +0,0 @@
{
"tile.tutorial": "Microworld",
"tile.tryIt": "Try It",
"microworlds.title": "Scratch Microworlds",
"microworlds.subTitle": "You can get started with Scratch in a variety of ways. Click a picture to try one.",
"microworlds.HipHopTitle": "Hip Hop Dance",
"microworlds.FashionTitle": "Fashion",
"microworlds.HouseTitle": "Interactive House",
"microworlds.MakeMusicTitle": "Make Music",
"microworlds.SoccerTitle": "Soccer",
"microworlds.JokeTitle": "Make a Joke",
"microworlds.ArtTitle": "Make Art"
}

View file

@ -1,37 +0,0 @@
[
{
"title": "microworlds.HipHopTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13386/5050.png",
"tutorialLoc": "/pathways/hiphop"
},
{
"title": "microworlds.MakeMusicTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13386/5393.png",
"tutorialLoc": "/projects/embed-editor/133865393/?isMicroworld=true"
},
{
"title": "microworlds.SoccerTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13386/5271.png",
"tutorialLoc": "/projects/embed-editor/133865271/?isMicroworld=true"
},
{
"title": "microworlds.FashionTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13386/5474.png",
"tutorialLoc": "/pathways/fashion"
},
{
"title": "microworlds.ArtTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13386/5435.png",
"tutorialLoc": "/projects/embed-editor/133865435/?isMicroworld=true"
},
{
"title": "microworlds.JokeTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13386/5327.png",
"tutorialLoc": "/projects/embed-editor/133865327/?isMicroworld=true"
},
{
"title": "microworlds.HouseTitle",
"thumbUrl": "//cdn.scratch.mit.edu/static/site/projects/thumbnails/13383/5490.png",
"tutorialLoc": "/projects/embed-editor/133835490/?isMicroworld=true"
}
]

View file

@ -1,49 +0,0 @@
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage;
const React = require('react');
const MasonryGrid = require('../../components/masonrygrid/masonrygrid.jsx');
const TitleBanner = require('../../components/title-banner/title-banner.jsx');
const TTTTile = require('../../components/ttt-tile/ttt-tile.jsx');
const Page = require('../../components/page/www/page.jsx');
const render = require('../../lib/render.jsx');
const Tiles = require('./microworlds.json');
require('./microworldshomepage.scss');
const MicroworldsHomepage = props => (
<div className="microworlds">
<TitleBanner className="masthead mod-blue-bg">
<h1 className="title-banner-h1">
<FormattedMessage id="microworlds.title" />
</h1>
<p className="intro title-banner-p">
<FormattedHTMLMessage id="microworlds.subTitle" />
</p>
</TitleBanner>
<div className="inner">
<MasonryGrid >
{Tiles.map((tile, key) => (
<TTTTile
key={key}
thumbUrl={tile.thumbUrl}
title={props.intl.formatMessage({id: tile.title})}
tutorialLoc={tile.tutorialLoc}
/>
))}
</MasonryGrid>
</div>
</div>
);
MicroworldsHomepage.propTypes = {
intl: intlShape
};
const WrappedMicroworldsHomepage = injectIntl(MicroworldsHomepage);
render(<Page><WrappedMicroworldsHomepage /></Page>, document.getElementById('app'));

View file

@ -1,3 +0,0 @@
#view {
padding: 0;
}

View file

@ -0,0 +1,41 @@
{
"parents.title": "For Parents",
"parents.intro": "Scratch is a programming language and an online community where children\n can program and share interactive media such as stories, games, and \nanimation with people from all over the world. As children create with \nScratch, they learn to think creatively, work collaboratively, and \nreason systematically. Scratch is designed and maintained by the \nLifelong Kindergarten group at the MIT Media Lab. ",
"parents.overview": "How it works",
"parents.faq": "FAQ",
"parents.overviewTitle": "How does Scratch work for children?",
"parents.overviewLearningTitle": "Learning",
"parents.overviewLearningBody": "For a one-page overview of what young people learn with Scratch, see {learningWithScratch}.\nRead an article on the {creativeLearningApproach}.",
"parents.learningWithScratchLinkText": "Learning with Scratch",
"parents.creativeLearningApproachLinkText": "Creative Learning Approach",
"parents.overviewCommunityTitle": "Community",
"parents.overviewCommunityBody": "We ask all participants on the site to follow the {communityGuidelines}.\nWe do not make private account information available to anyone. For more information, please see the {privacyPolicy}.",
"parents.communityGuidelinesLinkText": "Community Guidelines",
"parents.privacyPolicyLinkText": "Privacy Policy",
"parents.faqMoreAndAsk": "To find out more about Scratch, please see {faqPage}.\nYou can also ask questions in the {discussionForums}.\nIf you need to contact our staff team directly, click {contactUs} at the bottom of any page.",
"parents.faqLinkText": "Frequently Asked Questions",
"parents.faqDiscussionForumsLinkText": "Discussion Forums",
"parents.faqContactUsLinkText": "Contact Us",
"parents.faqAgeRangeTitle": "What is the age range for Scratch?",
"parents.faqAgeRangeBody": "Scratch is designed especially for young people ages 8 to 16, but people of all ages create and share with Scratch. Younger children may want to try {scratchJr}, a simplified version of Scratch designed for ages 5 to 7.",
"parents.faqResourcesTitle": "What resources are available for learning Scratch?",
"parents.faqResourcesBody": "If youre just getting started, theres a {stepByStepGuide} available inside Scratch. For an overview of Scratch resources, see the {ideasPage} page.",
"parents.faqIdeasLinkText": "Ideas",
"parents.faqStepByStepGuideLinkText": "step-by-step guide",
"parents.faqGettingStartedGuideLinkText": "Getting Started guide (PDF)",
"parents.faqScratchCardsLinkText": "Scratch Cards",
"parents.faqTipsLinkText": "Tips",
"parents.faqCommunityTitle": "What is the Scratch online community?",
"parents.faqCommunityBody": "When participating in the Scratch online community, members can explore and experiment in an open learning community with other Scratch members from all backgrounds, ages, and interests. Members can share their work, get feedback, and learn from each other.",
"parents.faqGuidelinesTitle": "What are the guidelines for the Scratch online community?",
"parents.faqGuidelinesBody": "The MIT Scratch Team works with the community to maintain a friendly and respectful environment for people of all ages, races, ethnicities, religions, sexual orientations, and gender identities. You can help your child learn how to participate by reviewing the {communityGuidelines} together. Members are asked to comment constructively and to help keep the website friendly by reporting any content that does not follow the community guidelines. The Scratch Team works each day to manage activity on the site and respond to reports, with the help of tools such as the {CleanSpeak} profanity filter.",
"parents.faqCommunityGuidelinesLinkText": "community guidelines",
"parents.faqPrivacyPolicyTitle": "What is your privacy policy?",
"parents.faqPrivacyPolicyBody": "To protect children's online privacy, we limit what we collect during the signup process, and what we make public on the website. We don't sell or rent account information to anyone. You can find out more about our {privacyPolicy} page.",
"parents.faqFAQLinkText": "frequently asked questions page",
"parents.faqOfflineTitle": "Is there a way to use Scratch without participating online?",
"parents.faqOfflineBody" : "The Scratch Desktop editor allows you to create Scratch projects without an internet connection. You can download {scratchDesktop} from the website. This was previously called the Scratch Offline editor.",
"parents.faqScratchDesktop": "Scratch Desktop",
"parents.faqOffline2LinkText": "Scratch 2.0 offline editor",
"parents.faqOffline14LinkText": "Scratch 1.4 offline editor"
}

View file

@ -0,0 +1,268 @@
const FormattedMessage = require('react-intl').FormattedMessage;
const React = require('react');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const SubNavigation = require('../../components/subnavigation/subnavigation.jsx');
const TitleBanner = require('../../components/title-banner/title-banner.jsx');
const Page = require('../../components/page/www/page.jsx');
const render = require('../../lib/render.jsx');
require('./parents.scss');
const Landing = () => (
<div className="parents">
<TitleBanner className="masthead">
<div className="inner">
<h1 className="title-banner-h1">
<FormattedMessage id="parents.title" />
</h1>
<FlexRow className="masthead-info">
<p className="title-banner-p intro">
<FormattedMessage id="parents.intro" />
</p>
<div className="ted-talk">
<iframe
allowFullScreen
frameBorder="0"
src="https://www.youtube.com/embed/jXUZaf5D12A"
/>
</div>
</FlexRow>
</div>
<div className="band">
<SubNavigation className="inner">
<a href="#overview">
<li>
<FormattedMessage id="parents.overview" />
</li>
</a>
<a href="#faq">
<li>
<FormattedMessage id="parents.faq" />
</li>
</a>
</SubNavigation>
</div>
</TitleBanner>
<div className="inner">
<section id="overview">
<span className="nav-spacer" />
<h2>
<FormattedMessage id="parents.overviewTitle" />
</h2>
<FlexRow className="general-usage">
<div>
<h3><FormattedMessage id="parents.overviewLearningTitle" /></h3>
<p>
<FormattedMessage
id="parents.overviewLearningBody"
values={{
learningWithScratch: (
<a href="http://llk.media.mit.edu/scratch/Learning-with-Scratch.pdf">
<FormattedMessage
id="parents.learningWithScratchLinkText"
/>
</a>
),
creativeLearningApproach: (
<a href="http://www.edutopia.org/kindergarten-creativity-collaboration-lifelong-learning">
<FormattedMessage
id="parents.creativeLearningApproachLinkText"
/>
</a>
)
}}
/>
</p>
</div>
<div>
<h3><FormattedMessage id="parents.overviewCommunityTitle" /></h3>
<p>
<FormattedMessage
id="parents.overviewCommunityBody"
values={{
communityGuidelines: (
<a href="/community_guidelines">
<FormattedMessage
id="parents.communityGuidelinesLinkText"
/>
</a>
),
privacyPolicy: (
<a href="/privacy_policy">
<FormattedMessage
id="parents.privacyPolicyLinkText"
/>
</a>
)
}}
/>
</p>
</div>
</FlexRow>
</section>
</div>
<TitleBanner className="faq-banner">
<div className="inner">
<section id="faq">
<span className="nav-spacer" />
<h2><FormattedMessage id="parents.faq" /></h2>
<p>
<FormattedMessage
id="parents.faqMoreAndAsk"
values={{
faqPage: (
<a href="/info/faq">
<FormattedMessage
id="parents.faqLinkText"
/>
</a>
),
discussionForums: (
<a href="/discuss">
<FormattedMessage
id="parents.faqDiscussionForumsLinkText"
/>
</a>
),
contactUs: (
<a href="/contact-us">
<FormattedMessage
id="parents.faqContactUsLinkText"
/>
</a>
)
}}
/>
</p>
<FlexRow className="three-col-row">
<div className="faq column">
<h3><FormattedMessage id="parents.faqAgeRangeTitle" /></h3>
<p>
<FormattedMessage
id="parents.faqAgeRangeBody"
values={{
scratchJr: (
<a href="https://www.scratchjr.org/">
ScratchJr
</a>
)
}}
/>
</p>
</div>
<div className="faq column">
<h3><FormattedMessage id="parents.faqResourcesTitle" /></h3>
<p>
<FormattedMessage
id="parents.faqResourcesBody"
values={{
ideasPage: (
<a href="/ideas">
<FormattedMessage
id="parents.faqIdeasLinkText"
/>
</a>
),
stepByStepGuide: (
<a href="/projects/editor/?tutorial=getStarted">
<FormattedMessage
id="parents.faqStepByStepGuideLinkText"
/>
</a>
),
gettingStartedGuide: (
<a href="https://cdn.scratch.mit.edu/scratchr2/static/__edf64cc2d5d5da51528c169e65053195__//pdfs/help/Getting-Started-Guide-Scratch2.pdf">
<FormattedMessage
id="parents.faqGettingStartedGuideLinkText"
/>
</a>
),
scratchCards: (
<a href="/info/cards">
<FormattedMessage
id="parents.faqScratchCardsLinkText"
/>
</a>
),
tips: (
<a href="/tips">
<FormattedMessage
id="parents.faqTipsLinkText"
/>
</a>
)
}}
/>
</p>
</div>
<div className="faq column">
<h3><FormattedMessage id="parents.faqCommunityTitle" /></h3>
<p>
<FormattedMessage id="parents.faqCommunityBody" />
</p>
</div>
<div className="faq column">
<h3><FormattedMessage id="parents.faqGuidelinesTitle" /></h3>
<p>
<FormattedMessage
id="parents.faqGuidelinesBody"
values={{
communityGuidelines: (
<a href="/community_guidelines">
<FormattedMessage
id="parents.faqCommunityGuidelinesLinkText"
/>
</a>
),
CleanSpeak: (
<a href="http://www.inversoft.com/features/profanity-filter/">CleanSpeak</a>
)
}}
/>
</p>
</div>
<div className="faq column">
<h3><FormattedMessage id="parents.faqPrivacyPolicyTitle" /></h3>
<p>
<FormattedMessage
id="parents.faqPrivacyPolicyBody"
values={{
privacyPolicy: (
<a href="/privacy_policy">
<FormattedMessage
id="parents.privacyPolicyLinkText"
/>
</a>
)
}}
/>
</p>
</div>
<div className="faq column">
<h3><FormattedMessage id="parents.faqOfflineTitle" /></h3>
<p>
<FormattedMessage
id="parents.faqOfflineBody"
values={{
scratchDesktop: (
<a href="/download">
<FormattedMessage
id="parents.faqScratchDesktop"
/>
</a>
)
}}
/>
</p>
</div>
</FlexRow>
</section>
</div>
</TitleBanner>
</div>
);
render(<Page><Landing /></Page>, document.getElementById('app'));

View file

@ -0,0 +1,269 @@
@import "../../colors";
@import "../../frameless";
$parents-spot: $ui-blue-dark;
$story-width: $cols3;
#view {
padding: 0;
}
.parents {
.intro {
margin: 0;
}
b {
font-weight: bold;
}
a {
white-space: normal;
}
.title-banner {
&.masthead {
background-color: $parents-spot;
padding-bottom: 0;
h1 {
margin: 0;
color: $ui-white;
}
.masthead-info {
display: flex;
align-items: center;
justify-content: space-between;
p {
margin: 0;
max-width: $cols6;
text-align: left;
color: $ui-white;
a {
border-bottom: 1px solid $ui-white;
color: $ui-white;
}
}
}
.ted-talk {
position: relative;
margin-bottom: $gutter;
border: 2px solid $ui-border;
border-radius: 10px;
width: $cols4;
height: $cols4 * .5625;
overflow: hidden;
iframe {
border: 0;
width: inherit;
height: inherit;
}
}
.band {
$band-color: hsla(360, 100, 100, .15);
margin-top: 2rem;
background-color: $band-color;
padding: 1rem 0;
}
.sub-nav {
text-align: left;
li {
margin: 0 .5rem 0 0;
}
}
}
&.faq-banner {
margin-bottom: 0;
background-color: $ui-gray;
}
}
.general-usage {
justify-content: space-between;
p {
max-width: $cols5;
}
}
section {
margin-bottom: 3rem;
}
#overview,
#faq {
.nav-spacer {
display: block;
visibility: hidden;
margin-top: -50px; // height of nav bar
height: 50px;
}
}
}
//4 columns
@media only screen and (max-width: $mobile - 1) {
.title-banner {
&.masthead {
padding-bottom: 2rem;
}
.band {
display: none;
}
}
.flex-row {
&.sidebar-row {
.body-copy {
width: 100%;
}
}
}
.overview {
text-align: center;
}
.flex-row {
align-items: center;
}
.general-usage {
align-items: center;
}
}
//6 columns
@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) {
.flex-row {
&.sidebar-row {
.body-copy {
width: 100%;
}
.sidebar {
margin: 0 auto;
}
}
}
.overview {
text-align: center;
}
.flex-row {
align-items: center;
}
.general-usage {
align-items: center;
}
}
//8 columns
@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) {
.masthead {
h1 {
text-align: center;
}
.subnav {
justify-content: center;
}
}
.masthead-info {
p {
width: $cols4;
}
iframe {
width: $cols4;
box-sizing: border-box;
}
}
#view {
text-align: left;
}
.flex-row {
&.sidebar-row {
.body-copy {
width: 100%;
}
.sidebar {
margin: 0 auto;
}
}
}
#overview {
h2 {
text-align: center;
}
.intro {
margin-bottom: 1rem;
text-align: center;
}
.general-usage {
margin-bottom: 2rem;
p {
margin: .25em 0;
max-width: $cols8;
text-align: center;
}
}
}
section {
p {
width: 100%;
}
}
#left {
width: $cols4;
}
}
// 12 columns
@media only screen and (min-width: $desktop) {
.masthead {
h1 {
text-align: left;
}
.sub-nav {
justify-content: flex-start;
}
}
.general-usage {
align-items: flex-start;
}
}

View file

@ -0,0 +1,34 @@
const PropTypes = require('prop-types');
const React = require('react');
const classNames = require('classnames');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const Button = require('../../components/forms/button.jsx');
require('./banner.scss');
const Banner = ({className, message, actionMessage, onAction}) => (
<div className={classNames('banner-outer', className)}>
<FlexRow className="inner banner-inner">
<span className="banner-text">
{message}
</span>
{actionMessage && onAction && (
<Button
className="banner-button"
onClick={onAction}
>
{actionMessage}
</Button>
)}
</FlexRow>
</div>
);
Banner.propTypes = {
actionMessage: PropTypes.node,
className: PropTypes.string,
message: PropTypes.node.isRequired,
onAction: PropTypes.func
};
module.exports = Banner;

View file

@ -0,0 +1,53 @@
@import "../../colors";
$navigation-height: 50px;
.banner-outer {
display: flex;
background-color: $ui-orange-25percent;
width: 100%;
min-height: 4rem;
overflow: hidden;
color: $ui-orange-high-contrast;
font-size: .875rem;
font-weight: bold;
align-self: center;
}
.banner-outer.banner-danger {
background-color: $ui-red-25percent;
color: $ui-red;
}
.banner-outer.banner-success {
background-color: $ui-green-35percent;
color: $ui-mint-green;
}
.banner-inner {
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
}
.banner-text {
padding: .5rem 0;
}
.banner-button {
margin-top: .75rem;
margin-bottom: .75rem;
border-radius: .25rem;
background-color: $ui-orange;
padding-top: .6875rem;
padding-bottom: .75rem;
min-width: 6rem;
max-width: 16rem;
min-height: 2.5rem;
max-height: 6rem;
font-size: .875rem;
}
.banner-danger .banner-button {
background-color: $ui-red;
}

View file

@ -158,7 +158,7 @@ class Comment extends React.Component {
className="comment-report" className="comment-report"
onClick={this.handleReport} onClick={this.handleReport}
> >
<FormattedMessage id="comments.report" /> <FormattedMessage id="general.report" />
</span> </span>
)} )}
</React.Fragment> </React.Fragment>

View file

@ -30,7 +30,7 @@
textarea { textarea {
&:not(:focus) { &:not(:focus) {
border: 1px solid $active-dark-gray; border: 2px solid $active-dark-gray;
} }
} }
} }
@ -199,6 +199,8 @@
} }
.comment-content { .comment-content {
font-size: 1rem;
line-height: 1.5rem;
overflow-wrap: break-word; overflow-wrap: break-word;
} }
@ -289,3 +291,7 @@
margin-right: -50%; margin-right: -50%;
} }
} }
/* Hide the action list buttons (delete/report/restore) until hover over */
.comment .action-list { opacity: 0; }
.comment:hover .action-list { opacity: 1; }

Some files were not shown because too many files have changed in this diff Show more