mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-26 17:16:11 -05:00
Resolve merge conflicts
This commit is contained in:
commit
a85db60610
32 changed files with 1321 additions and 48 deletions
|
@ -1,11 +1,15 @@
|
|||
{
|
||||
"rules": {
|
||||
"curly": [2, "multi-line"],
|
||||
"eol-last": [2],
|
||||
"indent": [2, 4],
|
||||
"quotes": [2, "single"],
|
||||
"linebreak-style": [2, "unix"],
|
||||
"max-len": [2, 120, 4],
|
||||
"no-trailing-spaces": [2, { "skipBlankLines": true }],
|
||||
"no-unused-vars": [2, {"args": "after-used", "varsIgnorePattern": "^_"}],
|
||||
"quotes": [2, "single"],
|
||||
"semi": [2, "always"],
|
||||
"space-before-function-paren": [2, "always"],
|
||||
"strict": [2, "never"]
|
||||
},
|
||||
"env": {
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -7,3 +7,8 @@ npm-*
|
|||
|
||||
# Build
|
||||
/build
|
||||
|
||||
# Elastic Beanstalk Files
|
||||
.elasticbeanstalk/*
|
||||
!.elasticbeanstalk/*.cfg.yml
|
||||
!.elasticbeanstalk/*.global.yml
|
||||
|
|
31
Makefile
31
Makefile
|
@ -22,6 +22,25 @@ webpack:
|
|||
|
||||
# ------------------------------------
|
||||
|
||||
watch:
|
||||
$(WATCH) "make clean && make static" ./static &
|
||||
$(WEBPACK) -d --watch &
|
||||
wait
|
||||
|
||||
stop:
|
||||
pkill -f "node $(WEBPACK) -d --watch"
|
||||
pkill -f "node $(WATCH) make clean && make static ./static"
|
||||
|
||||
start:
|
||||
$(NODE) ./server/index.js
|
||||
|
||||
# ------------------------------------
|
||||
|
||||
nginx_conf:
|
||||
node server/nginx.js
|
||||
|
||||
# ------------------------------------
|
||||
|
||||
test:
|
||||
@make lint
|
||||
|
||||
|
@ -35,14 +54,4 @@ lint:
|
|||
|
||||
# ------------------------------------
|
||||
|
||||
watch:
|
||||
$(WATCH) "make clean && make static" ./static &
|
||||
$(WEBPACK) -d --watch &
|
||||
wait
|
||||
|
||||
start:
|
||||
$(NODE) ./server/index.js
|
||||
|
||||
# ------------------------------------
|
||||
|
||||
.PHONY: build clean static webpack test lint watch start
|
||||
.PHONY: build clean static webpack watch stop start nginx_conf test lint
|
||||
|
|
13
package.json
13
package.json
|
@ -2,12 +2,13 @@
|
|||
"name": "www",
|
||||
"version": "1.0.0",
|
||||
"description": "Standalone WWW client for Scratch",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "make start",
|
||||
"test": "make test",
|
||||
"watch": "make watch",
|
||||
"build": "make build"
|
||||
"stop-watch": "make stop-watch",
|
||||
"build": "make build",
|
||||
"prestart": "make build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -28,16 +29,24 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer-loader": "2.1.0",
|
||||
"classnames": "2.1.3",
|
||||
"css-loader": "0.17.0",
|
||||
"eslint": "1.3.1",
|
||||
"eslint-plugin-react": "3.3.1",
|
||||
"file-loader": "0.8.4",
|
||||
"json-loader": "0.5.2",
|
||||
"jsx-loader": "0.13.2",
|
||||
"node-sass": "3.3.2",
|
||||
"react": "0.13.3",
|
||||
"react-modal": "0.3.0",
|
||||
"react-onclickoutside": "0.3.1",
|
||||
"react-slick": "0.7.0",
|
||||
"routes-to-nginx-conf": "0.0.4",
|
||||
"sass-loader": "2.0.1",
|
||||
"slick-carousel": "1.5.8",
|
||||
"style-loader": "0.12.3",
|
||||
"tape": "4.2.0",
|
||||
"url-loader": "0.5.6",
|
||||
"watch": "0.16.0",
|
||||
"webpack": "1.12.0",
|
||||
"xhr": "2.0.4"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var compression = require('compression');
|
||||
var express = require('express');
|
||||
var path = require('path');
|
||||
var _path = require('path');
|
||||
|
||||
var handler = require('./handler');
|
||||
var log = require('./log');
|
||||
|
@ -11,15 +11,15 @@ var app = express();
|
|||
app.disable('x-powered-by');
|
||||
app.use(log());
|
||||
app.use(compression());
|
||||
app.use(express.static(path.resolve(__dirname, '../build'), {
|
||||
lastModified: true,
|
||||
maxAge: '1y'
|
||||
}));
|
||||
|
||||
// Bind routes
|
||||
for (var item in routes) {
|
||||
var route = routes[item];
|
||||
app.get(route.pattern, handler(route));
|
||||
if ( route.static ) {
|
||||
app.use( express.static( eval( route.resolve ), route.attributes ) );
|
||||
} else {
|
||||
app.get(route.pattern, handler(route));
|
||||
}
|
||||
}
|
||||
|
||||
// Start listening
|
||||
|
|
5
server/nginx.js
Normal file
5
server/nginx.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
var routes = require('./routes.json');
|
||||
var nginx_conf = require('routes-to-nginx-conf');
|
||||
|
||||
nginx_conf.generate_nginx_conf( routes, function ( v ) { process.stdout.write(v); } );
|
||||
|
|
@ -1,15 +1,24 @@
|
|||
[
|
||||
{
|
||||
"pattern": "/",
|
||||
"view": "splash"
|
||||
"view": "splash",
|
||||
"static": false
|
||||
},
|
||||
{
|
||||
"pattern": "/about",
|
||||
"view": "about",
|
||||
"title": "About"
|
||||
"title": "About",
|
||||
"static": false
|
||||
},
|
||||
{
|
||||
"pattern": "/components",
|
||||
"view": "components"
|
||||
"view": "components",
|
||||
"static": false
|
||||
},
|
||||
{
|
||||
"static": true,
|
||||
"resolve": "_path.resolve(__dirname, '../build')",
|
||||
"attributes": { "lastModified": true, "maxAge": "1y" },
|
||||
"_todo": " TODO: Define a specification for how each entry is used/expected to look like, given the nginx conf generator's needs and stand-alone run-time needs. An outline of this so far: static requires resolve/attributes but could use pattern too. ..."
|
||||
}
|
||||
]
|
||||
|
|
49
src/components/carousel/carousel.json
Normal file
49
src/components/carousel/carousel.json
Normal file
|
@ -0,0 +1,49 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
}
|
||||
]
|
42
src/components/carousel/carousel.jsx
Normal file
42
src/components/carousel/carousel.jsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
var React = require('react');
|
||||
var Slider = require('react-slick');
|
||||
var Thumbnail = require('../thumbnail/thumbnail.jsx');
|
||||
|
||||
require('slick-carousel/slick/slick.scss');
|
||||
require('slick-carousel/slick/slick-theme.scss');
|
||||
require('./carousel.scss');
|
||||
|
||||
module.exports = React.createClass({
|
||||
propTypes: {
|
||||
items: React.PropTypes.array
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
items: require('./carousel.json'),
|
||||
settings: {
|
||||
arrows: true,
|
||||
dots: false,
|
||||
infinite: false,
|
||||
lazyLoad: true,
|
||||
slidesToShow: 5,
|
||||
slidesToScroll: 5,
|
||||
variableWidth: true
|
||||
}
|
||||
};
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Slider className={'carousel ' + this.props.className} {... this.props.settings}>
|
||||
{this.props.items.map(function (item) {
|
||||
return (
|
||||
<Thumbnail key={item.id}
|
||||
href={item.href}
|
||||
title={item.title}
|
||||
src={item.thumbnailUrl}
|
||||
extra={item.creator ? 'by ' + item.creator:null} />
|
||||
);
|
||||
})}
|
||||
</Slider>
|
||||
);
|
||||
}
|
||||
});
|
47
src/components/carousel/carousel.scss
Normal file
47
src/components/carousel/carousel.scss
Normal file
|
@ -0,0 +1,47 @@
|
|||
.carousel {
|
||||
$icon-size: 40px;
|
||||
$button-offset: $icon-size + 5px;
|
||||
$box-content-offset: 20px;
|
||||
|
||||
padding: 0 $button-offset;
|
||||
|
||||
.box-content & {
|
||||
padding: 0 $button-offset - 20px;
|
||||
}
|
||||
|
||||
.slick-next, .slick-prev {
|
||||
width: $icon-size;
|
||||
height: $icon-size;
|
||||
margin-top: -$icon-size/2;
|
||||
|
||||
&:before {
|
||||
font-size: $icon-size;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
&.slick-disabled:before{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.slick-prev {
|
||||
left: 0;
|
||||
|
||||
.box-content & {
|
||||
left: -$box-content-offset;
|
||||
}
|
||||
}
|
||||
|
||||
.slick-next {
|
||||
right: 0;
|
||||
|
||||
.box-content & {
|
||||
right: -$box-content-offset;
|
||||
}
|
||||
}
|
||||
|
||||
.slick-slide {
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
}
|
93
src/components/intro/intro.jsx
Normal file
93
src/components/intro/intro.jsx
Normal file
|
@ -0,0 +1,93 @@
|
|||
var React = require('react');
|
||||
var Modal = require('../modal/modal.jsx');
|
||||
|
||||
require('./intro.scss');
|
||||
|
||||
Modal.setAppElement(document.getElementById('view'));
|
||||
|
||||
module.exports = React.createClass({
|
||||
propTypes: {
|
||||
projectCount: React.PropTypes.number
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
projectCount: 10569070
|
||||
};
|
||||
},
|
||||
getInitialState: function () {
|
||||
return {
|
||||
videoOpen: false
|
||||
};
|
||||
},
|
||||
showVideo: function () {
|
||||
this.setState({videoOpen: true});
|
||||
},
|
||||
closeVideo: function () {
|
||||
this.setState({videoOpen: false});
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div className="intro">
|
||||
<div className="content">
|
||||
<h1>
|
||||
Create stories, games, and animations<br />
|
||||
Share with others around the world
|
||||
</h1>
|
||||
<div className="sprites">
|
||||
<a className="sprite sprite-1" href="/projects/editor/?tip_bar=getStarted">
|
||||
<img
|
||||
className="costume costume-1"
|
||||
src="//cdn.scratch.mit.edu/scratchr2/static/images/cat-a.png" />
|
||||
<img
|
||||
className="costume costume-2"
|
||||
src="//cdn.scratch.mit.edu/scratchr2/static/images/cat-b.png" />
|
||||
<div className="circle"></div>
|
||||
<div className="text">TRY IT OUT</div>
|
||||
</a>
|
||||
<a className="sprite sprite-2" href="/starter_projects/">
|
||||
<img
|
||||
className="costume costume-1"
|
||||
src="//cdn.scratch.mit.edu/scratchr2/static/images/tera-a.png" />
|
||||
<img
|
||||
className="costume costume-2"
|
||||
src="//cdn.scratch.mit.edu/scratchr2/static/images/tera-b.png" />
|
||||
<div className="circle"></div>
|
||||
<div className="text">SEE EXAMPLES</div>
|
||||
</a>
|
||||
<a className="sprite sprite-3" href="#">
|
||||
<img
|
||||
className="costume costume-1"
|
||||
src="//cdn.scratch.mit.edu/scratchr2/static/images/gobo-a.png" />
|
||||
<img
|
||||
className="costume costume-2"
|
||||
src="//cdn.scratch.mit.edu/scratchr2/static/images/gobo-b.png" />
|
||||
<div className="circle"></div>
|
||||
<div className="text">JOIN SCRATCH</div>
|
||||
<div className="text subtext">( it’s free )</div>
|
||||
</a>
|
||||
</div>
|
||||
<div className="description">
|
||||
A creative learning community with
|
||||
<span className="project-count"> {this.props.projectCount.toLocaleString()} </span>
|
||||
projects shared
|
||||
</div>
|
||||
<div className="links">
|
||||
<a href="/about/">ABOUT SCRATCH</a>
|
||||
<a href="/educators/">FOR EDUCATORS</a>
|
||||
<a className="last" href="/parents/">FOR PARENTS</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="video">
|
||||
<div className="play-button" onClick={this.showVideo}></div>
|
||||
<img src="//cdn.scratch.mit.edu/scratchr2/static/images/hp-video-screenshot.png" />
|
||||
</div>
|
||||
<Modal
|
||||
className="video-modal"
|
||||
isOpen={this.state.videoOpen}
|
||||
onRequestClose={this.closeVideo}>
|
||||
<iframe src="//player.vimeo.com/video/65583694?title=0&byline=0&portrait=0" />
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
202
src/components/intro/intro.scss
Normal file
202
src/components/intro/intro.scss
Normal file
|
@ -0,0 +1,202 @@
|
|||
.intro {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
align-content: flex-start;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.content {
|
||||
display: inline-block;
|
||||
width: calc(66% - 20px);
|
||||
|
||||
h1 {
|
||||
color: #F9A739;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.sprites {
|
||||
position: relative;
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
&:after {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sprite {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 193px;
|
||||
height: 136px;
|
||||
overflow: hidden;
|
||||
|
||||
.costume, .circle, .text {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.costume {
|
||||
z-index: 2;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.costume-2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .costume-1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .costume-2 {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.circle {
|
||||
z-index: 0;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
width: 112px;
|
||||
height: 112px;
|
||||
box-shadow: 0px 0px 5px #fff;
|
||||
top: 15px;
|
||||
left: 43px;
|
||||
}
|
||||
|
||||
$text-bg-color: #F1F3F4;
|
||||
.text {
|
||||
z-index: 1;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
left: 35px;
|
||||
padding-left: 40px;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
background-color: $text-bg-color;
|
||||
border: 2px solid $text-bg-color;
|
||||
}
|
||||
|
||||
.subtext {
|
||||
background-color: transparent;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
text-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
$sprite-1-bgcolor: #9C0;
|
||||
$sprite-2-bgcolor: #C2479D;
|
||||
$sprite-3-bgcolor: #199ED7;
|
||||
&.sprite-1 .circle { background-color: $sprite-1-bgcolor; }
|
||||
&.sprite-2 .circle { background-color: $sprite-2-bgcolor; }
|
||||
&.sprite-3 .circle { background-color: $sprite-3-bgcolor; }
|
||||
&:hover.sprite-1 .circle { box-shadow: 0 0 10px 2px $sprite-1-bgcolor; }
|
||||
&:hover.sprite-2 .circle { box-shadow: 0 0 10px 2px $sprite-2-bgcolor; }
|
||||
&:hover.sprite-3 .circle { box-shadow: 0 0 10px 2px $sprite-3-bgcolor; }
|
||||
&.sprite-1 .text { color: $sprite-1-bgcolor; top: 60px; left: 50px; }
|
||||
&.sprite-2 .text { color: $sprite-2-bgcolor; top: 77px; left: 50px; }
|
||||
&.sprite-3 .text { color: $sprite-3-bgcolor; top: 37px; left: 45px; }
|
||||
&.sprite-3 .subtext {
|
||||
top: 63px;
|
||||
left: 60px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 17px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.project-count {
|
||||
color: hsl(318, 50%, 52%);
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.links {
|
||||
font-size: 12px;
|
||||
margin-top: 20px;
|
||||
|
||||
a {
|
||||
border-right: 1px solid #000;
|
||||
padding: 0 5px;
|
||||
|
||||
&:last-child { border-right: 0; }
|
||||
&:first-child { padding-left: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
.video {
|
||||
display: inline-block;
|
||||
height: 208px;
|
||||
width: 34%;
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 5px;
|
||||
background-color: #f7f7f7;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 3px;
|
||||
}
|
||||
|
||||
.play-button {
|
||||
border-radius: 20px;
|
||||
display: block;
|
||||
width: 70px;
|
||||
height: 50px;
|
||||
left: calc(50% - 35px);
|
||||
top: calc(50% - 25px);
|
||||
background-color: #666;
|
||||
border: 5px solid #ccc;
|
||||
opacity: 0.8;
|
||||
|
||||
&, &:after {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:after {
|
||||
left: 28px;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
pointer-events: none;
|
||||
border-color: rgba(255, 255, 255, 0);
|
||||
border-left-color: #fff;
|
||||
border-width: 18px;
|
||||
top: 37px;
|
||||
margin-top: -30px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.video-modal {
|
||||
$video-width: 570px;
|
||||
$video-height: 357px;
|
||||
$padding: 15px;
|
||||
width: $video-width;
|
||||
height: $video-height;
|
||||
padding: $padding;
|
||||
top: 50%;
|
||||
bottom: auto;
|
||||
left: 50%;
|
||||
right: auto;
|
||||
margin-left: -($video-width + $padding * 2)/2;
|
||||
margin-top: -($video-height + $padding * 2)/2;
|
||||
|
||||
iframe {
|
||||
width: $video-width;
|
||||
height: $video-height;
|
||||
border: 0;
|
||||
}
|
||||
}
|
27
src/components/login/login.jsx
Normal file
27
src/components/login/login.jsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
var React = require('react');
|
||||
|
||||
require('./login.scss');
|
||||
|
||||
module.exports = React.createClass({
|
||||
propTypes: {
|
||||
onLogIn: React.PropTypes.func
|
||||
},
|
||||
handleSubmit: function (event) {
|
||||
event.preventDefault();
|
||||
this.props.onLogIn();
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div className="login">
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<label htmlFor="username">Username</label>
|
||||
<input type="text" name="username" maxLength="30" />
|
||||
<label htmlFor="password">Password</label>
|
||||
<input type="password" name="password" />
|
||||
<button className="submit-button" type="submit">Sign in</button>
|
||||
<a href="/accounts/password_reset/">Forgot password?</a>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
7
src/components/login/login.scss
Normal file
7
src/components/login/login.scss
Normal file
|
@ -0,0 +1,7 @@
|
|||
.login {
|
||||
padding: 14px 9px;
|
||||
|
||||
.submit-button {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
22
src/components/modal/modal.jsx
Normal file
22
src/components/modal/modal.jsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
var React = require('react');
|
||||
var Modal = require('react-modal');
|
||||
|
||||
require('./modal.scss');
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
statics: {
|
||||
setAppElement: Modal.setAppElement
|
||||
},
|
||||
requestClose: function () {
|
||||
return this.refs.modal.portal.requestClose();
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Modal ref="modal" {... this.props}>
|
||||
<div className="modal-close" onClick={this.requestClose}></div>
|
||||
{this.props.children}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
});
|
50
src/components/modal/modal.scss
Normal file
50
src/components/modal/modal.scss
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* Copied from the un-styleable react-modal */
|
||||
|
||||
.ReactModal__Overlay {
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
z-index: 100;
|
||||
}
|
||||
.ReactModal__Content {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
right: 40px;
|
||||
bottom: 40px;
|
||||
background: #fff;
|
||||
overflow: visible;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
padding: 20px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.ReactModal__Content {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
$modal-close-size: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border-radius: $modal-close-size/2;
|
||||
border: 2px solid #ddd;
|
||||
background-color: #666;
|
||||
color: #fff;
|
||||
width: $modal-close-size;
|
||||
height: $modal-close-size;
|
||||
margin-top: -$modal-close-size/2;
|
||||
margin-right: -$modal-close-size/2;
|
||||
text-align: center;
|
||||
line-height: $modal-close-size;
|
||||
font-size: $modal-close-size;
|
||||
cursor: pointer;
|
||||
&:before {
|
||||
content: "x";
|
||||
}
|
||||
}
|
3
src/components/navigation/_colors.scss
Normal file
3
src/components/navigation/_colors.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
$base-background-color: #0f8bc0;
|
||||
$active-background-color: rgb(1, 96, 135);
|
||||
$border-color: rgb(20, 154, 203);
|
37
src/components/navigation/dropdown.jsx
Normal file
37
src/components/navigation/dropdown.jsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
var React = require('react');
|
||||
var classNames = require('classnames');
|
||||
|
||||
require('./dropdown.scss');
|
||||
|
||||
module.exports = React.createClass({
|
||||
mixins: [
|
||||
require('react-onclickoutside')
|
||||
],
|
||||
propTypes: {
|
||||
onRequestClose: React.PropTypes.func,
|
||||
isOpen: React.PropTypes.bool
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
as: 'div',
|
||||
isOpen: false
|
||||
};
|
||||
},
|
||||
handleClickOutside: function () {
|
||||
if (this.props.isOpen) {
|
||||
this.props.onRequestClose();
|
||||
}
|
||||
},
|
||||
render: function () {
|
||||
var classes = classNames(
|
||||
'dropdown',
|
||||
this.props.className,
|
||||
{open: this.props.isOpen}
|
||||
);
|
||||
return (
|
||||
<this.props.as className={classes}>
|
||||
{this.props.children}
|
||||
</this.props.as>
|
||||
);
|
||||
}
|
||||
});
|
74
src/components/navigation/dropdown.scss
Normal file
74
src/components/navigation/dropdown.scss
Normal file
|
@ -0,0 +1,74 @@
|
|||
@import 'colors';
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
min-width: 160px;
|
||||
max-width: 220px;
|
||||
background-color: $base-background-color;
|
||||
overflow: hidden;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
box-shadow: inset 0 1px 1px rgba(100,100,100,.25),0 1px 1px rgba(0,0,0,.25);
|
||||
color: white;
|
||||
font-weight: normal;
|
||||
font-size: 0.8125rem;
|
||||
|
||||
display: none;
|
||||
&.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
input {
|
||||
// 100% minus border and padding
|
||||
width: calc(100% - 2px - 8px);
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
> li {
|
||||
display: block;
|
||||
line-height: 30px;
|
||||
|
||||
&.divider {
|
||||
border-top: 1px solid #149acb;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 0 10px;
|
||||
|
||||
&:hover {
|
||||
background-color: $active-background-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.with-arrow {
|
||||
$arrow-border-width: 11px;
|
||||
overflow: visible;
|
||||
margin-top: $arrow-border-width;
|
||||
border-radius: 4px;
|
||||
&:before {
|
||||
position: absolute;
|
||||
display: block;
|
||||
right: 10%;
|
||||
top: -$arrow-border-width;
|
||||
left: auto;
|
||||
border-color: transparent;
|
||||
border-bottom-color: $base-background-color;
|
||||
border-style: solid;
|
||||
border-width: 0 $arrow-border-width $arrow-border-width $arrow-border-width;
|
||||
content: " ";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,48 @@
|
|||
var React = require('react');
|
||||
var classNames = require('classnames');
|
||||
var Login = require('../login/login.jsx');
|
||||
var Dropdown = require('./dropdown.jsx');
|
||||
|
||||
require('./navigation.scss');
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState: function () {
|
||||
return {
|
||||
'loginOpen': false,
|
||||
'loggedIn': false,
|
||||
'loggedInUser': {
|
||||
'username': 'raimondious',
|
||||
'thumbnail': '//cdn2.scratch.mit.edu/get_image/user/2584924_32x32.png'
|
||||
},
|
||||
'accountNavOpen': false
|
||||
};
|
||||
},
|
||||
handleLoginClick: function (e) {
|
||||
e.preventDefault();
|
||||
this.setState({'loginOpen': true});
|
||||
},
|
||||
closeLogin: function () {
|
||||
this.setState({'loginOpen': false});
|
||||
},
|
||||
handleLogIn: function () {
|
||||
this.setState({'loggedIn': true});
|
||||
},
|
||||
handleLogOut: function () {
|
||||
this.setState({'loggedIn': false});
|
||||
},
|
||||
handleClickAccountNav: function () {
|
||||
this.setState({'accountNavOpen': true});
|
||||
},
|
||||
closeAccountNav: function () {
|
||||
this.setState({'accountNavOpen': false});
|
||||
},
|
||||
render: function () {
|
||||
var classes = classNames({
|
||||
'inner': true,
|
||||
'logged-in': this.state.loggedIn
|
||||
});
|
||||
return (
|
||||
<div className="inner">
|
||||
<div className={classes}>
|
||||
<ul>
|
||||
<li className="logo"><a href="/"></a></li>
|
||||
|
||||
|
@ -23,9 +60,38 @@ module.exports = React.createClass({
|
|||
<input type="hidden" name="sort_by" value="datetime_shared" />
|
||||
</form>
|
||||
</li>
|
||||
|
||||
<li className="link right"><a href="/join">Join Scratch</a></li>
|
||||
<li className="link right"><a href="">Sign In</a></li>
|
||||
{this.state.loggedIn ? [
|
||||
<li className="link right messages"><a href="/messages/" title="Messages">Messages</a></li>,
|
||||
<li className="link right mystuff"><a href="/mystuff/" title="My Stuff">My Stuff</a></li>,
|
||||
<li className="link right account-nav">
|
||||
<a href="#" onClick={this.handleClickAccountNav}>
|
||||
<img src={this.state.loggedInUser.thumbnail} />
|
||||
{this.state.loggedInUser.username}
|
||||
</a>
|
||||
<Dropdown
|
||||
as="ul"
|
||||
isOpen={this.state.accountNavOpen}
|
||||
onRequestClose={this.closeAccountNav}>
|
||||
<li><a href="/users/raimondious/">Profile</a></li>
|
||||
<li><a href="/mystuff/">My Stuff</a></li>
|
||||
<li><a href="/accounts/settings/">Account settings</a></li>
|
||||
<li className="divider">
|
||||
<a href="#" onClick={this.handleLogOut}>Sign out</a>
|
||||
</li>
|
||||
</Dropdown>
|
||||
</li>
|
||||
] : [
|
||||
<li className="link right join"><a href="/join">Join Scratch</a></li>,
|
||||
<li className="link right">
|
||||
<a href="#" onClick={this.handleLoginClick}>Sign In</a>
|
||||
<Dropdown
|
||||
className="login-dropdown with-arrow"
|
||||
isOpen={this.state.loginOpen}
|
||||
onRequestClose={this.closeLogin}>
|
||||
<Login onLogIn={this.handleLogIn} />
|
||||
</Dropdown>
|
||||
</li>
|
||||
]}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
@import 'colors';
|
||||
|
||||
#navigation {
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: #0f8bc0;
|
||||
background-color: $base-background-color;
|
||||
|
||||
/* NOTE: Height should match offset settings in main.scss file */
|
||||
height: 35px;
|
||||
|
||||
ul {
|
||||
.inner > ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
|
@ -20,12 +23,13 @@
|
|||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
> li {
|
||||
display: inline-block;
|
||||
align-self: flex-start;
|
||||
float: left;
|
||||
height: 100%;
|
||||
border-left: 1px solid rgb(20, 154, 203);
|
||||
border-left: 1px solid $border-color;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
@ -48,7 +52,7 @@
|
|||
}
|
||||
|
||||
.link {
|
||||
a {
|
||||
> a {
|
||||
display: block;
|
||||
height: 28px;
|
||||
padding: 7px 15px 0 15px;
|
||||
|
@ -59,8 +63,8 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background-color: rgb(1, 96, 135);
|
||||
> a:hover {
|
||||
background-color: $active-background-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +78,7 @@
|
|||
|
||||
input {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
height: 14px;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
@ -85,7 +89,7 @@
|
|||
height: 22px;
|
||||
|
||||
background-color: white;
|
||||
background-image: url(/images/nav-search-glass.png);
|
||||
background-image: url('/images/nav-search-glass.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
border-right: 1px solid #efefef;
|
||||
|
@ -110,13 +114,77 @@
|
|||
margin-left: auto;
|
||||
font-weight: bold;
|
||||
|
||||
a:hover {
|
||||
background-color: #f79231;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right: 1px solid rgb(20, 154, 203);
|
||||
}
|
||||
}
|
||||
|
||||
.join > a:hover {
|
||||
background-color: #f79231;
|
||||
}
|
||||
|
||||
.messages, .mystuff {
|
||||
> a {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
text-indent: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.messages {
|
||||
> a {
|
||||
background-image: url('/images/nav-notifications.png');
|
||||
width: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.mystuff {
|
||||
> a {
|
||||
background-image: url('/images/mystuff.png');
|
||||
width: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-dropdown {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.account-nav {
|
||||
> a {
|
||||
font-weight: normal;
|
||||
font-size: 0.8125rem;
|
||||
|
||||
img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&:after {
|
||||
$caret-border-width: 4px;
|
||||
margin-left: $caret-border-width;
|
||||
border: $caret-border-width solid transparent;
|
||||
border-bottom-width: 0;
|
||||
border-top-color: white;
|
||||
content: " ";
|
||||
opacity: 0.5;
|
||||
vertical-align: middle;
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ module.exports = React.createClass({
|
|||
},
|
||||
render: function () {
|
||||
return (
|
||||
<Box
|
||||
className="news"
|
||||
title="Scratch News"
|
||||
<Box
|
||||
className="news"
|
||||
title="Scratch News"
|
||||
moreTitle="View All"
|
||||
moreHref="/news">
|
||||
|
||||
|
|
28
src/components/thumbnail/thumbnail.jsx
Normal file
28
src/components/thumbnail/thumbnail.jsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
var React = require('react');
|
||||
|
||||
require('./thumbnail.scss');
|
||||
|
||||
module.exports = React.createClass({
|
||||
propTypes: {
|
||||
src: React.PropTypes.string
|
||||
},
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
href: '/projects/1000/',
|
||||
title: 'Example Project',
|
||||
src: 'http://www.lorempixel.com/144/108/',
|
||||
extra: 'by raimondious'
|
||||
};
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div className={'thumbnail ' + this.props.className}>
|
||||
<a className="thumbnail-image" href={this.props.href}>
|
||||
<img src={this.props.src} />
|
||||
</a>
|
||||
<span className="thumbnail-title"><a href={this.props.href}>{this.props.title}</a></span>
|
||||
<span className="thumbnail-extra">{this.props.extra}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
33
src/components/thumbnail/thumbnail.scss
Normal file
33
src/components/thumbnail/thumbnail.scss
Normal file
|
@ -0,0 +1,33 @@
|
|||
.thumbnail {
|
||||
.thumbnail-image,
|
||||
.thumbnail-title,
|
||||
.thumbnail-extra {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.thumbnail-image img {
|
||||
margin-bottom: 2px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.thumbnail-title,
|
||||
.thumbnail-extra {
|
||||
line-height: normal;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.thumbnail-title {
|
||||
margin-bottom: 1px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-weight: 800;
|
||||
font-size: .9230em;
|
||||
}
|
||||
|
||||
.thumbnail-extra {
|
||||
font-size: .8462em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,11 @@ h1, h2, h3, h4 {
|
|||
font-weight: 700;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.625rem;
|
||||
line-height: 2.125rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.0rem;
|
||||
line-height: 1.1rem;
|
||||
|
@ -48,3 +53,38 @@ a:hover {
|
|||
/* NOTE: Margin should match height in navigation.scss */
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
input {
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
margin-bottom: 9px;
|
||||
font-size: 13px;
|
||||
color: #555;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
|
||||
transition: border linear .2s,box-shadow linear .2s;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
line-height: 30px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 5px;
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
|
||||
transition: all .25s ease-in-out;
|
||||
height: 32px;
|
||||
text-shadow: 0 1px #fff;
|
||||
font-weight: normal;
|
||||
color: #666;
|
||||
border-color: #999;
|
||||
display: inline-block;
|
||||
background: linear-gradient(to bottom, #fff, #ccc)
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-image: linear-gradient(#e6e6e6,#e6e6e6);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var React = require('react');
|
||||
|
||||
var Box = require('../../components/box/box.jsx');
|
||||
var Carousel = require('../../components/carousel/carousel.jsx');
|
||||
|
||||
require('./components.scss');
|
||||
|
||||
|
@ -9,13 +10,19 @@ var View = React.createClass({
|
|||
return (
|
||||
<div className="inner">
|
||||
<h1>Box Component</h1>
|
||||
<Box
|
||||
<Box
|
||||
title="Some Title"
|
||||
more="Cat Gifs"
|
||||
moreUrl="http://www.catgifpage.com/">
|
||||
<h4>Things go in here</h4>
|
||||
<p>Lorem ipsum dolor sit amet.</p>
|
||||
</Box>
|
||||
<h1>Carousel Component</h1>
|
||||
<Carousel />
|
||||
<Box
|
||||
title="Carousel component in a box!">
|
||||
<Carousel />
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
314
src/views/splash/featured.json
Normal file
314
src/views/splash/featured.json
Normal file
|
@ -0,0 +1,314 @@
|
|||
[
|
||||
{
|
||||
"title": "Featured Projects",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Featured Studios",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "studio",
|
||||
"title": "Example Studio",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/170/100/",
|
||||
"href": "/studios/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "studio",
|
||||
"title": "Example Studio",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/170/100/",
|
||||
"href": "/studios/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "studio",
|
||||
"title": "Example Studio",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/170/100/",
|
||||
"href": "/studios/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "studio",
|
||||
"title": "Example Studio",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/170/100/",
|
||||
"href": "/studios/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "studio",
|
||||
"title": "Example Studio",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/170/100/",
|
||||
"href": "/studios/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "studio",
|
||||
"title": "Example Studio",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/170/100/",
|
||||
"href": "/studios/1000/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Projects Curated by raimondious",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Scratch Design Studio - \"Custom Block Madness!\"",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "What the Community is Remixing",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "What the Community is Loving",
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "project",
|
||||
"title": "Example Project",
|
||||
"thumbnailUrl": "http://www.lorempixel.com/144/108/",
|
||||
"creator": "raimondious",
|
||||
"href": "/projects/1000/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -4,6 +4,9 @@ var Api = require('../../mixins/api.jsx');
|
|||
var Session = require('../../mixins/session.jsx');
|
||||
|
||||
var Activity = require('../../components/activity/activity.jsx');
|
||||
var Box = require('../../components/box/box.jsx');
|
||||
var Carousel = require('../../components/carousel/carousel.jsx');
|
||||
var Intro = require('../../components/intro/intro.jsx');
|
||||
var News = require('../../components/news/news.jsx');
|
||||
|
||||
require('./splash.scss');
|
||||
|
@ -15,9 +18,10 @@ var View = React.createClass({
|
|||
],
|
||||
getInitialState: function () {
|
||||
return {
|
||||
projectCount: 10569070,
|
||||
activity: [],
|
||||
news: [],
|
||||
featured: []
|
||||
featured: require('./featured.json')
|
||||
};
|
||||
},
|
||||
componentDidMount: function () {
|
||||
|
@ -28,11 +32,20 @@ var View = React.createClass({
|
|||
render: function () {
|
||||
return (
|
||||
<div className="inner">
|
||||
<Intro projectCount={this.state.projectCount} />
|
||||
<div className="splash-header">
|
||||
<Activity />
|
||||
<News />
|
||||
</div>
|
||||
<div className="featured"></div>
|
||||
{this.state.featured.map(function (set) {
|
||||
return (
|
||||
<Box
|
||||
className="featured"
|
||||
title={set.title}>
|
||||
<Carousel items={set.items} />
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,4 +15,8 @@
|
|||
width: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
|
BIN
static/images/mystuff.png
Normal file
BIN
static/images/mystuff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 431 B |
BIN
static/images/nav-notifications.png
Normal file
BIN
static/images/nav-notifications.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -7,7 +7,9 @@ var entry = {
|
|||
main: './src/main.jsx'
|
||||
};
|
||||
routes.forEach(function (route) {
|
||||
entry[route.view] = './src/views/' + route.view + '/' + route.view + '.jsx';
|
||||
if ( ! route.static ) {
|
||||
entry[route.view] = './src/views/' + route.view + '/' + route.view + '.jsx';
|
||||
}
|
||||
});
|
||||
|
||||
// Config
|
||||
|
@ -36,7 +38,11 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
loader: 'style!css!sass!autoprefixer-loader?browsers=last 3 versions'
|
||||
loader: 'style!css!autoprefixer-loader?browsers=last 3 versions!sass'
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif|eot|svg|ttf|woff)$/,
|
||||
loader: 'url-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue