Resolve merge conflicts

This commit is contained in:
Andrew Sliwinski 2015-09-21 10:44:58 -04:00
commit a85db60610
32 changed files with 1321 additions and 48 deletions

View file

@ -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
View file

@ -7,3 +7,8 @@ npm-*
# Build
/build
# Elastic Beanstalk Files
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml

View file

@ -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

View file

@ -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"

View file

@ -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
View 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); } );

View file

@ -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. ..."
}
]

View 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/"
}
]

View 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>
);
}
});

View 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;
}
}

View 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&rsquo;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&amp;byline=0&amp;portrait=0" />
</Modal>
</div>
);
}
});

View 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;
}
}

View 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>
);
}
});

View file

@ -0,0 +1,7 @@
.login {
padding: 14px 9px;
.submit-button {
margin-right: 3px;
}
}

View 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>
);
}
});

View 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";
}
}

View file

@ -0,0 +1,3 @@
$base-background-color: #0f8bc0;
$active-background-color: rgb(1, 96, 135);
$border-color: rgb(20, 154, 203);

View 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>
);
}
});

View 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: " ";
}
}
}

View file

@ -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>
);

View file

@ -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;
}
}
}
}

View file

@ -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">

View 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>
);
}
});

View 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;
}
}

View file

@ -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);
}

View file

@ -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>
);
}

View 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/"
}
]
}
]

View file

@ -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>
);
}

View file

@ -15,4 +15,8 @@
width: 40%;
}
}
.box {
margin-bottom: 20px;
}
}

BIN
static/images/mystuff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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'
}
]
},