mirror of
https://github.com/status-im/burnchart.git
synced 2025-02-03 06:13:40 +00:00
a crude header
This commit is contained in:
parent
bcc3e52ef9
commit
5047977f47
@ -9,6 +9,8 @@
|
||||
"deep-diff": "^0.3.3",
|
||||
"lesshat": "^3.0.2",
|
||||
"lodash": "^3.10.1",
|
||||
"marked": "^0.3.5",
|
||||
"moment": "^2.11.1",
|
||||
"normalize.less": "^1.0.0",
|
||||
"object-assign": "^4.0.1",
|
||||
"object-path": "^0.9.2",
|
||||
|
@ -14,7 +14,7 @@ delete RouterMixin.handleClick;
|
||||
// Values are function names below.
|
||||
let routes = {
|
||||
'/': 'projects',
|
||||
'/new/project': 'add',
|
||||
'/new/project': 'addProject',
|
||||
'/:owner/:name': 'milestones',
|
||||
'/:owner/:name/:milestone': 'chart',
|
||||
'/demo': 'demo'
|
||||
@ -87,7 +87,7 @@ export default React.createClass({
|
||||
},
|
||||
|
||||
// Add a project.
|
||||
add() {
|
||||
addProject() {
|
||||
return <AddProjectPage />;
|
||||
},
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import actions from '../actions/appActions.js';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'Comment.jsx',
|
||||
|
||||
// Save the input field value in our state.
|
||||
_onChange(evt) {
|
||||
this.setState({ 'value': evt.target.value });
|
||||
},
|
||||
|
||||
_onAdd() {
|
||||
// Emit the event.
|
||||
actions.emit('articles.comment', {
|
||||
id: this.props.id,
|
||||
value: this.state.value
|
||||
});
|
||||
|
||||
// Clear the input.
|
||||
this.setState({ value: null });
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return { value: null };
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={this.state.value}
|
||||
onChange={this._onChange}
|
||||
placeholder="Comment..."
|
||||
/>
|
||||
<button onClick={this._onAdd}>Add</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
72
src/js/components/Header.jsx
Normal file
72
src/js/components/Header.jsx
Normal file
@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
|
||||
import actions from '../actions/appActions.js';
|
||||
|
||||
import Icon from './Icon.jsx';
|
||||
import Link from './Link.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'Header.jsx',
|
||||
|
||||
// Sign user in.
|
||||
_onSignIn() {
|
||||
actions.emit('user.signin');
|
||||
},
|
||||
|
||||
// Sign user out.
|
||||
_onSignOut() {
|
||||
actions.emit('user.signout');
|
||||
},
|
||||
|
||||
render() {
|
||||
let props = this.props;
|
||||
|
||||
// Switch loading icon with app icon.
|
||||
let icon = [ 'fire', 'spinner' ][ +props.system.loading ];
|
||||
|
||||
// Sign-in/out.
|
||||
let user;
|
||||
if (props.user.uid) {
|
||||
user = (
|
||||
<div className="right">
|
||||
<a onClick={this._onSignOut}>
|
||||
<Icon name="signout" /> Sign Out {props.user.github.displayName}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
user = (
|
||||
<div className="right">
|
||||
<a className="button" onClick={this._onSignIn}>
|
||||
<Icon name="github"/> Sign In
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="head">
|
||||
{user}
|
||||
|
||||
<Link route={{ to: 'projects' }} id="icon">
|
||||
<Icon name={icon} />
|
||||
</Link>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<Link route={{ to: 'addProject' }}>
|
||||
<Icon name="plus" /> Add a Project
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link route={{ to: 'demo' }}>
|
||||
<Icon name="computer" /> See Examples
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
46
src/js/components/Icon.jsx
Normal file
46
src/js/components/Icon.jsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
|
||||
import Format from '../mixins/Format.js';
|
||||
|
||||
// Fontello icon hex codes.
|
||||
let codes = {
|
||||
'spyglass': '\e801', // Font Awesome - search
|
||||
'plus': '\e804', // Font Awesome - plus-circled
|
||||
'settings': '\e800', // Font Awesome - cog
|
||||
'rocket': '\e80a', // Font Awesome - rocket
|
||||
'computer': '\e807', // Font Awesome - desktop
|
||||
'help': '\e80f', // Font Awesome - lifebuoy
|
||||
'signout': '\e809', // Font Awesome - logout
|
||||
'github': '\e802', // Font Awesome - github
|
||||
'warning': '\e80c', // Entypo - attention
|
||||
'direction': '\e803', // Entypo - address
|
||||
'megaphone': '\e808', // Entypo - megaphone
|
||||
'heart': '\e80e', // Typicons - heart
|
||||
'sort': '\e806', // Typicons - sort-alphabet
|
||||
'spinner': '\e80b', // MFG Labs - spinner1
|
||||
'fire': '\e805' // Maki - fire-station
|
||||
};
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'Icon.jsx',
|
||||
|
||||
mixins: [ Format ],
|
||||
|
||||
render() {
|
||||
let name = this.props.name;
|
||||
|
||||
if (name && name in codes) {
|
||||
let code = this._hexToDec(codes[name]);
|
||||
return (
|
||||
<span
|
||||
className={'icon ' + name}
|
||||
dangerouslySetInnerHTML={{ '__html': '&#' + code + ';' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
@ -16,7 +16,11 @@ export default React.createClass({
|
||||
let link = App.link(route.to, route.params, route.query);
|
||||
|
||||
return (
|
||||
<a href={'#!' + link} onClick={this._route.bind(this, link)}>
|
||||
<a
|
||||
{...this.props}
|
||||
href={'#!' + link}
|
||||
onClick={this._route.bind(this, link)}
|
||||
>
|
||||
{this.props.children}
|
||||
</a>
|
||||
);
|
12
src/js/components/Notify.jsx
Normal file
12
src/js/components/Notify.jsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'Header.jsx',
|
||||
|
||||
// TODO.
|
||||
render() {
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
42
src/js/mixins/Format.js
Normal file
42
src/js/mixins/Format.js
Normal file
@ -0,0 +1,42 @@
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import marked from 'marked';
|
||||
|
||||
export default {
|
||||
|
||||
// Time from now.
|
||||
// TODO: Memoize.
|
||||
_fromNow(jsonDate) {
|
||||
return moment(jsonDate, moment.ISO_8601).fromNow();
|
||||
},
|
||||
|
||||
// When is a milestone due?
|
||||
_due(jsonDate) {
|
||||
if (!jsonDate) {
|
||||
return ' ';
|
||||
} else {
|
||||
return [ 'due', this.fromNow(jsonDate) ].join(' ');
|
||||
}
|
||||
},
|
||||
|
||||
// Markdown formatting.
|
||||
// TODO: works?
|
||||
_markdown(...args) {
|
||||
marked.apply(args);
|
||||
},
|
||||
|
||||
// Format milestone title.
|
||||
_title(text) {
|
||||
if (text.toLowerCase().indexOf('milestone') > -1) {
|
||||
return text;
|
||||
} else {
|
||||
return [ 'Milestone', text ].join(' ');
|
||||
}
|
||||
},
|
||||
|
||||
// Hex to decimal.
|
||||
_hexToDec(hex) {
|
||||
return parseInt(hex, 16);
|
||||
}
|
||||
|
||||
};
|
@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Page from '../mixins/Page.js';
|
||||
|
||||
import Link from '../components/Link.jsx';
|
||||
import Comment from '../components/Comment.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'ArticlePage.jsx',
|
||||
|
||||
mixins: [ Page ],
|
||||
|
||||
render() {
|
||||
let store = this.state,
|
||||
id = this.props.id;
|
||||
|
||||
// Find the article.
|
||||
let article = _.find(store.articles, a => a.id == id);
|
||||
|
||||
// Any comments?
|
||||
let comments;
|
||||
if (article.comments) {
|
||||
comments = (
|
||||
<div>
|
||||
{article.comments.map((t, i) => <div key={i}>{t}</div>)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{article.title}</div>
|
||||
<div>Lorem ipsum …</div>
|
||||
<Link route={{ to: 'blog' }}>Back</Link>
|
||||
{comments}
|
||||
<Comment id={article.id} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import Page from '../mixins/Page.js';
|
||||
|
||||
import Link from '../components/Link.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'BlogPage.jsx',
|
||||
|
||||
mixins: [ Page ],
|
||||
|
||||
render() {
|
||||
let store = this.state;
|
||||
|
||||
// Map through the articles.
|
||||
let articles = store.articles.map(a => {
|
||||
return (
|
||||
<div key={a.id}>
|
||||
<Link route={{ to: 'article', params: { id: a.id } }}>
|
||||
{a.title}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
return <div>{articles}</div>;
|
||||
}
|
||||
|
||||
});
|
@ -2,6 +2,9 @@ import React from 'react';
|
||||
|
||||
import Page from '../mixins/Page.js';
|
||||
|
||||
import Notify from '../components/Notify.jsx';
|
||||
import Header from '../components/Header.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'AddProjectPage.jsx',
|
||||
@ -9,7 +12,20 @@ export default React.createClass({
|
||||
mixins: [ Page ],
|
||||
|
||||
render() {
|
||||
return <div>Add</div>;
|
||||
return (
|
||||
<div>
|
||||
<Notify />
|
||||
<Header {...this.state} />
|
||||
|
||||
<div id="page" />
|
||||
|
||||
<div id="footer">
|
||||
<div className="wrap">
|
||||
© 2012-2016 <a href="https:/radekstepan.com" target="_blank">Radek Stepan</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -2,6 +2,9 @@ import React from 'react';
|
||||
|
||||
import Page from '../mixins/Page.js';
|
||||
|
||||
import Notify from '../components/Notify.jsx';
|
||||
import Header from '../components/Header.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'ChartPage.jsx',
|
||||
@ -9,7 +12,20 @@ export default React.createClass({
|
||||
mixins: [ Page ],
|
||||
|
||||
render() {
|
||||
return <div>Chart</div>;
|
||||
return (
|
||||
<div>
|
||||
<Notify />
|
||||
<Header {...this.state} />
|
||||
|
||||
<div id="page" />
|
||||
|
||||
<div id="footer">
|
||||
<div className="wrap">
|
||||
© 2012-2016 <a href="https:/radekstepan.com" target="_blank">Radek Stepan</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -2,6 +2,9 @@ import React from 'react';
|
||||
|
||||
import Page from '../mixins/Page.js';
|
||||
|
||||
import Notify from '../components/Notify.jsx';
|
||||
import Header from '../components/Header.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'MilestonesPage.jsx',
|
||||
@ -9,7 +12,20 @@ export default React.createClass({
|
||||
mixins: [ Page ],
|
||||
|
||||
render() {
|
||||
return <div>Milestones</div>;
|
||||
return (
|
||||
<div>
|
||||
<Notify />
|
||||
<Header {...this.state} />
|
||||
|
||||
<div id="page" />
|
||||
|
||||
<div id="footer">
|
||||
<div className="wrap">
|
||||
© 2012-2016 <a href="https:/radekstepan.com" target="_blank">Radek Stepan</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -2,6 +2,9 @@ import React from 'react';
|
||||
|
||||
import Page from '../mixins/Page.js';
|
||||
|
||||
import Notify from '../components/Notify.jsx';
|
||||
import Header from '../components/Header.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
|
||||
displayName: 'ProjectsPage.jsx',
|
||||
@ -9,7 +12,20 @@ export default React.createClass({
|
||||
mixins: [ Page ],
|
||||
|
||||
render() {
|
||||
return <div>Projects</div>;
|
||||
return (
|
||||
<div>
|
||||
<Notify />
|
||||
<Header {...this.state} />
|
||||
|
||||
<div id="page" />
|
||||
|
||||
<div id="footer">
|
||||
<div className="wrap">
|
||||
© 2012-2016 <a href="https:/radekstepan.com" target="_blank">Radek Stepan</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -9,25 +9,13 @@ class AppStore extends Store {
|
||||
// Initial payload.
|
||||
constructor() {
|
||||
super({
|
||||
articles: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Winklevoss Twins Aim to Take Bitcoin Mainstream with a Regulated Exchange',
|
||||
url: 'nytimes.com'
|
||||
}, {
|
||||
id: 2,
|
||||
title: 'Gotham Air: Manhattan to JFK in 6 minutes for $99',
|
||||
url: 'gothamair.com'
|
||||
}, {
|
||||
id: 3,
|
||||
title: 'Gitlet: Git implemented in JavaScript',
|
||||
url: 'maryrosecook.com'
|
||||
}
|
||||
]
|
||||
system: {
|
||||
loading: true
|
||||
},
|
||||
user: {}
|
||||
});
|
||||
|
||||
// Listen to all app actions
|
||||
// articles.comment -> onArticlesComment
|
||||
actions.onAny((obj, event) => {
|
||||
let fn = ('on.' + event).replace(/[.]+(\w|$)/g, (m, p) => {
|
||||
return p.toUpperCase();
|
||||
@ -36,24 +24,13 @@ class AppStore extends Store {
|
||||
(fn in this) && this[fn](obj);
|
||||
});
|
||||
}
|
||||
|
||||
// Add article comment action listener.
|
||||
onArticlesComment(obj) {
|
||||
let key;
|
||||
// Find the article.
|
||||
let article = _.find(this.get('articles'), (a, i) => {
|
||||
if (a.id == obj.id) {
|
||||
key = [ 'articles', i, 'comments' ];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Init new or add to array.
|
||||
if ('comments' in article) {
|
||||
this.set(key.concat([ article.comments.length ]), obj.value);
|
||||
} else {
|
||||
this.set(key, [ obj.value ]);
|
||||
}
|
||||
onUserSignin() {
|
||||
console.log('in');
|
||||
}
|
||||
|
||||
onUserSignOut() {
|
||||
console.log('out');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -174,6 +174,7 @@ ul {
|
||||
a {
|
||||
color: #e0808d;
|
||||
font-weight: bold;
|
||||
.user-select(none);
|
||||
|
||||
&.active, &:hover {
|
||||
color: #fff;
|
||||
|
Loading…
x
Reference in New Issue
Block a user