Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Andrew Fryer Front end Task #28

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
},
"dependencies": {
"classnames": "^2.2.5",
"css-loader": "^0.28.11",
"director": "^1.2.8",
"express": "^4.15.3",
"jsesc": "^2.5.1",
Expand All @@ -59,6 +60,7 @@
"prop-types": "^15.5.10",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"style-loader": "^0.18.2",
"todomvc-app-css": "^2.1.0",
"todomvc-common": "^1.0.3",
"url-loader": "^0.5.9",
Expand Down
141 changes: 141 additions & 0 deletions src/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
hr {
margin: 20px 0;
border: 0;
border-top: 1px dashed #c5c5c5;
border-bottom: 1px dashed #f7f7f7;
}

.learn a {
font-weight: normal;
text-decoration: none;
color: #b83f45;
}

.learn a:hover {
text-decoration: underline;
color: #787e7e;
}

.learn h3,
.learn h4,
.learn h5 {
margin: 10px 0;
font-weight: 500;
line-height: 1.2;
color: #000;
}

.learn h3 {
font-size: 24px;
}

.learn h4 {
font-size: 18px;
}

.learn h5 {
margin-bottom: 0;
font-size: 14px;
}

.learn ul {
padding: 0;
margin: 0 0 30px 25px;
}

.learn li {
line-height: 20px;
}

.learn p {
font-size: 15px;
font-weight: 300;
line-height: 1.3;
margin-top: 0;
margin-bottom: 0;
}

#issue-count {
display: none;
}

.quote {
border: none;
margin: 20px 0 60px 0;
}

.quote p {
font-style: italic;
}

.quote p:before {
content: '“';
font-size: 50px;
opacity: .15;
position: absolute;
top: -20px;
left: 3px;
}

.quote p:after {
content: '”';
font-size: 50px;
opacity: .15;
position: absolute;
bottom: -42px;
right: 3px;
}

.quote footer {
position: absolute;
bottom: -40px;
right: 0;
}

.quote footer img {
border-radius: 3px;
}

.quote footer a {
margin-left: 5px;
vertical-align: middle;
}

.speech-bubble {
position: relative;
padding: 10px;
background: rgba(0, 0, 0, .04);
border-radius: 5px;
}

.speech-bubble:after {
content: '';
position: absolute;
top: 100%;
right: 30px;
border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04);
}

.learn-bar > .learn {
position: absolute;
width: 272px;
top: 8px;
left: -300px;
padding: 10px;
border-radius: 5px;
background-color: rgba(255, 255, 255, .6);
transition-property: left;
transition-duration: 500ms;
}

@media (min-width: 899px) {
.learn-bar {
width: auto;
padding-left: 300px;
}

.learn-bar > .learn {
left: 8px;
}
}
3 changes: 3 additions & 0 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import TodoApp from './components/todoApp.js';
import React from 'react';
import ReactDOM from 'react-dom';

import './base.css';
import './index.css';

const initialState = window.initialState && JSON.parse(window.initialState) || {};

var todoStore = TodoStore.fromJS(initialState.todos || []);
Expand Down
10 changes: 2 additions & 8 deletions src/components/todoApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {observer} from 'mobx-react';
import TodoEntry from './todoEntry';
import TodoOverview from './todoOverview';
import TodoFooter from './todoFooter';
import { ALL_TODOS, ACTIVE_TODOS, COMPLETED_TODOS } from '../constants';

import DevTool from 'mobx-react-devtools';

Expand All @@ -29,13 +28,8 @@ export default class TodoApp extends React.Component {
componentDidMount() {
if (__CLIENT__) {
var { Router } = require('director/build/director');
var viewStore = this.props.viewStore;
var router = Router({
'/': function() { viewStore.todoFilter = ALL_TODOS; },
'/active': function() { viewStore.todoFilter = ACTIVE_TODOS; },
'/completed': function() { viewStore.todoFilter = COMPLETED_TODOS; }
});
router.init('/');
var router = Router({});
router.init('/');
}
}
}
Expand Down
17 changes: 8 additions & 9 deletions src/components/todoFooter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import {observer} from 'mobx-react';
import {action} from 'mobx';
import {pluralize} from '../utils';
import { ALL_TODOS, ACTIVE_TODOS, COMPLETED_TODOS } from '../constants';

@observer
export default class TodoFooter extends React.Component {
Expand All @@ -14,15 +13,15 @@ export default class TodoFooter extends React.Component {

const activeTodoWord = pluralize(todoStore.activeTodoCount, 'item');

const filters = this.props.todoStore.rangeOfTags;

return (
<footer className="footer">
<span className="todo-count">
<strong>{todoStore.activeTodoCount}</strong> {activeTodoWord} left
</span>
<ul className="filters">
{this.renderFilterLink(ALL_TODOS, "", "All")}
{this.renderFilterLink(ACTIVE_TODOS, "active", "Active")}
{this.renderFilterLink(COMPLETED_TODOS, "completed", "Completed")}
{filters.map(t => this.renderFilterLink(t))}
</ul>
{ todoStore.completedCount === 0
? null
Expand All @@ -36,12 +35,12 @@ export default class TodoFooter extends React.Component {
);
}

renderFilterLink(filterName, url, caption) {
renderFilterLink(filterName) {
return (<li>
<a href={"#/" + url}
className={filterName === this.props.viewStore.todoFilter ? "selected" : ""}>
{caption}
</a>
<button onClick={() => this.props.viewStore.toggleView(filterName)}
className={this.props.viewStore.todoFilters.includes(filterName) ? "selected" : ""}>
{filterName}
</button>
{' '}
</li>)
}
Expand Down
34 changes: 29 additions & 5 deletions src/components/todoItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,37 @@ import React from 'react';
import PropTypes from 'prop-types';
import {observer} from 'mobx-react';
import {observable, action, computed} from 'mobx';

const ESCAPE_KEY = 27;
const ENTER_KEY = 13;
import { COMPLETED_TODOS } from '../constants';

@observer
export default class TodoItem extends React.Component {
@observable editText = "";

render() {
const {todo} = this.props;

console.log(todo.tag)
return (
<li className={[
todo.completed ? "completed": "",
todo.tags.includes(COMPLETED_TODOS) ? "completed": "",
this.isBeingEdited ? "editing" : ""
].join(" ")}>
<div className="view">
<input
className="toggle"
type="checkbox"
checked={todo.completed}
checked={todo.tags.includes(COMPLETED_TODOS)}
onChange={this.handleToggle}
/>
<label onDoubleClick={this.handleEdit}>
{todo.title}
</label>
<ul className="tags">
{todo.tags.filter(t => t !== COMPLETED_TODOS).map(t => this.renderTag(t))}
</ul>
<button className="new-tag" onClick={this.handleNewTag} />
<button className="destroy" onClick={this.handleDestroy} />
</div>
<input
Expand All @@ -41,6 +47,15 @@ export default class TodoItem extends React.Component {
);
}

renderTag(name) {
return (<li key={name}>
<button onClick={() => this.props.todo.toggleTag(name)}>
{name}
</button>
{' '}
</li>)
}

@computed
get isBeingEdited() {
return this.props.viewStore.todoBeingEdited === this.props.todo
Expand Down Expand Up @@ -88,11 +103,20 @@ export default class TodoItem extends React.Component {

@action
handleToggle = () => {
this.props.todo.toggle();
this.props.todo.toggleTag(COMPLETED_TODOS);
};

@action
handleNewTag = () => {
const tagStr = prompt("enter new tag");
if(!this.props.todo.tags.includes(tagStr)) {
this.props.todo.toggleTag(tagStr);
}
}
}

TodoItem.propTypes = {
todo: PropTypes.object.isRequired,
viewStore: PropTypes.object.isRequired
viewStore: PropTypes.object.isRequired,
todoStore: PropTypes.object.isRequired,
};
30 changes: 22 additions & 8 deletions src/components/todoOverview.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {observer} from 'mobx-react';
import { ACTIVE_TODOS, COMPLETED_TODOS } from '../constants';
import { ACTIVE_TODOS, COMPLETED_TODOS, ALL_TODOS } from '../constants';

import TodoItem from './todoItem';

Expand All @@ -13,7 +13,7 @@ export default class TodoOverview extends React.Component {
return null;
return <section className="main">
<input
className="toggle-all"
className="toggle-all" // this image doen't make sense to me...
id="toggle-all"
type="checkbox"
onChange={this.toggleAll}
Expand All @@ -26,6 +26,7 @@ export default class TodoOverview extends React.Component {
key={todo.id}
todo={todo}
viewStore={viewStore}
todoStore={todoStore}
/>)
)}
</ul>
Expand All @@ -34,14 +35,27 @@ export default class TodoOverview extends React.Component {

getVisibleTodos() {
return this.props.todoStore.todos.filter(todo => {
switch (this.props.viewStore.todoFilter) {
case ACTIVE_TODOS:
return !todo.completed;
case COMPLETED_TODOS:
return todo.completed;
default:
for(let i = 0; i < this.props.viewStore.todoFilters.length; i++) {
const filter = this.props.viewStore.todoFilters[i];
let res = null;
switch (filter) {
case ALL_TODOS:
res = true;
break;
case ACTIVE_TODOS:
res = !todo.tags.includes(COMPLETED_TODOS);
break;
case COMPLETED_TODOS:
res = todo.tags.includes(COMPLETED_TODOS);
break;
default:
res = todo.tags.includes(filter);
}
if(res) {
return true;
}
}
return false;
});
}

Expand Down
6 changes: 3 additions & 3 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const ALL_TODOS = 'all';
export const ACTIVE_TODOS = 'active';
export const COMPLETED_TODOS = 'completed';
export const ALL_TODOS = 'All';
export const ACTIVE_TODOS = 'Active';
export const COMPLETED_TODOS = 'Completed';
Loading