Commit b7bfaec4 authored by Matthew Taylor's avatar Matthew Taylor

Merge pull request #1006 from chrisgarrity/feature/gh979-tttpage

Fix gh-979: TTT page
parent e6de0d0b
var classNames = require('classnames');
var React = require('react');
var MediaQuery = require('react-responsive');
var frameless = require('../../lib/frameless');
require('./masonrygrid.scss');
var MasonryGrid = React.createClass({
type: 'MasonryGrid',
getDefaultProps: function () {
return {
as: 'div'
};
},
reorderColumns: function (items, cols) {
var a1 = [];
var a2 = [];
var a3 = [];
var i = 0;
//only implemented for 2 and 3 columns so far - easy to extend if needed
if (cols > 1 && cols < 4) {
for (i=0;i<items.length;i++){
var col = (i+cols)%cols;
if (col === 0) {
a1.push(items[i]);
}
else if (col === 1) {
a2.push(items[i]);
}
else if (col === 2) {
a3.push(items[i]);
}
}
return a1.concat(a2,a3);
} else {
return items;
}
},
render: function () {
var classes = classNames(
'masonry',
this.props.className
);
return (
<this.props.as className={classes}>
<MediaQuery maxWidth={frameless.tablet - 1} >
{this.props.children}
</MediaQuery>
<MediaQuery minWidth={frameless.tablet} maxWidth={frameless.desktop - 1} >
{this.reorderColumns(this.props.children, 2)}
</MediaQuery>
<MediaQuery minWidth={frameless.desktop} >
{this.reorderColumns(this.props.children, 3)}
</MediaQuery>
</this.props.as>
);
}
});
module.exports = MasonryGrid;
@import "../../frameless";
.masonry {
column-gap: $gutter;
column-width: $cols4;
padding-bottom: 50px;
-webkit-perspective: 1;
}
// working around Firefox issue that requires column-count, using explicit -moz-column-count
//4 columns
@media only screen and (max-width: $mobile - 1) {
.masonry {
-moz-column-count: 1;
}
}
//6 columns
@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) {
.masonry {
-moz-column-count: 1;
}
}
//8 columns
@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) {
.masonry {
-moz-column-count: 2;
}
}
// 12 columns
@media only screen and (min-width: $desktop) {
.masonry {
-moz-column-count: 3;
}
}
var classNames = require('classnames');
var React = require('react');
var FormattedMessage = require('react-intl').FormattedMessage;
require('../forms/button.scss');
require('./ttt-tile.scss');
var TTTTile = React.createClass({
type: 'TTTTile',
propTypes: {
title: React.PropTypes.string.isRequired,
description: React.PropTypes.string.isRequired,
thumbUrl: React.PropTypes.string.isRequired,
tutorialLoc: React.PropTypes.string.isRequired,
onGuideClick: React.PropTypes.func.isRequired
},
render: function () {
var classes = classNames(
'ttt-tile',
this.props.className
);
return (
<div className={classes} >
<a href={this.props.tutorialLoc}>
<div className="ttt-tile-tutorial">
<div className="ttt-tile-image">
<img className="ttt-tile-image-img" src={this.props.thumbUrl} alt="" />
<div className="ttt-tile-image-try">
<div className="button mod-ttt-tile-image-try-button">
<FormattedMessage id="ttt.tryIt" />
</div>
</div>
</div>
<div className="ttt-tile-info">
<div className="ttt-tile-tag">
<FormattedMessage id='tile.tutorial' defaultMessage='Tutorial'/>
</div>
<h4 className="ttt-tile-title">{this.props.title}</h4>
<p className="ttt-tile-description">
{this.props.description}
</p>
</div>
</div>
</a>
<div className="ttt-tile-guides" onClick={this.props.onGuideClick}>
<FormattedMessage id='tile.guides' defaultMessage='See Cards and Guides'/>
<img className="ttt-tile-see-more" src="/svgs/ttt/see-more.svg" />
</div>
</div>
);
}
});
module.exports = TTTTile;
@import "../../colors";
@import "../../frameless";
.ttt-tile {
display: inline-block;
// work-around chrome bug with columns support - 1 px of next column ends up
// at the bottom of the previous column.
margin-top: 1px;
margin-bottom: calc(1.25rem - 1px);
border-radius: 1rem;
box-shadow: 0 0 0 1px $active-gray;
width: $cols4;
text-align: center;
}
.ttt-tile-tutorial {
display: inline-block;
position: relative;
}
// nesting is required (not just name-spacing) because we want the image
// and tile box to change style on hover of the parent component.
.ttt-tile-tutorial:hover {
.ttt-tile-image {
.ttt-tile-image-img {
opacity: .5;
}
.ttt-tile-image-try {
display: inline-block;
}
}
}
.ttt-tile-image {
border-radius: 1rem 1rem 0 0;
background: $ui-blue;
width: 100%;
}
.ttt-tile-image-img {
display: block;
border-radius: 1rem 1rem 0 0;
width: 100%;
}
// wrapper for try button to get position correct
.ttt-tile-image-try {
display: none;
position: absolute;
top: 4rem;
left: 50%;
transform: translate(-50%, 0);
text-align: center;
color: $ui-white;
}
.mod-ttt-tile-image-try-button {
border: 1px solid $ui-white;
background-color: transparent;
}
.ttt-tile-info {
position: relative;
cursor: pointer;
padding: 1rem 0;
}
.ttt-tile-tag {
display: inline-block;
position: absolute;
top: -1rem;
left: 1rem;
margin: .5em 0;
border: 0;
border-radius: 1rem;
background-color: $ui-blue;
padding: .25rem 1rem;
color: $type-white;
font-size: .8rem;
font-weight: bold;
}
.ttt-tile-title {
margin: .5rem auto;
width: calc(100% - 3rem);
}
.ttt-tile-description {
margin: auto;
width: calc(100% - 3rem);
font-size: .875rem;
}
.ttt-tile-guides {
margin: auto;
border-top: 1px dashed $ui-border;
border-radius: 0 0 1rem 1rem;
cursor: pointer;
padding: 1.25rem 0;
color: $link-blue;
font-size: .75rem;
font-weight: 500;
&:hover {
background-color: lighten($link-blue, 40%);
}
}
.ttt-tile-see-more {
display: inline-block;
padding: 0 .25rem;
vertical-align: middle;
}
......@@ -133,6 +133,13 @@
"view": "cards/cards",
"title": "Cards"
},
{
"name": "things-to-try",
"pattern": "^/go/?$",
"routeAlias": "/go/?$",
"view": "thingstotry/thingstotry",
"title": "Things to Try"
},
{
"name": "communityblocks-interviews",
"pattern": "^/info/communityblocks-interviews/?$",
......
{
"ttt.MakeItFlyActivityLoc": "/pdfs/cards/FlyCards.pdf",
"ttt.MakeItFlyGuideLoc": "/pdfs/guides/FlyGuide.pdf",
"ttt.AnimateYourNameActivityLoc": "/pdfs/cards/AnimateYourNameCards.pdf",
"ttt.AnimateYourNameGuideLoc": "/pdfs/guides/NameGuide.pdf",
"ttt.MakeMusicActivityLoc": "/pdfs/cards/MusicCards.pdf",
"ttt.MakeMusicGuideLoc": "/pdfs/guides/MusicGuide.pdf",
"ttt.RaceActivityLoc": "/pdfs/cards/RaceGameCards.pdf",
"ttt.RaceGuideLoc": "/pdfs/guides/RaceGuide.pdf",
"ttt.DanceActivityLoc": "/pdfs/cards/DanceCards.pdf",
"ttt.DanceGuideLoc": "/pdfs/guides/DanceGuide.pdf",
"ttt.PongActivityLoc": "/pdfs/cards/PongCards.pdf",
"ttt.PongGuideLoc": "/pdfs/guides/PongGuide.pdf",
"ttt.CatchActivityLoc": "/pdfs/cards/CatchCards.pdf",
"ttt.CatchGuideLoc": "/pdfs/guides/CatchGuide.pdf",
"ttt.HideAndSeekActivityLoc": "/pdfs/cards/Hide-and-Seek-Cards.pdf",
"ttt.HideAndSeekGuideLoc": "/pdfs/guides/Hide-and-Seek-Guide.pdf",
"ttt.VirtualPetActivityLoc": "/pdfs/cards/PetCards.pdf",
"ttt.VirtualPetGuideLoc": "/pdfs/guides/PetGuide.pdf",
"ttt.FashionActivityLoc": "/pdfs/cards/DressupCards.pdf",
"ttt.FashionGuideLoc": "/pdfs/guides/DressupGuide.pdf",
"ttt.StoryActivityLoc": "/pdfs/cards/StoryCards.pdf",
"ttt.StoryGuideLoc": "/pdfs/guides/StoryGuide.pdf"
}
{
"ttt.placeholder": "Placeholder text",
"ttt.title": "Things to Try",
"ttt.subTitle": "You can get started with Scratch in a variety of ways. Click a picture to try a <b>Tutorial</b>. You can also download a set of <b>Activity Cards</b> and <b>Educator Guide</b> for each theme.",
"tile.tutorial": "Tutorial",
"tile.guides": "See Cards and Guides",
"ttt.tutorialTitle": "Tutorial",
"ttt.tutorialSubtitle": "Find out how to make this project using a step-by-step tutorial in Scratch.",
"ttt.activityTitle": "Activity Cards",
"ttt.activitySubtitle": "Explore new coding ideas using this set of illustrated cards you can print out.",
"ttt.educatorTitle": "Educator Guide",
"ttt.educatorSubtitle": "Use this educator guide to plan and lead a one-hour Scratch workshop.",
"ttt.tryIt": "Try It",
"ttt.download": "Download",
"ttt.MakeItFlyTitle": "Make It Fly",
"ttt.MakeItFlyDescription": "Animate the Scratch Cat, The Powerpuff Girls, or even a taco!",
"ttt.AnimateYourNameTitle": "Animate Your Name",
"ttt.AnimateYourNameDescription": "Animate the letters of your name, initials, or favorite word.",
"ttt.RaceTitle": "Race to the Finish",
"ttt.RaceDescription": "Make a game where two characters race each other.",
"ttt.MakeMusicTitle": "Make Music",
"ttt.MakeMusicDescription": "Choose instruments, add sounds, and press keys to play music.",
"ttt.HideAndSeekTitle": "Hide-and-Seek Game",
"ttt.HideAndSeekDescription": "Make a hide-and-seek game with characters that appear and disappear.",
"ttt.StoryTitle": "Create a Story",
"ttt.StoryDescription": "Choose characters, add conversation, and bring your story to life.",
"ttt.FashionTitle": "Fashion Game",
"ttt.FashionDescription": "Dress up a character with different clothes and styles.",
"ttt.PongTitle": "Pong Game",
"ttt.PongDescription": "Make a bouncing ball game with sounds, points, and other effects.",
"ttt.DanceTitle": "Let's Dance",
"ttt.DanceDescription": "Design an animated dance scene with music and dance moves.",
"ttt.CatchTitle": "Catch Game",
"ttt.CatchDescription": "Make a game where you catch things falling from the sky.",
"ttt.VirtualPetTitle": "Virtual Pet",
"ttt.VirtualPetDescription": "Create an interactive pet that can eat, drink, and play."
}
var React = require('react');
var injectIntl = require('react-intl').injectIntl;
var FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
var FormattedMessage = require('react-intl').FormattedMessage;
var render = require('../../lib/render.jsx');
var MasonryGrid = require('../../components/masonrygrid/masonrygrid.jsx');
var Page = require('../../components/page/www/page.jsx');
var TitleBanner = require('../../components/title-banner/title-banner.jsx');
var TTTTile = require('../../components/ttt-tile/ttt-tile.jsx');
var TTTModal = require('../../components/modal/ttt/modal.jsx');
var Tiles = require('./ttt.json');
require('./thingstotry.scss');
var ThingsToTry = injectIntl(React.createClass({
type: 'ThingsToTry',
getInitialState: function () {
return {
currentTile: Tiles[0],
TTTModalOpen: false
};
},
showTTTModal: function (tile) {
// expects translated tile
this.setState({currentTile: tile});
this.setState({TTTModalOpen: true});
},
hideTTTModal: function () {
this.setState({TTTModalOpen: false});
},
renderTTTTiles: function () {
var formatMessage = this.props.intl.formatMessage;
var translatedTiles = [];
var translatedTile = {};
Tiles.map(function (tile, key) {
translatedTile = {
title: formatMessage({id: tile.title}),
description: formatMessage({id: tile.description}),
tutorialLoc: tile.tutorialLoc,
activityLoc: formatMessage({id: tile.activityLoc}),
guideLoc: formatMessage({id: tile.guideLoc}),
thumbUrl: tile.thumbUrl,
bannerUrl: tile.bannerUrl
};
translatedTiles.push(
<TTTTile
key={key}
onGuideClick={this.showTTTModal.bind(this, translatedTile)}
{...translatedTile}
/>
);
}, this); // don't forget to pass 'this' into map function
return translatedTiles;
},
render: function () {
return (
<div className="ttt">
<TitleBanner className="masthead mod-ttt-title">
<section className="ttt-section">
<img className="ttt-banner-image" src="/svgs/ttt/resources.svg" alt=""/>
</section>
<h1>
<FormattedMessage id="ttt.title" />
</h1>
<p className="intro">
<FormattedHTMLMessage id="ttt.subTitle" />
</p>
</TitleBanner>
<div className="inner">
<section className="ttt-section">
<MasonryGrid >
{this.renderTTTTiles()}
</MasonryGrid>
<TTTModal
isOpen={this.state.TTTModalOpen}
onRequestClose={this.hideTTTModal}
{...this.state.currentTile}
/>
</section>
</div>
</div>
);
}
}));
render(<Page><ThingsToTry /></Page>, document.getElementById('app'));
@import "../../colors";
@import "../../frameless";
$base-bg: $ui-white;
#view {
padding: 0;
}
// .mod-ttt-title, to avoid collision with .title-banner.mod-tt in ttt modal
.title-banner.mod-ttt-title {
background-color: $ui-blue;
}
.ttt-section {
display: flex;
margin: 0 auto;
text-align: center;
justify-content: center;
flex-wrap: wrap;
align-items: center;
}
.ttt-banner-image {
max-width: calc(100% - 2rem);
}
//4 columns
@media only screen and (max-width: $mobile - 1) {
.title-banner {
&.masthead {
padding-bottom: 1.25rem;
p {
max-width: $cols4;
}
}
}
.ttt-section.mod-title-banner {
max-width: $mobile;
}
}
//6 columns
@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) {
.title-banner {
&.masthead {
p {
max-width: $cols6;
}
}
}
.ttt-section.mod-title-banner {
max-width: $mobile;
}
}
//8 columns
@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) {
.title-banner {
&.masthead {
padding-bottom: 2rem;
p {
max-width: $cols8;
}
}
}
.ttt-section.mod-title-banner {
max-width: $tablet;
}
}
// 12 columns
@media only screen and (min-width: $desktop) {
.title-banner {
&.masthead {
padding-bottom: 1.25rem;
p {
max-width: $cols8;
}
}
}
}
[
{
"title": "ttt.AnimateYourNameTitle",
"description": "ttt.AnimateYourNameDescription",
"thumbUrl": "/images/ttt/animate-your-name.jpg",
"bannerUrl": "/images/ttt/animate-your-name-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=name",
"activityLoc": "ttt.AnimateYourNameActivityLoc",
"guideLoc": "ttt.AnimateYourNameGuideLoc"
},
{
"title": "ttt.MakeItFlyTitle",
"description": "ttt.MakeItFlyDescription",
"thumbUrl": "/images/ttt/make-it-fly.jpg",
"bannerUrl": "/images/ttt/make-it-fly-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=fly",
"activityLoc": "ttt.MakeItFlyActivityLoc",
"guideLoc": "ttt.MakeItFlyGuideLoc"
},
{
"title": "ttt.MakeMusicTitle",
"description": "ttt.MakeMusicDescription",
"thumbUrl": "/images/ttt/make-music.jpg",
"bannerUrl": "/images/ttt/make-music-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=music",
"activityLoc": "ttt.MakeMusicActivityLoc",
"guideLoc": "ttt.MakeMusicGuideLoc"
},
{
"title": "ttt.RaceTitle",
"description": "ttt.RaceDescription",
"thumbUrl": "/images/ttt/race-to-the-finish.jpg",
"bannerUrl": "/images/ttt/race-to-the-finish-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=racegame",
"activityLoc": "ttt.RaceActivityLoc",
"guideLoc": "ttt.RaceGuideLoc"
},
{
"title": "ttt.HideAndSeekTitle",
"description": "ttt.HideAndSeekDescription",
"thumbUrl": "/images/ttt/hide-and-seek.jpg",
"bannerUrl": "/images/ttt/hide-and-seek-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=hide",
"activityLoc": "ttt.HideAndSeekActivityLoc",
"guideLoc": "ttt.HideAndSeekGuideLoc"
},
{
"title": "ttt.PongTitle",
"description": "ttt.PongDescription",
"thumbUrl": "/images/ttt/pong-game.jpg",
"bannerUrl": "/images/ttt/pong-game-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=pong",
"activityLoc": "ttt.PongActivityLoc",
"guideLoc": "ttt.PongGuideLoc"
},
{
"title": "ttt.DanceTitle",
"description": "ttt.DanceDescription",
"thumbUrl": "/images/ttt/lets-dance.jpg",
"bannerUrl": "/images/ttt/lets-dance-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=dance",
"activityLoc": "ttt.DanceActivityLoc",
"guideLoc": "ttt.DanceGuideLoc"
},
{
"title": "ttt.CatchTitle",
"description": "ttt.CatchDescription",
"thumbUrl": "/images/ttt/catch-game.jpg",
"bannerUrl": "/images/ttt/catch-game-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=catch",
"activityLoc": "ttt.CatchActivityLoc",
"guideLoc": "ttt.CatchGuideLoc"
},
{
"title": "ttt.VirtualPetTitle",
"description": "ttt.VirtualPetDescription",
"thumbUrl": "/images/ttt/virtual-pet.jpg",
"bannerUrl": "/images/ttt/virtual-pet-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=pet",
"activityLoc": "ttt.VirtualPetActivityLoc",
"guideLoc": "ttt.VirtualPetGuideLoc"
}
]
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.2;fill:#4C97FF;stroke:#4C97FF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st1{fill:none;stroke:#4C97FF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st2{fill:#4C97FF;}
</style>
<path class="st0" d="M13,11H6c-0.6,0-1-0.4-1-1V3c0-0.6,0.4-1,1-1h7c0.6,0,1,0.4,1,1v7C14,10.6,13.6,11,13,11z"/>
<path class="st1" d="M9,13c0,0.6-0.4,1-1,1H3c-0.6,0-1-0.4-1-1V8c0-0.6,0.4-1,1-1"/>
<path class="st1" d="M13,11H6c-0.6,0-1-0.4-1-1V3c0-0.6,0.4-1,1-1h7c0.6,0,1,0.4,1,1v7C14,10.6,13.6,11,13,11z"/>
<g>
<path class="st2" d="M12,4.2v2.4c0,0.2-0.3,0.3-0.4,0.2L10.8,6l-3,2.7c-0.1,0.1-0.3,0.1-0.4,0c-0.1-0.1-0.1-0.3,0-0.4L10,5.2
L9.2,4.4C9,4.3,9.1,4,9.4,4h2.4C11.9,4,12,4.1,12,4.2z"/>
</g>
</svg>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment