Commit 79199d6d authored by chrisgarrity's avatar chrisgarrity

Placeholders for everything ‘above the fold’

parent f86bd016
{
"plugins": [
"transform-object-rest-spread"
],
"presets": ["es2015", "react"],
}
......@@ -16,6 +16,12 @@ $ui-white: #fff;
$ui-border: hsla(0, 0, 85, 1); //#D9D9D9
/* 3.0 colors */
/* Using www naming convention for now, should be consistent with gui */
$ui-green: hsla(163, 83, 40, 1); //#0fbd8c Pen Primary
$ui-coral: hsla(350, 100, 70, 1); //#FF6680 More Priamry
$ui-blue-10percent: hsla(215, 100, 65, .1);
$ui-orange-25percent: hsla(35, 90, 55, .25);
/* Overlay UI Gray Colors */
$active-gray: hsla(0, 0, 0, .1);
......
const PropTypes = require('prop-types');
const React = require('react');
const FormattedNumber = require('react-intl').FormattedNumber;
const CappedNumber = props => (
<props.as className={props.className}>
<FormattedNumber value={Math.min(props.value, 100)} />
{props.value > 100 ? '+' : ''}
</props.as>
);
CappedNumber.propTypes = {
value: PropTypes.number.isRequired,
className: PropTypes.string
};
CappedNumber.defaultProps = {
as: 'span'
};
module.exports = CappedNumber;
const classNames = require('classnames');
const PropTypes = require('prop-types');
const React = require('react');
require('./share-banner.scss');
const ShareBanner = props => (
<div className={classNames('shareBanner', props.className)}>
<div className="inner">
{props.children}
</div>
</div>
);
ShareBanner.propTypes = {
children: PropTypes.node,
className: PropTypes.string
};
module.exports = ShareBanner;
@import "../../colors";
$navigation-height: 50px;
.shareBanner {
background-color: $ui-orange-25percent;
color: $ui-orange;
width: 100%;
overflow: hidden;
}
......@@ -193,7 +193,7 @@
},
{
"name": "preview",
"pattern": "^/preview/?$",
"pattern": "^/preview/?(\\d+)?$",
"routeAlias": "/preview/?$",
"view": "preview/preview",
"title": "Scratch 3.0 Preview"
......
const bindAll = require('lodash.bindall');
const FormattedMessage = require('react-intl').FormattedMessage;
const FormattedNumber = require('react-intl').FormattedNumber;
const FormattedDate = require('react-intl').FormattedDate;
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const PropTypes = require('prop-types');
const React = require('react');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const Avatar = require('../../components/avatar/avatar.jsx');
const CappedNumber = require('../../components/cappednumber/cappednumber.jsx');
const placeholder = require('./gui-placeholder.png');
const ShareBanner = require('../../components/share-banner/share-banner.jsx');
require('./preview.scss');
const PreviewPresentation = props => {
const {
intl,
projectInfo,
...otherProps
} = props;
const formatMessage = intl.formatMessage;
const messages = {
'general.viewAll': formatMessage({id: 'general.viewAll'}),
};
const shareDate = (projectInfo.history && projectInfo.history.shared) ? projectInfo.history.shared : '';
return (
<div className="preview">
<ShareBanner>
<FlexRow className="previewRow">
<span className="shareText">
This project is not shared — so only you can see it.Click share to let everyone see it!
</span>
<button className="button shareButton">
Share
</button>
</FlexRow>
</ShareBanner>
{ projectInfo && projectInfo.author && projectInfo.author.id ? [
<div className="inner">
<FlexRow className="previewRow">
<FlexRow className="projectTitle">
<Avatar
src={`https://cdn2.scratch.mit.edu/get_image/user/${projectInfo.author.id}_44x48.png`}
/>
<div className="title">
<h1>{projectInfo.title}</h1>
by{' '}
<a href={`/users/${projectInfo.author.username}`}>
{projectInfo.author.username}
</a>
</div>
</FlexRow>
<div className="projectButtons">
<button className="button remixButton">
Remix
</button>
<button className="button seeInsideButton">
See Inside
</button>
</div>
</FlexRow>
<FlexRow className="previewRow">
<div className="placeholder">
<img src={placeholder} alt="" />
</div>
<FlexRow className="projectNotes">
{shareDate !== '' ? [
<div className="shareDate">
<div className="copyleft">&copy;</div>
{' '}
<FormattedDate
value={Date.parse(shareDate)}
year="numeric"
month="short"
day="2-digit"
/>
</div>
] : ''}
<div className="remixCredit">
Remix info here
</div>
<div className="projectDescription">
{projectInfo.description}
</div>
</FlexRow>
</FlexRow>
<FlexRow className="previewRow">
<FlexRow className="stats">
<div key="loves" className="project-loves">
<CappedNumber value={projectInfo.stats.loves} />
</div>
<div key="favorites" className="project-favorites favorited">
<CappedNumber value={projectInfo.stats.favorites} />
</div>
<div key="remixes" className="project-remixes">
<CappedNumber value={projectInfo.remix.count} />
</div>
<div key="views" className="project-views">
<CappedNumber value={projectInfo.stats.views} />
</div>
</FlexRow>
<FlexRow className="action-buttons">
<a href="#">
<li>
Add to Studio
</li>
</a>
<a href="#">
<li>
Social
</li>
</a>
<a href="#">
<li className="report">
Report
</li>
</a>
</FlexRow>
</FlexRow>
</div>
] : []
}
</div>
);
}
PreviewPresentation.propTyps = {
intl: intlShape,
projectInfo: PropTypes.shape({
id: PropTypes.number,
title: PropTypes.string,
description: PropTypes.string,
author: PropTypes.shape({id: PropTypes.number}),
history: PropTypes.shape({
created: PropTypes.string,
modified: PropTypes.string,
shared: PropTypes.string
}),
stats: PropTypes.shape({
views: PropTypes.number,
loves: PropTypes.number,
favorites: PropTypes.number
}),
remix: PropTypes.shape({
parent: PropTypes.number,
root: PropTypes.number
})
}),
sessionStatus: PropTypes.string
}
module.exports = injectIntl(PreviewPresentation);
\ No newline at end of file
html, body, #app, .gui {
width: 100%;
height: 100%;
margin: 0;
}
.gui * { box-sizing: border-box; }
const React = require('react');
const PropTypes = require('prop-types');
const bindAll = require('lodash.bindall');
const connect = require('react-redux').connect;
const Page = require('../../components/page/www/page.jsx');
const render = require('../../lib/render.jsx');
require('./preview.css');
const GUI = require('scratch-gui').default;
const api = require('../../lib/api');
const log = require('../../lib/log.js');
const PreviewPresentation = require('./presentation.jsx');
const sessionActions = require('../../redux/session.js');
class Preview extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'getProjectInfo'
]);
this.state = {
projectInfo: {} // project data to show
};
}
componentDidMount () {
// handle project id in URI
let pathname = window.location.pathname.toLowerCase();
if (pathname[pathname.length - 1] === '/') {
pathname = pathname.substring(0, pathname.length - 1);
}
const path = pathname.split('/');
const projectId = path[path.length - 1];
this.getProjectInfo(projectId);
}
getProjectInfo (projectId) {
api({
uri: `/projects/${projectId}`
}, (err, body) => {
if (!body) return log.error('No project info');
if (!err) return this.setState({projectInfo: body});
});
}
render () {
return (
// will need a container to set 'dir' attribute RTL if lang is rtl.
<GUI className="gui" />
<PreviewPresentation
projectInfo={this.state.projectInfo}
sessionStatus={this.props.sessionStatus}
/>
);
}
}
render(<Preview />, document.getElementById('app'));
Preview.propTypes = {
sessionStatus: PropTypes.string,
user: PropTypes.shape({
id: PropTypes.number,
banned: PropTypes.bool,
username: PropTypes.string,
token: PropTypes.string,
thumbnailUrl: PropTypes.string,
dateJoined: PropTypes.string,
email: PropTypes.string,
classroomId: PropTypes.string
})
};
Preview.defaultProps = {
sessionStatus: sessionActions.Status.NOT_FETCHED,
user: {}
};
const mapStateToProps = state => ({
sessionStatus: state.session.status,
user: state.session.session.user
});
const mapDispatchToProps = dispatch => ({
refreshSession: () => {
dispatch(sessionActions.refreshSession());
}
});
const ConnectedPreview = connect(
mapStateToProps,
mapDispatchToProps
)(Preview);
render(<Page><ConnectedPreview /></Page>, document.getElementById('app'));
@import "../../colors";
@import "../../frameless";
html, body, #app, .gui {
width: 100%;
height: 100%;
margin: 0;
}
/* override view padding for share banner */
#view {
padding: 0 0 20px 0;
}
.gui * { box-sizing: border-box; }
.preview h1 {
font-size: 1.5rem;
font-weight: 500;
}
.preview img.avatar {
border: 0;
border-radius: 5px;
}
.preview .title {
margin-left: 1rem;
font-size: .8rem;
text-align: left;
}
.preview .button {
margin-left: 1rem;
}
.shareButton,
.remixButton,
.seeInsideButton {
font-size: .875rem;
font-weight: normal;
&:before {
display: inline-block;
margin-right: .5rem;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
width: 1.5rem;
height: 1.5rem;
vertical-align: middle;
content: "";
}
}
.shareText {
align-self: center;
}
.shareButton {
background-color: $ui-orange;
&:before {
background-image: url("/svgs/favorite/favorite_type-gray.svg");
}
}
.remixButton {
background-color: $ui-green;
&:before {
background-image: url("/svgs/remix/remix_type-gray.svg");
}
}
.seeInsideButton {
&:before {
background-image: url("/images/emoji/cool-cat.png");
}
}
.previewRow {
justify-content: space-between;
align-items: flex-start;
margin-top: 1rem;
}
.placeholder {
width: 480px;
display: inline-block;
}
.placeholder img {
width: 100%;
}
.projectNotes {
width: 45%;
height: 404px;
flex-flow: column;
align-items: left;
}
.shareDate {
height: 2.5rem;
vertical-align: middle;
}
.remixCredit {
height: 34px;
width: 100%;
margin-bottom: 1rem;
border: 1px solid $ui-blue-10percent;
border-radius: 8px;
background-color: $ui-blue-10percent;
padding: .5rem;
}
.projectDescription {
white-space: pre-line;
flex: 1;
width: 100%;
overflow-y:scroll;
border: 1px solid $ui-blue-10percent;
border-radius: 8px;
background-color: $ui-blue-10percent;
padding: .5rem;
}
.copyleft {
display: inline-block;
text-align: right;
margin: 0px;
transform: scale(-1,1);
}
.stats {
width: 480px;
justify-content: flex-start;
}
.project-loves,
.project-favorites,
.project-remixes,
.project-views {
display: inline;
font-size: 1.25rem;
padding-right: 2rem;
&:before {
display: inline-block;
margin-right: .1rem;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
width: 1.5rem;
height: 1.5rem;
vertical-align: text-bottom;
content: "";
}
}
.project-loves {
&:before {
background-image: url("/svgs/love/love_type-gray.svg");
}
}
.project-loves.loved {
&:before {
background-image: url("/svgs/messages/love.svg");
}
}
.project-favorites {
&:before {
background-image: url("/svgs/favorite/favorite_type-gray.svg");
}
}
.project-favorites.favorited {
&:before {
background-image: url("/svgs/messages/favorite.svg");
}
}
.project-remixes {
&:before {
background-image: url("/svgs/remix/remix_type-gray.svg");
}
}
.project-views {
&:before {
background-image: url("/svgs/view/view_type-gray.svg");
}
}
.action-buttons {
display: flex;
width: 40%;
color: $type-white;
font-size: .8rem;
font-weight: 500;
justify-content: flex-end;
flex-wrap: wrap;
li {
display: inline-block;
margin: 0 5px;
border: 1px solid $ui-blue;
border-radius: 50px;
background-color: $ui-blue;
padding: .5em .75em .5em 1.5em;
text-decoration: none;
color: $type-white;
list-style-type: none;
&:hover {
transition: background-color .25s ease;
border-color: transparent;
background-color: $active-gray;
}
&:active {
border: 0 solid transparent;
box-shadow: inset 0 0 5px $box-shadow-gray;
background-color: $active-dark-gray;
padding: calc(.75em + 1px) calc(1.5em + 1px);
}
&.report {
border: 1px solid $ui-coral;
background-color: $ui-coral;
&:hover {
transition: background-color .25s ease;
border-color: transparent;
background-color: $active-gray;
}
&:active {
border: 0 solid transparent;
box-shadow: inset 0 0 5px $box-shadow-gray;
background-color: $active-dark-gray;
padding: calc(.75em + 1px) calc(1.5em + 1px);
}
}
}
}
.preview {
.title-banner {
&.masthead {
background-color: $ui-orange-25percent;
color: $ui-orange;
font-weight: bold;
padding-bottom: 0;
h1 {
margin: 0;
color: $ui-white;
}
.masthead-info {
display: flex;
align-items: center;
justify-content: space-between;
p {
margin: 0;
max-width: $cols6;
text-align: left;
color: $ui-white;
a {
border-bottom: 1px solid $ui-white;
color: $ui-white;
}
}
}
.ted-talk {
position: relative;
margin-bottom: $gutter;
border: 2px solid $ui-border;
border-radius: 10px;
width: $cols4;
height: $cols4 * .5625;
overflow: hidden;
iframe {
border: 0;
width: inherit;
height: inherit;
}
}
.band {
$band-color: hsla(360, 100, 100, .15);
margin-top: 2rem;
background-color: $band-color;
padding: 1rem 0;
}
.sub-nav {
text-align: left;
li {
margin: 0 .5rem 0 0;
}
}
}
&.faq-banner {
margin-bottom: 0;
background-color: $ui-gray;
}
}
}
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