diff --git a/index.html b/index.html index df9680c..c45b9bb 100644 --- a/index.html +++ b/index.html @@ -8,9 +8,13 @@
+
+ Page #1 Page #2 + + diff --git a/package.json b/package.json index fbdb4ed..a7cc31c 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,11 @@ "name": "webpack-react-workflow", "version": "0.1.0", "description": "A dummy project on how to integrate React and Webpack in a Web project", + "dependencies": { + "alt": "^0.17.3", + "node-uuid": "^1.4.3", + "react": "^0.13.3" + }, "devDependencies": { "autoprefixer": "^5.2.0", "babel-core": "^5.8.22", @@ -22,7 +27,6 @@ "mocha": "^2.2.5", "node-sass": "3.2.0", "postcss-loader": "^0.6.0", - "react": "^0.13.3", "react-hot-loader": "^1.2.8", "sass-loader": "^2.0.0", "style-loader": "^0.12.3", diff --git a/src/app.js b/src/app.js index 2424c01..5e21e8f 100644 --- a/src/app.js +++ b/src/app.js @@ -7,5 +7,13 @@ import Book from './book/book.js'; import Section from './book/section.jsx'; // eslint-disable-line no-unused-vars React.render(
, document.getElementById( 'heading-container' ) ); +import PersistentBrowserStore from './core/PersistentBrowserStore'; +import persist from './flux/libs/persist'; + +persist( PersistentBrowserStore ); + +import Todos from './todos/App.jsx'; // eslint-disable-line no-unused-vars +React.render( , document.getElementById( 'notes-container' ) ); + var book = new Book(); book.logSomething(); diff --git a/src/core/PersistentBrowserStore.js b/src/core/PersistentBrowserStore.js new file mode 100644 index 0000000..0d76e43 --- /dev/null +++ b/src/core/PersistentBrowserStore.js @@ -0,0 +1,13 @@ +export default class { + static get( key ) { + try { + return JSON.parse( localStorage.getItem( key ) ) + } catch( error ) { + return null + } + } + + static set( key, value ) { + localStorage.setItem( key, JSON.stringify( value ) ) + } +} diff --git a/src/flux/actions/NoteActions.js b/src/flux/actions/NoteActions.js new file mode 100644 index 0000000..a97f7c3 --- /dev/null +++ b/src/flux/actions/NoteActions.js @@ -0,0 +1,3 @@ +import alt from "../libs/alt" + +export default alt.generateActions("create", "update", "delete") diff --git a/src/flux/libs/alt.js b/src/flux/libs/alt.js new file mode 100644 index 0000000..2faeca7 --- /dev/null +++ b/src/flux/libs/alt.js @@ -0,0 +1,5 @@ +import Alt from "alt" + +let alt = new Alt() + +export default alt diff --git a/src/flux/libs/persist.js b/src/flux/libs/persist.js new file mode 100644 index 0000000..a98a436 --- /dev/null +++ b/src/flux/libs/persist.js @@ -0,0 +1,15 @@ +import alt from './alt' +import makeFinalStore from 'alt/utils/makeFinalStore' + +export default function( PersistentBrowserStore, storeName = 'app' ) { + let finalStore = makeFinalStore( alt ) + + alt.bootstrap( PersistentBrowserStore.get( storeName ) ) + + finalStore.listen( () => { + if ( PersistentBrowserStore.get( 'debug' ) ) { + return + } + PersistentBrowserStore.set( storeName, alt.takeSnapshot() ) + }) +} diff --git a/src/flux/stores/NoteStore.js b/src/flux/stores/NoteStore.js new file mode 100644 index 0000000..8227469 --- /dev/null +++ b/src/flux/stores/NoteStore.js @@ -0,0 +1,4 @@ +import alt from "../libs/alt" +import NoteStoreModel from "./NoteStoreModel" + +export default alt.createStore( NoteStoreModel, "NoteStore" ) diff --git a/src/flux/stores/NoteStoreModel.js b/src/flux/stores/NoteStoreModel.js new file mode 100644 index 0000000..45599fc --- /dev/null +++ b/src/flux/stores/NoteStoreModel.js @@ -0,0 +1,54 @@ +import uuid from "node-uuid" +import NoteActions from "../actions/NoteActions" + +export default class { + + constructor() { + this.bindActions( NoteActions ) + + this.notes = [] + } + + create( note ) { + let notes = this.notes + + note.id = uuid.v4() + + this.setState({ + notes: notes.concat( note ) + }) + } + + update( {id, task} ) { + let noteIndex = this.findNoteIndexById( id ) + if ( noteIndex < 0 ) { + return + } + + let notes = this.notes + notes[ noteIndex ].task = task + this.setState({ notes }) + } + + findNoteIndexById( id ) { + let notes = this.notes + let noteIndex = notes.findIndex( ( note ) => note.id === id ) + + if ( noteIndex < 0 ) { + console.warn( "Could not find note", id, notes ) + } + + return noteIndex + } + + delete( id ) { + let noteIndex = this.findNoteIndexById( id ) + if ( noteIndex < 0 ) { + return + } + + let notes = this.notes + notes.splice( noteIndex, 1 ) + this.setState({ notes }) + } +} diff --git a/src/todos/App.jsx b/src/todos/App.jsx new file mode 100644 index 0000000..4ad0bc0 --- /dev/null +++ b/src/todos/App.jsx @@ -0,0 +1,53 @@ +import React from "react" +import Button from "./Button.jsx" +import Notes from "./Notes.jsx" +import NoteActions from "../flux/actions/NoteActions.js" +import NoteStore from "../flux/stores/NoteStore.js" +import "./Todos.css" + +export default class extends React.Component { + constructor(props) { + super(props) + this.bindInstanceMethods() + + this.state = NoteStore.getState() + } + + bindInstanceMethods() { + this.setState = this.setState.bind( this ) + } + + componentDidMount() { + NoteStore.listen( this.setState ) + } + + componentWillUnmount() { + NoteStore.unlisten( this.setState ) + } + + render() { + let notes = this.state.notes + + return ( +
+
+ ) + } + + addNote() { + NoteActions.create( {task: "New task"} ) + } + + editNote( id, task ) { + NoteActions.update( {id, task} ) + } + + deleteNote( id ) { + NoteActions.delete( id ) + } +} diff --git a/src/todos/Button.jsx b/src/todos/Button.jsx new file mode 100644 index 0000000..0a86803 --- /dev/null +++ b/src/todos/Button.jsx @@ -0,0 +1,13 @@ +import React from "react" + +export default class extends React.Component { + + render() { + let text = this.props.text || "OK", + className = this.props.className || null + + return () + } +} diff --git a/src/todos/EditableTextBox.jsx b/src/todos/EditableTextBox.jsx new file mode 100644 index 0000000..b993332 --- /dev/null +++ b/src/todos/EditableTextBox.jsx @@ -0,0 +1,15 @@ +import React from "react" + +export default class extends React.Component { + + render() { + let autoFocus = this.props.autoFocus || true + + return () + } +} diff --git a/src/todos/Note.jsx b/src/todos/Note.jsx new file mode 100644 index 0000000..a2e7765 --- /dev/null +++ b/src/todos/Note.jsx @@ -0,0 +1,92 @@ +import React from "react" +import Button from "./Button.jsx" +import EditableTextBox from "./EditableTextBox.jsx" + +export default class extends React.Component { + constructor(props) { + super( props ) + this.bindInstanceMethods() + + this.state = { + editing: false + } + } + + bindInstanceMethods() { + let methods = [ + "startEditing", + "handleInputBlur", + "handleKeyPress", + "renderDelete", + "renderInput", + "renderTask" + ] + for ( let method of methods ) { + this[ method ] = this[ method ].bind( this ) + } + } + + render() { + let editing = this.state.editing + let renderedElement + if ( editing ) { + renderedElement = this.renderInput() + } else { + renderedElement = this.renderTask() + } + + return renderedElement + } + + renderTask() { + let renderedDelete + if ( this.props.onDeleteCompleted ) { + renderedDelete = this.renderDelete() + } + + return (
+ {this.props.task} + {renderedDelete} +
) + } + + renderDelete() { + return (