diff --git a/.travis.yml b/.travis.yml index 99aaa1b5b..59f2aa1da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,11 @@ env: - GA_TRACKER_VAR=GA_TRACKER_$TRAVIS_BRANCH - GA_TRACKER=${!GA_TRACKER_VAR} - GA_TRACKER=${GA_TRACKER:-$GA_TRACKER_STAGING} + - SCRATCH_ENV_master=production + - SCRATCH_ENV_STAGING=staging + - SCRATCH_ENV_VAR=SCRATCH_ENV_$TRAVIS_BRANCH + - SCRATCH_ENV=${!SCRATCH_ENV_VAR} + - SCRATCH_ENV=${SCRATCH_ENV:-$SCRATCH_ENV_STAGING} - S3_BUCKET_NAME_master=scratch-www-production - S3_BUCKET_NAME_STAGING=scratch-www-staging - S3_BUCKET_NAME_VAR=S3_BUCKET_NAME_$TRAVIS_BRANCH diff --git a/Makefile b/Makefile index fa44ed42e..a89afec30 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,9 @@ webpack: $(WEBPACK) --bail sync-s3: - $(S3CMD) sync -P --delete-removed --exclude '.DS_Store' --exclude '*.svg' ./build/ s3://$(S3_BUCKET_NAME)/ + $(S3CMD) sync -P --delete-removed --exclude '.DS_Store' --exclude '*.svg' --exclude '*.js' ./build/ s3://$(S3_BUCKET_NAME)/ $(S3CMD) sync -P --delete-removed --exclude '*' --include '*.svg' --mime-type 'image/svg+xml' ./build/ s3://$(S3_BUCKET_NAME)/ + $(S3CMD) sync -P --delete-removed --exclude '*' --include '*.js' --mime-type 'application/javascript' ./build/ s3://$(S3_BUCKET_NAME)/ sync-fastly: $(NODE) ./bin/configure-fastly.js diff --git a/custom-locales.json b/custom-locales.json index ad3e37405..83c4a0b11 100644 --- a/custom-locales.json +++ b/custom-locales.json @@ -1,4 +1,8 @@ { + "ab": { + "locale": "ab", + "parentLocale": "az" + }, "an": { "locale": "an", "parentLocale": "ca" diff --git a/languages.json b/languages.json index bcabe056f..85679754d 100644 --- a/languages.json +++ b/languages.json @@ -1,9 +1,11 @@ { - "en": "English", + "ab": "Аҧсшәа", + "ar": "العربية", "an": "Aragonés", "ast": "Asturianu", "id": "Bahasa Indonesia", "ms": "Bahasa Melayu", + "bg": "Български", "ca": "Català", "cs": "Česky", "cy": "Cymraeg", @@ -12,62 +14,63 @@ "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", "is": "Íslenska", "it": "Italiano", + "kn": "ಭಾಷೆ-ಹೆಸರು", "rw": "Kinyarwanda", + "km": "សំលៀកបំពាក", "ht": "Kreyòl", "ku": "Kurdî", "la": "Latina", "lv": "Latviešu", "lt": "Lietuvių", + "mk": "Македонски", "hu": "Magyar", + "ml": "മലയാളം", "mt": "Malti", + "mr": "मराठी", "cat": "Meow", + "mn": "Монгол хэл", + "my": "မြန်မာဘာသာ", "nl": "Nederlands", + "ja": "日本語", + "ja-hr": "にほんご", "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": "Shqiptar", "sk": "Slovenčina", "sl": "Slovenščina", - "fi": "suomi", + "sr": "Српски", + "fi": "Suomi", "sv": "Svenska", + "te": "తెలుగు", "nai": "Tepehuan", "vi": "Tiếng Việt", "tr": "Türkçe", - "ab": "Аҧсшәа", - "ar": "العربية", - "bg": "Български", - "el": "Ελληνικά", - "fa": "فارسی", - "he": "עִבְרִית", - "hi": "हिन्दी", - "hy": "Հայերեն", - "ja": "日本語", - "ja-hr": "にほんご", - "km": "សំលៀកបំពាក", - "kn": "ಭಾಷೆ-ಹೆಸರು", - "ko": "한국어", - "mk": "Македонски", - "ml": "മലയാളം", - "mn": "Монгол хэл", - "mr": "मराठी", - "my": "မြန်မာဘာသာ", - "ru": "Русский", - "sr": "Српски", - "th": "ไทย", "uk": "Українська", "zh-cn": "简体中文", "zh-tw": "正體中文" diff --git a/package.json b/package.json index a72efc85b..a9f0916aa 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "react-modal": "1.3.0", "react-onclickoutside": "4.1.1", "react-redux": "4.4.5", + "react-responsive": "1.1.4", "react-slick": "0.12.2", "react-telephone-input": "3.4.5", "redux": "3.5.2", diff --git a/src/_colors.scss b/src/_colors.scss index 7a8947665..dff8ef60a 100644 --- a/src/_colors.scss +++ b/src/_colors.scss @@ -11,6 +11,7 @@ $background-color: hsla(0, 0, 99, 1); //#FDFDFD /* UI Secondary Colors */ $ui-aqua: hsla(170, 70, 50, 1); //#26D9BB $ui-purple: hsla(265, 55, 55, 1); //#824DCB +$ui-yellow: hsla(45, 100, 50, 1); //#FFBF00 $ui-white: #fff; $ui-border: hsla(0, 0, 85, 1); //#D9D9D9 diff --git a/src/components/carousel/carousel.jsx b/src/components/carousel/carousel.jsx index fbebed63d..50df3a61b 100644 --- a/src/components/carousel/carousel.jsx +++ b/src/components/carousel/carousel.jsx @@ -5,6 +5,8 @@ var Slider = require('react-slick'); var Thumbnail = require('../thumbnail/thumbnail.jsx'); +var frameless = require('../../lib/frameless.js'); + require('slick-carousel/slick/slick.scss'); require('slick-carousel/slick/slick-theme.scss'); require('./carousel.scss'); @@ -27,12 +29,29 @@ var Carousel = React.createClass({ render: function () { var settings = this.props.settings || {}; defaults(settings, { + centerMode: false, dots: false, infinite: false, lazyLoad: true, slidesToShow: 5, slidesToScroll: 5, - variableWidth: true + variableWidth: true, + responsive: [ + {breakpoint: frameless.mobile, settings: { + arrows: true, + slidesToScroll: 1, + slidesToShow: 1, + centerMode: true + }}, + {breakpoint: frameless.tablet, settings: { + slidesToScroll: 2, + slidesToShow: 2 + }}, + {breakpoint: frameless.desktop, settings: { + slidesToScroll: 4, + slidesToShow: 4 + }} + ] }); var arrows = this.props.items.length > settings.slidesToShow; var classes = classNames( diff --git a/src/components/footer/conference/footer.scss b/src/components/footer/conference/footer.scss index 4d40c51cc..24d20e0ad 100644 --- a/src/components/footer/conference/footer.scss +++ b/src/components/footer/conference/footer.scss @@ -35,7 +35,7 @@ .intel { img { - max-height: 50px + max-height: 50px; } } } diff --git a/src/components/footer/www/footer.jsx b/src/components/footer/www/footer.jsx index 9388c2a42..e243a5a35 100644 --- a/src/components/footer/www/footer.jsx +++ b/src/components/footer/www/footer.jsx @@ -1,9 +1,14 @@ var React = require('react'); -var FormattedMessage = require('react-intl').FormattedMessage; +var ReactIntl = require('react-intl'); +var FormattedMessage = ReactIntl.FormattedMessage; +var injectIntl = ReactIntl.injectIntl; var FooterBox = require('../container/footer.jsx'); var LanguageChooser = require('../../languagechooser/languagechooser.jsx'); +var MediaQuery = require('react-responsive'); +var frameless = require('../../../lib/frameless'); + require('./footer.scss'); var Footer = React.createClass({ @@ -11,159 +16,197 @@ var Footer = React.createClass({ render: function () { return ( -
-
-
- -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ +
+
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
-
-
- -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
+
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
-
-
- -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
+
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
-
-
- -
-
- - - -
-
- - - -
-
- - - -
-
- -
-
- -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
-
- - +
+
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ +

@@ -175,4 +218,4 @@ var Footer = React.createClass({ } }); -module.exports = Footer; +module.exports = injectIntl(Footer); diff --git a/src/components/footer/www/footer.scss b/src/components/footer/www/footer.scss index d7bcfce93..43d195030 100644 --- a/src/components/footer/www/footer.scss +++ b/src/components/footer/www/footer.scss @@ -1,4 +1,5 @@ @import "../../../colors"; +@import "../../../frameless"; #footer { .lists { @@ -6,11 +7,10 @@ text-align: center; flex-direction: row; flex-wrap: nowrap; - justify-content: space-between; + justify-content: space-around; dl { display: inline-block; - width: 130pt; vertical-align: top; text-align: left; font-size: .8rem; diff --git a/src/components/forms/checkbox.scss b/src/components/forms/checkbox.scss index df8a17237..393ee86de 100644 --- a/src/components/forms/checkbox.scss +++ b/src/components/forms/checkbox.scss @@ -12,7 +12,7 @@ display: block; float: left; margin-right: 1rem; - border: 1px solid $active-gray; + border: 1px solid $active-dark-gray; border-radius: 3px; width: 1.25rem; height: 1.25rem; @@ -22,7 +22,7 @@ &:focus { transition: all .5s ease; outline: none; - box-shadow: 0 0 0 .25rem $active-gray; + box-shadow: 0 0 0 .25rem $active-dark-gray; } &:checked { diff --git a/src/components/forms/phone-input.jsx b/src/components/forms/phone-input.jsx index a4e26eb50..260c5a2ef 100644 --- a/src/components/forms/phone-input.jsx +++ b/src/components/forms/phone-input.jsx @@ -1,13 +1,15 @@ -var classNames = require('classnames'); -var React = require('react'); -var FormsyMixin = require('formsy-react').Mixin; -var ReactPhoneInput = require('react-telephone-input/lib/withStyles'); var allCountries = require('react-telephone-input/lib/country_data').allCountries; -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var validationHOCFactory = require('./validations.jsx').validationHOCFactory; -var Row = require('formsy-react-components').Row; +var classNames = require('classnames'); var ComponentMixin = require('formsy-react-components').ComponentMixin; +var FormsyMixin = require('formsy-react').Mixin; +var React = require('react'); +var ReactPhoneInput = require('react-telephone-input/lib/withStyles'); +var Row = require('formsy-react-components').Row; + +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; var inputHOC = require('./input-hoc.jsx'); +var intl = require('../../lib/intl.jsx'); +var validationHOCFactory = require('./validations.jsx').validationHOCFactory; var allIso2 = allCountries.map(function (country) {return country.iso2;}); @@ -62,7 +64,7 @@ var PhoneInput = React.createClass({ }); var phoneValidationHOC = validationHOCFactory({ - isPhone: 'Please enter a valid phone number' + isPhone: }); module.exports = inputHOC(defaultValidationHOC(phoneValidationHOC(PhoneInput))); diff --git a/src/components/forms/validations.jsx b/src/components/forms/validations.jsx index 6410322b9..bd5099e05 100644 --- a/src/components/forms/validations.jsx +++ b/src/components/forms/validations.jsx @@ -23,6 +23,7 @@ module.exports.validations = { return phoneNumberUtil.isValidNumber(parsed); } }; +module.exports.validations.notEqualsUsername = module.exports.validations.notEquals; module.exports.validationHOCFactory = function (defaultValidationErrors) { return function (Component) { diff --git a/src/components/grid/grid.jsx b/src/components/grid/grid.jsx index 04f8a0b42..93572840d 100644 --- a/src/components/grid/grid.jsx +++ b/src/components/grid/grid.jsx @@ -15,7 +15,8 @@ var Grid = React.createClass({ showLoves: false, showFavorites: false, showRemixes: false, - showViews: false + showViews: false, + showAvatar: false }; }, render: function () { @@ -36,10 +37,13 @@ var Grid = React.createClass({ showFavorites={this.props.showFavorites} showRemixes={this.props.showRemixes} showViews={this.props.showViews} + showAvatar={this.props.showAvatar} type={'project'} href={href} title={item.title} src={item.image} + avatar={'https://cdn2.scratch.mit.edu/get_image/user/' + + item.author.id + '_32x32.png'} creator={item.author.username} loves={item.stats.loves} favorites={item.stats.favorites} diff --git a/src/components/grid/grid.scss b/src/components/grid/grid.scss index 1f72e99d5..2afed6b19 100644 --- a/src/components/grid/grid.scss +++ b/src/components/grid/grid.scss @@ -1,40 +1,89 @@ @import "../../frameless"; +@import "../../colors"; .grid { display: inline-block; width: 100%; - $project-width: 200px; - $project-height: 150px; - - $gallery-width: 200px; - $gallery-height: 118px; + $thumbnail-width: 220px; + $thumbnail-inner-width: 204px; + + $project-height: 208px; + $gallery-height: 164px; .flex-row { margin: 0 auto; - padding: 12px; - width: (96px + (4 * $project-width)) / $em; + padding: 12px 0; + width: $cols12; justify-content: flex-start; } .thumbnail { - padding: 12px; + margin: 7px; + border-radius: 4px; + box-shadow: 0 0 3px $box-shadow-gray; + background-color: $ui-white; + padding-bottom: 4px; + width: $thumbnail-width; + + .thumbnail-image { + margin: 8px auto; + width: $thumbnail-inner-width; + } + + .thumbnail-info { + margin: 0 auto; + width: $thumbnail-inner-width; + + .creator-image { + float: left; + + img { + margin-right: 8px; + border-radius: 4px; + width: 32px; + height: 32px; + } + } + + .thumbnail-title { + float: left; + max-width: 164px; + + .thumbnail-creator a { + color: $type-gray; + } + } + } &.project { - width: $project-width; + height: $project-height; - img { - width: $project-width; - height: $project-height; + .thumbnail-image { + height: 152px; + + img { + margin: 0 auto; + border: 0; + border-radius: 4px; + width: $thumbnail-inner-width; + height: 152px; + } } } &.gallery { - width: $gallery-width; + height: $gallery-height; - img { - width: $gallery-width; - height: $gallery-height; + .thumbnail-image { + height: 120px; + + img { + border: 0; + border-radius: 4px; + width: $thumbnail-inner-width; + height: 120px; + } } } } @@ -44,15 +93,24 @@ justify-content: center; } - @media only screen and (max-width: $tablet - 1) { - flex-direction: column; + //4 columns + @media only screen and (max-width: $mobile - 1) { + .flex-row { + width: $cols4; + } } - @media only screen and (max-width: $desktop - 1) { + //6 columns + @media only screen and (min-width: $mobile) and (max-width: $tablet - 1) { .flex-row { - padding: 12px 0; - width: 100%; - justify-content: space-around; + width: $cols6; + } + } + + // 8 columns + @media only screen and (min-width: $tablet) and (max-width: $desktop - 1) { + .flex-row { + width: $cols9; } } } diff --git a/src/components/languagechooser/languagechooser.jsx b/src/components/languagechooser/languagechooser.jsx index bb6dc5910..c538fb923 100644 --- a/src/components/languagechooser/languagechooser.jsx +++ b/src/components/languagechooser/languagechooser.jsx @@ -16,7 +16,7 @@ var LanguageChooser = React.createClass({ getDefaultProps: function () { return { languages: languages, - locale: window._locale + locale: 'en' }; }, onSetLanguage: function (name, value) { diff --git a/src/components/login/login.scss b/src/components/login/login.scss index a8cf55da0..a00cceae2 100644 --- a/src/components/login/login.scss +++ b/src/components/login/login.scss @@ -7,11 +7,11 @@ padding-top: 5px; font-weight: bold; } - + .right { float: right; } - + .spinner { margin: 0 .8rem; width: 1rem; diff --git a/src/components/navigation/www/navigation.jsx b/src/components/navigation/www/navigation.jsx index ce7219f53..d2ffc819b 100644 --- a/src/components/navigation/www/navigation.jsx +++ b/src/components/navigation/www/navigation.jsx @@ -251,7 +251,9 @@ var Navigation = React.createClass({ - {this.props.session.session.user.username} + + {this.props.session.session.user.username} + ul > li { + &.login-item { + margin-left: 0; + } + + &.account-nav { + margin-left: 0; + + > a { + .avatar { + margin-right: 0; + } + + &:after { + display: none; + } + } + } + } + + .create, + .discuss, + .explore, + .search, + .help, + .mystuff, + .profile-name { + display: none; + } + } +} + + +//6 columns +@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) { + #navigation .inner { + width: $cols6; + + > ul > li { + &.login-item { + margin-left: 0; + } + + &.account-nav { + margin-left: 0; + + > a { + .avatar { + margin-right: 0; + } + + &:after { + display: none; + } + } + } + } + + .discuss, + .explore, + .search, + .mystuff, + .profile-name { + display: none; + } + + } +} + +//8 columns +@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) { + #navigation .inner { + width: $cols8; + + > ul > li { + &.login-item, + &.account-nav { + margin-left: 0; + } + } + + .explore, + .search, + .mystuff { + display: none; + } + } +} diff --git a/src/components/registration/steps.jsx b/src/components/registration/steps.jsx index b178083a1..854f5b785 100644 --- a/src/components/registration/steps.jsx +++ b/src/components/registration/steps.jsx @@ -89,38 +89,55 @@ module.exports = { onChangeShowPassword: function (field, value) { this.setState({showPassword: value}); }, - onValidSubmit: function (formData, reset, invalidate) { - this.setState({waiting: true}); + validateUsername: function (username, callback) { + callback = callback || function () {}; api({ host: '', - uri: '/accounts/check_username/' + formData.user.username + '/' - }, function (err, res) { + uri: '/accounts/check_username/' + username + '/' + }, function (err, body, res) { var formatMessage = this.props.intl.formatMessage; - this.setState({waiting: false}); - if (err) return invalidate({all: err}); - res = res[0]; - switch (res.msg) { + if (err || res.statusCode !== 200) { + err = err || formatMessage({id: 'general.error'}); + this.refs.form.refs.formsy.updateInputsWithError({all: err}); + return callback(false); + } + body = body[0]; + + switch (body.msg) { case 'valid username': this.setState({ validUsername: 'pass' }); - return this.props.onNextStep(formData); + return callback(true); case 'username exists': - return invalidate({ + this.refs.form.refs.formsy.updateInputsWithError({ 'user.username': formatMessage({id: 'registration.validationUsernameExists'}) }); + return callback(false); case 'bad username': - return invalidate({ + this.refs.form.refs.formsy.updateInputsWithError({ 'user.username': formatMessage({id: 'registration.validationUsernameVulgar'}) }); + return callback(false); case 'invalid username': default: - return invalidate({ + this.refs.form.refs.formsy.updateInputsWithError({ 'user.username': formatMessage({id: 'registration.validationUsernameInvalid'}) }); + return callback(false); } }.bind(this)); }, + onUsernameBlur: function (event) { + this.validateUsername(event.currentTarget.value); + }, + onValidSubmit: function (formData) { + this.setState({waiting: true}); + this.validateUsername(formData.user.username, function (isValid) { + this.setState({waiting: false}); + if (isValid) return this.props.onNextStep(formData); + }.bind(this)); + }, render: function () { var formatMessage = this.props.intl.formatMessage; return ( @@ -146,7 +163,7 @@ module.exports = { )}

-
+
{formatMessage({id: 'registration.createUsername'})} @@ -159,6 +176,7 @@ module.exports = {

- +
-
@@ -595,7 +615,7 @@ module.exports = { placeholder={'http://'} />
} /> + text={} /> diff --git a/src/components/registration/steps.scss b/src/components/registration/steps.scss index 21d0ff0a5..d9ef9e135 100644 --- a/src/components/registration/steps.scss +++ b/src/components/registration/steps.scss @@ -20,6 +20,10 @@ .row { margin-left: .5rem; + + .validation-message { + transform: translate(14rem, 0); + } } } @@ -102,14 +106,12 @@ } &.usescratch-step { - .form { - .form-group { - margin-bottom: 0; + .form-group { + margin-bottom: 0; - &.has-error { - .textarea { - border: 1px solid $ui-orange; - } + &.has-error { + .textarea { + border: 1px solid $ui-orange; } } } @@ -189,28 +191,3 @@ } } } - -/* IE10 and IE11 fallback */ -@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { - .registration-step { - &.username-step, - &.demographics-step, - &.name-step, - &.phone-step, - &.organization-step, - &.address-step, - &.email-step { - .validation-message { - position: relative; - transform: none; - margin: inherit; - width: 100%; - height: inherit; - - &:before { - display: none; - } - } - } - } -} diff --git a/src/components/tabs/tabs.jsx b/src/components/tabs/tabs.jsx index 814a3e02e..dd816c1ac 100644 --- a/src/components/tabs/tabs.jsx +++ b/src/components/tabs/tabs.jsx @@ -16,9 +16,11 @@ var Tabs = React.createClass({ this.props.className ); return ( - - {this.props.children} - +
+ + {this.props.children} + +
); } }); diff --git a/src/components/tabs/tabs.scss b/src/components/tabs/tabs.scss index 3d3939717..a612c3f76 100644 --- a/src/components/tabs/tabs.scss +++ b/src/components/tabs/tabs.scss @@ -1,38 +1,53 @@ @import "../../colors"; +@import "../../frameless"; + +.tab-background { + box-shadow: 0 0 1px $box-shadow-gray; + background-color: $ui-white; + width: 100%; +} .tabs { - background-color: $ui-gray; - padding: 0 0 0 20px; - width: calc(100% - 20px); - justify-content: flex-start; + background-color: $ui-white; + padding: 0; + width: $cols12; + justify-content: center; } .tabs li { - opacity: .75; - margin-bottom: -4px; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - background-color: $ui-white; + margin: 0; + border: 0; + border-radius: 0; + width: $cols2; + text-align: center; color: $header-gray; - + + &.active { + border-bottom: 3px solid $ui-aqua; + + &:hover { + border-bottom: 3px solid $ui-aqua; + color: $header-gray; + } + } + + &:active { + box-shadow: none; + padding: .75em 1.5em; + } + + &:hover { + border-bottom: 3px solid $active-dark-gray; + } + + .tab-icon { + display: block; + margin: 0 auto; + margin-bottom: 4px; + width: 24px; + } + &:hover { - opacity: 1; - border-color: $active-gray; - background-color: $ui-white; - color: $header-gray; - } -} - - -.tabs li.active { - opacity: 1; - border-bottom: 4px solid $ui-white; - - &:hover { - opacity: 1; - border-bottom: 4px solid $ui-white; background-color: $ui-white; color: $header-gray; } diff --git a/src/components/thumbnail/thumbnail.jsx b/src/components/thumbnail/thumbnail.jsx index b2bb234c5..ce96cf529 100644 --- a/src/components/thumbnail/thumbnail.jsx +++ b/src/components/thumbnail/thumbnail.jsx @@ -1,5 +1,5 @@ -var React = require('react'); var classNames = require('classnames'); +var React = require('react'); require('./thumbnail.scss'); @@ -13,11 +13,13 @@ var Thumbnail = React.createClass({ href: '#', title: 'Project', src: '', + avatar: '', type: 'project', showLoves: false, showFavorites: false, showRemixes: false, showViews: false, + showAvatar: false, linkTitle: true, alt: '' }; @@ -29,13 +31,8 @@ var Thumbnail = React.createClass({ this.props.className ); var extra = []; - if (this.props.creator) { - extra.push( - - ); - } + var info = []; + if (this.props.loves && this.props.showLoves) { extra.push(
); } - var imgElement,titleElement; + var imgElement,titleElement,avatarElement; if (this.props.linkTitle) { imgElement = {this.props.alt} @@ -87,11 +84,30 @@ var Thumbnail = React.createClass({ titleElement = this.props.title; } + info.push(titleElement); + + if (this.props.creator) { + info.push( + + ); + } + + if (this.props.avatar && this.props.showAvatar) { + avatarElement = + + {this.props.creator} + ; + } return (
{imgElement} -
- {titleElement} +
+ {avatarElement} +
+ {info} +
{extra}
diff --git a/src/components/thumbnail/thumbnail.scss b/src/components/thumbnail/thumbnail.scss index f119b78ec..f731449ab 100644 --- a/src/components/thumbnail/thumbnail.scss +++ b/src/components/thumbnail/thumbnail.scss @@ -90,9 +90,11 @@ $project-height: 108px; width: $project-width; - img { - width: $project-width; - height: $project-height; + .thumbnail-image { + img { + width: $project-width; + height: $project-height; + } } } diff --git a/src/l10n.json b/src/l10n.json index 10e8a8b46..6b9041260 100644 --- a/src/l10n.json +++ b/src/l10n.json @@ -16,6 +16,7 @@ "general.discuss": "Discuss", "general.dmca": "DMCA", "general.emailAddress": "Email Address", + "general.error": "Oops! Something went wrong", "general.explore": "Explore", "general.faq": "FAQ", "general.female": "Female", @@ -56,6 +57,7 @@ "general.privacyPolicy": "Privacy Policy", "general.projects": "Projects", "general.profile": "Profile", + "general.resourcesTitle": "Educator Resources", "general.scratchConference": "Scratch Conference", "general.scratchday": "Scratch Day", "general.scratchEd": "ScratchEd", @@ -153,5 +155,7 @@ "registration.waitForApprovalDescription": "You can log into your Scratch Account now, but the features specific to Teachers are not yet available. Your information is being reviewed. Please be patient, the approval process can take up to 24 hours. You will receive an email indicating your account has been upgraded once your account has been approved.", "registration.welcomeStepDescription": "You have successfully set up a Scratch account! You are now a member of the class:", "registration.welcomeStepPrompt": "To get started, click on the button below.", - "registration.welcomeStepTitle": "Hurray! Welcome to Scratch!" + "registration.welcomeStepTitle": "Hurray! Welcome to Scratch!", + + "thumbnail.by": "by" } diff --git a/src/lib/frameless.js b/src/lib/frameless.js new file mode 100644 index 000000000..9c63eb507 --- /dev/null +++ b/src/lib/frameless.js @@ -0,0 +1,9 @@ +/* This file contains breakpoints from _frameless.scss, to be used in MediaQuery elements. + * All units are in px, as per _frameless.scss and the MediaQuery default arguments. + */ + +module.exports = { + desktop: 942, + tablet: 640, + mobile: 480 +}; diff --git a/src/main.scss b/src/main.scss index 54dc7b16d..6ef3c37ae 100644 --- a/src/main.scss +++ b/src/main.scss @@ -164,7 +164,7 @@ dl { dt { font-weight: 700; } - + dd { margin: 0; } diff --git a/src/routes.json b/src/routes.json index 27f57fa5a..478b94c9e 100644 --- a/src/routes.json +++ b/src/routes.json @@ -47,32 +47,28 @@ "pattern": "^/conference/plan/?$", "routeAlias": "/conference(?!/201[4-5])", "view": "conference/plan/plan", - "title": "Plan Your Visit", - "viewportWidth": "device-width" + "title": "Plan Your Visit" }, { "name": "conference-expectations", "pattern": "^/conference/expect/?$", "routeAlias": "/conference(?!/201[4-5])", "view": "conference/expect/expect", - "title": "What to Expect", - "viewportWidth": "device-width" + "title": "What to Expect" }, { "name": "conference-schedule", "pattern": "^/conference/schedule/?$", "routeAlias": "/conference(?!/201[4-5])", "view": "conference/schedule/schedule", - "title": "Conference Schedule", - "viewportWidth": "device-width" + "title": "Conference Schedule" }, { "name": "conference-details", "pattern": "^/conference/:id/details/?$", "routeAlias": "/conference(?!/201[4-5])", "view": "conference/details/details", - "title": "Event Details", - "viewportWidth": "device-width" + "title": "Event Details" }, { "name": "developers", @@ -104,11 +100,10 @@ }, { "name": "teacherregistration", - "pattern": "^/educators/register$", + "pattern": "^/educators/register/?$", "routeAlias": "/educators(?:/(faq|register|waiting))?/?$", "view": "teacherregistration/teacherregistration", - "title": "Teacher Registration", - "viewportWidth": "device-width" + "title": "Teacher Registration" }, { "name": "teacherwaitingroom", diff --git a/src/template-config.js b/src/template-config.js index 297328d74..33cd26ca7 100644 --- a/src/template-config.js +++ b/src/template-config.js @@ -7,7 +7,7 @@ module.exports = { 'and animations.', // override if mobile-friendly - viewportWidth: 942, + viewportWidth: 'device-width', // Open graph og_image: 'https://scratch.mit.edu/images/scratch-og.png', diff --git a/src/template.html b/src/template.html index b97326cc4..9f905045a 100644 --- a/src/template.html +++ b/src/template.html @@ -6,7 +6,6 @@ - Scratch - {{title}} diff --git a/src/views/explore/explore.jsx b/src/views/explore/explore.jsx index 761d6292e..c1c0e00df 100644 --- a/src/views/explore/explore.jsx +++ b/src/views/explore/explore.jsx @@ -7,8 +7,11 @@ var render = require('../../lib/render.jsx'); var api = require('../../lib/api'); var Page = require('../../components/page/www/page.jsx'); -var Box = require('../../components/box/box.jsx'); var Tabs = require('../../components/tabs/tabs.jsx'); +var TitleBanner = require('../../components/title-banner/title-banner.jsx'); +var Button = require('../../components/forms/button.jsx'); +var Form = require('../../components/forms/form.jsx'); +var Select = require('../../components/forms/select.jsx'); var SubNavigation = require('../../components/subnavigation/subnavigation.jsx'); var Grid = require('../../components/grid/grid.jsx'); @@ -27,16 +30,19 @@ var Explore = injectIntl(React.createClass({ stories: 'stories' }; var typeOptions = ['projects','studios']; + var modeOptions = ['trending', 'popular', 'recent', '']; var pathname = window.location.pathname.toLowerCase(); if (pathname[pathname.length - 1] === '/') { pathname = pathname.substring(0, pathname.length - 1); } - var slash = pathname.lastIndexOf('/'); - var currentCategory = pathname.substring(slash + 1,pathname.length); - var typeStart = pathname.indexOf('explore/'); - var type = pathname.substring(typeStart + 8,slash); - if (Object.keys(categoryOptions).indexOf(currentCategory) === -1 || typeOptions.indexOf(type) === -1) { + var options = pathname.split('/'); + var type = options[2]; + var currentCategory = options[3]; + var currentMode = options.length > 4 ? options[4] : ''; + if (Object.keys(categoryOptions).indexOf(currentCategory) === -1 || + typeOptions.indexOf(type) === -1 || + modeOptions.indexOf(currentMode) === -1){ window.location = window.location.origin + '/explore/projects/all/'; } @@ -44,7 +50,9 @@ var Explore = injectIntl(React.createClass({ category: currentCategory, acceptableTabs: categoryOptions, acceptableTypes: typeOptions, + acceptableModes: modeOptions, itemType: type, + mode: currentMode, loadNumber: 16 }; }, @@ -59,12 +67,13 @@ var Explore = injectIntl(React.createClass({ }, getExploreMore: function () { var qText = '&q=' + this.props.acceptableTabs[this.props.category] || '*'; - + api({ uri: '/search/' + this.props.itemType + '?limit=' + this.props.loadNumber + '&offset=' + this.state.offset + '&language=' + this.props.intl.locale + + '&mode=' + (this.props.mode ? this.props.mode : 'trending') + qText }, function (err, body) { if (!err) { @@ -84,14 +93,20 @@ var Explore = injectIntl(React.createClass({ break; } } - window.location = window.location.origin + '/explore/' + newType + '/' + this.props.tab; + window.location = window.location.origin + '/explore/' + newType + '/' + this.props.tab + '/' + this.props.mode; + }, + changeSortMode: function (name, value) { + if (this.props.acceptableModes.indexOf(value) !== -1) { + window.location = window.location.origin + '/explore/' + + this.props.itemType + '/' + this.props.category + '/' + value; + } }, getBubble: function (type) { var classes = classNames({ active: (this.props.category === type) }); return ( - +
  • @@ -103,18 +118,33 @@ var Explore = injectIntl(React.createClass({ active: (this.props.itemType === type) }); return ( -
    +
  • + {this.props.itemType === type ? [ + + ] : [ + + ]}
  • ); }, render: function () { + return (
    - + +
    +

    Explore

    +
    +
    + + {this.getTab('projects')} + {this.getTab('studios')} + +
    {this.getBubble('all')} {this.getBubble('animations')} @@ -123,25 +153,29 @@ var Explore = injectIntl(React.createClass({ {this.getBubble('music')} {this.getBubble('stories')} - - {this.getTab('projects')} - {this.getTab('studios')} - -
    - - - - -
    - +
    + +
    +
    +
    + {this.getTab('projects')} {this.getTab('studios')}
    - - - - + +
    -
    ); diff --git a/src/views/search/search.scss b/src/views/search/search.scss index 49752fb82..0a9d4f583 100644 --- a/src/views/search/search.scss +++ b/src/views/search/search.scss @@ -4,33 +4,181 @@ $base-bg: $ui-white; #view { - .box { - display: block; - margin-right: auto; - margin-bottom: 20px; - margin-left: auto; + background-color: $ui-gray; + padding: 0; +} - .box-content { +.outer { + .title-banner { + &.masthead { + margin-bottom: 0; + background-color: darken($ui-blue, 10%); padding: 0; - } - } - #projectBox { - border-top: 2px solid; - border-color: $active-gray; + h1 { + text-align: center; + color: $ui-white; + font-size: 3rem; + } + + p { + margin: 0; + width: $cols6; + text-align: left; + color: $ui-white; + + a { + border-bottom: 1px solid $ui-white; + color: $ui-white; + } + } + } + } + + .search { + margin: 0 auto; + border-right: 0; + width: $cols6; + color: $type-white; + + .form { + margin: 0; + } + + .row { + .help-block { + display: none; + } + } + + .input, + .button { + display: inline-block; + margin-top: 5px; + outline: none; + border: 0; + background-color: $active-gray; + height: 14px; + + &[type=text] { + transition: .15s ease background-color; + padding: 0; + padding-right: 10px; + padding-left: 40px; + width: calc(100% - 50px); + height: 40px; + color: $type-white; + font-size: .85em; + + &::placeholder { + $placeholder-transparent: rgba(255, 255, 255, .75); + color: $placeholder-transparent; + } + + &:focus { + transition: .15s ease background-color; + background-color: $active-dark-gray; + } + + .ie9 & { + width: 70px; + } + } + } + + .btn-search { + position: absolute; + + box-shadow: none; + background-color: transparent; + background-image: url("/images/nav-search-glass.png"); + background-repeat: no-repeat; + background-position: center center; + background-size: 14px 14px; + + width: 40px; + height: 40px; + + &:hover { + box-shadow: none; + } + } + } + + .select { + select { + margin-bottom: 0; + color: $header-gray; + } + + .help-block { + display: none; + } + } + + .tab-background { + box-shadow: 0 0 1px $box-shadow-gray; background-color: $ui-white; - padding-bottom: 30px; width: 100%; } - .load button { - outline: None; - border: None; - background-color: $ui-white; - padding: 0; + #projectBox { + margin-top: 16px; + background-color: $ui-gray; + padding-bottom: 32px; + width: 100%; - li { - color: $header-gray; + .button { + display: block; + margin: 0 auto; + } + } +} + +//4 columns +@media only screen and (max-width: $mobile - 1) { + .outer { + .search { + width: $cols4; + + .btn-search { + left: 40px; + } + } + + .tabs { + width: $cols4; + } + + .sort-controls { + width: $cols4; + } + } +} + + +//6 columns +@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) { + .outer { + .tabs { + width: $cols6; + } + + .sort-controls { + width: $cols6; + } + } +} + +// 8 columns +@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) { + .outer { + .tabs { + width: $cols8; + } + + .sort-controls { + width: $cols8; } } } diff --git a/src/views/splash/l10n.json b/src/views/splash/l10n.json index 297f35426..f63a65bb8 100644 --- a/src/views/splash/l10n.json +++ b/src/views/splash/l10n.json @@ -26,7 +26,6 @@ "teacherbanner.greeting": "Hi", "teacherbanner.subgreeting": "Teacher Account", "teacherbanner.classesButton": "My Classes", - "teacherbanner.resourcesButton": "Educator Resources", "teacherbanner.faqButton": "Teacher Account FAQ", "welcome.welcomeToScratch": "Welcome to Scratch!", diff --git a/src/views/splash/splash.jsx b/src/views/splash/splash.jsx index 1745d37ba..919994d12 100644 --- a/src/views/splash/splash.jsx +++ b/src/views/splash/splash.jsx @@ -21,6 +21,9 @@ var Page = require('../../components/page/www/page.jsx'); var TeacherBanner = require('../../components/teacher-banner/teacher-banner.jsx'); var Welcome = require('../../components/welcome/welcome.jsx'); +var MediaQuery = require('react-responsive'); +var frameless = require('../../lib/frameless'); + require('./splash.scss'); var Splash = injectIntl(React.createClass({ @@ -186,16 +189,12 @@ var Splash = injectIntl(React.createClass({ var rows = [ , @@ -213,8 +212,8 @@ var Splash = injectIntl(React.createClass({ this.state.featuredGlobal.curator_top_projects[0].curator_name} moreTitle={formatMessage({id: 'general.learnMore', defaultMessage: 'Learn More'})} moreHref="/studios/386359/"> - + + ); } @@ -226,14 +225,12 @@ var Splash = injectIntl(React.createClass({ - + + ); } @@ -243,14 +240,9 @@ var Splash = injectIntl(React.createClass({ this.state.featuredGlobal.community_newest_projects.length > 0) { rows.push( - - + + ); } @@ -259,12 +251,9 @@ var Splash = injectIntl(React.createClass({ this.state.featuredCustom.custom_projects_by_following.length > 0) { rows.push( - - + ); @@ -273,12 +262,9 @@ var Splash = injectIntl(React.createClass({ this.state.featuredCustom.custom_projects_loved_by_following.length > 0) { rows.push( - - + ); @@ -288,31 +274,22 @@ var Splash = injectIntl(React.createClass({ this.state.featuredCustom.custom_projects_in_studios_following.length > 0) { rows.push( - - + ); } rows.push( - , -
    ] : [ - + + + ]) : [] } diff --git a/src/views/splash/splash.scss b/src/views/splash/splash.scss index 24c8e4521..841b2c73a 100644 --- a/src/views/splash/splash.scss +++ b/src/views/splash/splash.scss @@ -1,3 +1,5 @@ +@import "../../frameless"; + .splash { .splash-header { display: flex; @@ -24,7 +26,7 @@ .news { width: 40%; - + img { flex-shrink: 0; } @@ -38,4 +40,42 @@ .box { margin-bottom: 20px; } -} +} + +//4 columns +@media only screen and (max-width: $mobile - 1) { + .splash { + .splash-header { + flex-wrap: wrap; + justify-content: center; + + .box { + width: $cols4; + } + } + } +} + +//6 columns +@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) { + .splash { + .splash-header { + flex-wrap: wrap; + justify-content: center; + + .box { + width: $cols6; + } + } + } +} + +//6 columns +@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) { + .splash { + .splash-header { + margin: 0 auto; + width: $cols8; + } + } +} diff --git a/src/views/studentcompleteregistration/studentcompleteregistration.jsx b/src/views/studentcompleteregistration/studentcompleteregistration.jsx index 50df16443..e8d429d54 100644 --- a/src/views/studentcompleteregistration/studentcompleteregistration.jsx +++ b/src/views/studentcompleteregistration/studentcompleteregistration.jsx @@ -132,7 +132,8 @@ var StudentCompleteRegistration = intl.injectIntl(React.createClass({ {this.props.must_reset_password ? + waiting={this.state.waiting} + username={this.props.studentUsername} /> : [] } diff --git a/src/views/teachers/faq/faq.jsx b/src/views/teachers/faq/faq.jsx index c2c2528ab..a685166df 100644 --- a/src/views/teachers/faq/faq.jsx +++ b/src/views/teachers/faq/faq.jsx @@ -20,18 +20,22 @@ var TeacherFaq = injectIntl(React.createClass({
    -
    -
    -
    -
    -
    -
    + +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/src/views/teachers/faq/l10n.json b/src/views/teachers/faq/l10n.json index e1c58b6eb..bade92855 100644 --- a/src/views/teachers/faq/l10n.json +++ b/src/views/teachers/faq/l10n.json @@ -1,19 +1,21 @@ { "teacherfaq.title": "Scratch Teacher Account FAQ", "teacherfaq.teacherWhatTitle": "What are teacher accounts?", - "teacherfaq.teacherWhatBody": "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. Learn more about Teacher Accounts in this video.", - "teacherfaq.teacherQuestionsTitle": "What if I have any questions or comments on Teacher Accounts?", - "teacherfaq.teacherQuestionsBody": "If you have any questions or feedback on Teacher Accounts, you can message us at teacher-accounts@scratch.mit.edu.", - "teacherfaq.teacherGoogleTitle": "Are teacher accounts integrated with Google Classroom or any other classroom managment service?", - "teacherfaq.teacherGoogleBody": "Scratch Teacher accounts are not integrated with any classroom management services.", - "teacherfaq.teacherEdTitle": "Are ScratchEd & Scratch Teacher accounts the same thing?", - "teacherfaq.teacherEdBody": "ScratchEd accounts are not linked to Scratch Teacher accounts.", + "teacherfaq.teacherWhatBody": "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. Learn more about Teacher Accounts in the video below:", + "teacherfaq.teacherSignUpTitle": "How do I request a teacher account?", + "teacherfaq.teacherSignUpBody": "To request a Teacher Account, go to the teacher account request form.", "teacherfaq.teacherWaitTitle": "Why do I have to wait 24 hours for my account?", "teacherfaq.teacherWaitBody": "The Scratch Team uses this time to manually review account creation submissions to verify the account creator is an educator.", "teacherfaq.teacherPersonalTitle": "Why do you need to know my personal information during registration?", "teacherfaq.teacherPersonalBody": "We use this information to verify the account creator is an educator. We will not share this information with anyone else, and it will not be shared publicly on the site.", + "teacherfaq.teacherGoogleTitle": "Are teacher accounts integrated with Google Classroom or any other classroom managment service?", + "teacherfaq.teacherGoogleBody": "Scratch Teacher accounts are not integrated with any classroom management services.", + "teacherfaq.teacherEdTitle": "Are Scratch Teacher accounts linked to ScratchEd accounts?", + "teacherfaq.teacherEdBody": "No, Scratch Teacher accounts are not linked to ScratchEd accounts.", "teacherfaq.teacherMultipleTitle": "Can a class have multiple teachers?", "teacherfaq.teacherMultipleBody": "A class can only have one teacher account associated with it.", + "teacherfaq.teacherQuestionsTitle": "What if I have any questions or comments on Teacher Accounts?", + "teacherfaq.teacherQuestionsBody": "If you have any questions or feedback on Teacher Accounts, you can message us at teacher-accounts@scratch.mit.edu.", "teacherfaq.studentAccountsTitle": "Student Accounts", "teacherfaq.studentVerifyTitle": "Do I have to verify each of my students' emails?", @@ -21,7 +23,7 @@ "teacherfaq.studentEndTitle": "What happens when I \"end\" my class?", "teacherfaq.studentEndBody": "When you end a class, your class profile page will be hidden and your students will no longer be able to log in (but their projects and the class studios will still be visible on the site). You may re-open the class at any time. ", "teacherfaq.studentForgetTitle": "What happens if a student forgets their password?", - "teacherfaq.studentForgetBody": "You can manually reset a student password from within your Scratch Teacher Account. First, navigate to My Classes. From there, find the correct Class and click on the Students link. You can then reset the password at the student level using the Settings menu. ", + "teacherfaq.studentForgetBody": "You can manually reset a student password from within your Scratch Teacher Account. First, navigate to My Classes (either from the purple banner on the homepage or in the dropdown menu next to your user icon). From there, find the correct Class and click on the Students link. You can then reset the password at the student level using the Settings menu. ", "teacherfaq.studentUnsharedTitle": "Can I see unshared student projects?", "teacherfaq.studentUnsharedBody": "Teacher accounts can only access shared student projects.", "teacherfaq.studentDeleteTitle": "Can I delete student accounts?", diff --git a/src/views/teachers/landing/l10n.json b/src/views/teachers/landing/l10n.json index 8bd9dd442..1697f6756 100644 --- a/src/views/teachers/landing/l10n.json +++ b/src/views/teachers/landing/l10n.json @@ -8,7 +8,6 @@ "teacherlanding.generalUsageSettings": "Settings: schools, museums, libraries, community centers", "teacherlanding.generalUsageGradeLevels": "Grade Levels: elementary, middle, and high school (and some colleges too!)", "teacherlanding.generalUsageSubjectAreas": "Subject Areas: language arts, science, social studies, math, computer science, foreign languages, and the arts", - "teacherlanding.resourcesTitle": "Educator Resources", "teacherlanding.scratchEdTitle": "A Community for Educators", "teacherlanding.scratchEdDescription": "ScratchEd is an online community where Scratch educators share stories, exchange resources, ask questions, and find people. ScratchEd is developed and supported by the Harvard Graduate School of Education.", "teacherlanding.meetupTitle": "In-Person Gatherings", diff --git a/src/views/teachers/landing/landing.jsx b/src/views/teachers/landing/landing.jsx index ce32a564c..a367ad806 100644 --- a/src/views/teachers/landing/landing.jsx +++ b/src/views/teachers/landing/landing.jsx @@ -64,7 +64,7 @@ var Landing = injectIntl(React.createClass({
    -

    +

    @@ -82,19 +82,25 @@ var Landing = injectIntl(React.createClass({

    - resources icon + + resources icon +

    - tips window icon + + tips window icon +

    - creative computing icon + + creative computing icon +

    diff --git a/src/views/terms/terms.jsx b/src/views/terms/terms.jsx index fc52bd229..fc4937b69 100644 --- a/src/views/terms/terms.jsx +++ b/src/views/terms/terms.jsx @@ -85,7 +85,7 @@ var Terms = React.createClass({ (for example, in the event of a loss, theft, or unauthorized disclosure of your password), promptly change your password. If you cannot access your account to change your password, notify us at{' '} - . + help@scratch.mit.edu.

    diff --git a/static/svgs/tabs/projects-active.svg b/static/svgs/tabs/projects-active.svg new file mode 100644 index 000000000..3738946b1 --- /dev/null +++ b/static/svgs/tabs/projects-active.svg @@ -0,0 +1 @@ +Icons \ No newline at end of file diff --git a/static/svgs/tabs/projects-inactive.svg b/static/svgs/tabs/projects-inactive.svg new file mode 100644 index 000000000..c86555b0c --- /dev/null +++ b/static/svgs/tabs/projects-inactive.svg @@ -0,0 +1 @@ +Icons \ No newline at end of file diff --git a/static/svgs/tabs/studios-active.svg b/static/svgs/tabs/studios-active.svg new file mode 100644 index 000000000..71e9fac64 --- /dev/null +++ b/static/svgs/tabs/studios-active.svg @@ -0,0 +1 @@ +Icons \ No newline at end of file diff --git a/static/svgs/tabs/studios-inactive.svg b/static/svgs/tabs/studios-inactive.svg new file mode 100644 index 000000000..241faf900 --- /dev/null +++ b/static/svgs/tabs/studios-inactive.svg @@ -0,0 +1 @@ +Icons \ No newline at end of file