diff --git a/.gitignore b/.gitignore index 19df1caaec6f2820f897112ae32b30f14e954320..4c173947e1e5d3f007ee39f99f33e8ac4e48d575 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/* npm-debug.log public/assets/* +public/uploads/* db*/ diff --git a/README.md b/README.md index 5b5587dc654fd10c215285d6c198bb8b7afe27b6..9a868e06deab5c3ee8fc02d4c6f00cf1e272baf7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Preconditions -Node.js is a requirement, read about how to install it here: [https://nodejs.org/en/](https://nodejs.org/en/) +Node.js, version above or equal to 4.22, is a requirement, read about how to install it here: [https://nodejs.org/en/](https://nodejs.org/en/) # Install @@ -12,17 +12,23 @@ $ npm install # Start the server +To start the JS compilation and webserver, run: ```bash $ npm run dev +``` + +And then initialize your blog by running: +```bash $ ./bin/init.sh ``` -Point your browser to: http://localhost:3000 +Point your browser to: http://localhost:3000/admin/manager and all should be well. Visit http://localhost for the blog landing page. + +# Roadmap (14th of December, 2015) + +Next two weeks (until 1st of January 2016): -# Roadmap (23rd of November, 2015) +Permissions, roles and authentication. -Next week (23-27 November): +January: Collaboration, multiple concurrent users -1. Simple auth -2. A proper abstract display on the front page -3. Last write wins strategy for document updates diff --git a/app/components/Admin/Blogpost.jsx b/app/components/Admin/Blogpost.jsx index 91f82743023fe2e7a0f6bcea38b711d9f3930a7a..bd1054b4fc369db8fcbe2b57c48ed33ced38cb86 100644 --- a/app/components/Admin/Blogpost.jsx +++ b/app/components/Admin/Blogpost.jsx @@ -1,9 +1,9 @@ import React from 'react' -import { Button, Row, Col } from 'react-bootstrap' +import { Button } from 'react-bootstrap' import { LinkContainer } from 'react-router-bootstrap' import TextInput from './TextInput' -import '../../scss/components/_blogpost' +import '../../scss/components/Admin/blogpost' export default class Blogpost extends React.Component { constructor (props) { @@ -27,6 +27,7 @@ export default class Blogpost extends React.Component { _onPublish () { this.props.update(Object.assign(this.props.blogpost, { + published_at: new Date(), status: 'published' })) } @@ -46,7 +47,7 @@ export default class Blogpost extends React.Component { } render () { - const { blogpost } = this.props + const { blogpost, number } = this.props var input if (this.state.isEditing) { input = @@ -56,30 +57,57 @@ export default class Blogpost extends React.Component { value={blogpost.title} /> } + + var changePublished + if (blogpost.status === 'unpublished') { + changePublished = <Button title='Publish' aria-label='Publish' bsStyle='success' onClick={this._onPublish}> + <i className='fa fa-chain'></i> + </Button> + } else { + changePublished = <Button title='Unpublish' aria-label='Unpublish' bsStyle='warning' onClick={this._onUnpublish}> + <i className='fa fa-chain-broken'></i> + </Button> + } + + if (blogpost.published_at) { + blogpost.published_at = new Date(blogpost.published_at).toDateString() + } + return ( - <div className='blogpost'> - <Row key={blogpost._id}> - <Col xs={12} md={8}> - <label onDoubleClick={this._onDoubleClick}> - {blogpost.title} ({blogpost.status}) - </label> - {input} - </Col> - <Col xs={12} md={4}> - <LinkContainer to={`/admin/editor/${blogpost._id}`}> - <Button bsStyle='primary'>Edit this</Button> - </LinkContainer> - <Button bsStyle='success' onClick={this._onPublish}>Publish</Button> - <Button bsStyle='warning' onClick={this._onUnpublish}>Unpublish</Button> - <Button bsStyle='danger' onClick={this._onDestroyClick}>Delete</Button> - </Col> - </Row> - </div> + <tr className='blogpost' key={blogpost.key}> + <td> + {number} + </td> + <td> + <label onDoubleClick={this._onDoubleClick}> + {blogpost.title} + </label> + {input} + </td> + <td> + {blogpost.author} + </td> + <td> + {blogpost.published_at} ({blogpost.status}) + </td> + <td> + <LinkContainer to={`/admin/editor/${blogpost._id}`}> + <Button bsStyle='primary' title='Edit' aria-label='Edit'> + <i className='fa fa-pencil'></i> + </Button> + </LinkContainer> + {changePublished} + <Button bsStyle='danger' onClick={this._onDestroyClick} title='Delete' aria-label='Delete'> + <i className='fa fa-trash-o'></i> + </Button> + </td> + </tr> ) } } Blogpost.propTypes = { + number: React.PropTypes.number, blogpost: React.PropTypes.object, delete: React.PropTypes.func, update: React.PropTypes.func diff --git a/app/components/Admin/BlogpostCreator.jsx b/app/components/Admin/BlogpostCreator.jsx index 198f5727004c1a74fb0f29341b26d12291147437..7c2f7b14a75fe2c85cc101ebaed6dd2cb01701fe 100644 --- a/app/components/Admin/BlogpostCreator.jsx +++ b/app/components/Admin/BlogpostCreator.jsx @@ -1,28 +1,52 @@ import React from 'react' -import TextInput from './TextInput' - -import styles from '../../scss/components/_blogpostCreator' +// import TextInput from './TextInput' +import { Input, Button } from 'react-bootstrap' export default class BlogpostCreator extends React.Component { constructor (props) { super(props) - this._onSave = this._onSave.bind(this) + this.onSave = this.onSave.bind(this) + this.onChange = this.onChange.bind(this) } - _onSave (text) { + onSave (text) { this.props.create({ type: 'blogpost', - title: text, + title: this.state.title, + author: this.state.author, status: 'unpublished', source: '' }) } + onChange () { + this.setState({ + title: this.refs.title.getValue(), + author: this.refs.author.getValue() + }) + } + render () { return ( <div> - <h1 className={styles.entrybox__header}>Create a new blog post</h1> - <TextInput className={styles.entrybox__input} placeholder='Title' onSave={this._onSave} /> + <h3>Create a new blog post</h3> + <Input + type='text' + placeholder='One fine day...' + label='Title' + ref='title' + onChange={this.onChange} + /> + <Input + type='text' + placeholder='Benjamin Franklin' + label='Author' + ref='author' + onChange={this.onChange} + /> + <Button bsStyle='primary' onClick={this.onSave} title='Create' aria-label='Create'> + <i className='fa fa-plus'></i> Create + </Button> </div> ) } diff --git a/app/components/Admin/BlogpostList.jsx b/app/components/Admin/BlogpostList.jsx index cb72c10e5f93435bc0e1bd947d642cb85c2850d3..ef88d66d1d0d0569482d8017670eb71faeefe997 100644 --- a/app/components/Admin/BlogpostList.jsx +++ b/app/components/Admin/BlogpostList.jsx @@ -7,6 +7,7 @@ export default class BlogpostList extends React.Component { render () { const blogposts = this.props.blogposts.map((blogpost, key) => { return (<Blogpost + number={key + 1} key={blogpost._id} blogpost={blogpost} delete={this.props.delete} @@ -16,7 +17,20 @@ export default class BlogpostList extends React.Component { return ( <div className={styles['list']}> <h3 className={styles['header']}>Blog posts</h3> - {blogposts} + <table className='table table-hover'> + <thead> + <tr> + <th>#</th> + <th>Title</th> + <th>Author</th> + <th>Status</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + {blogposts} + </tbody> + </table> </div> ) } diff --git a/app/components/Admin/Editor.jsx b/app/components/Admin/Editor.jsx index 1a12f926bbb01d890e2f943d15b2928993ec5518..8713d094ec342bde23e51991ec93a3960dcd2b17 100644 --- a/app/components/Admin/Editor.jsx +++ b/app/components/Admin/Editor.jsx @@ -1,12 +1,12 @@ import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import * as Actions from '../actions' +import * as Actions from '../../actions' import _ from 'lodash' import React from 'react' import ReactQuill from 'react-quill' -import '../scss/components/_editor' +import '../../scss/components/_editor' class Editor extends React.Component { constructor (props) { diff --git a/app/components/Admin/SubstanceEditor.jsx b/app/components/Admin/SubstanceEditor.jsx deleted file mode 100644 index f89d4594756a52cf96e629457a4bc8334ad70667..0000000000000000000000000000000000000000 --- a/app/components/Admin/SubstanceEditor.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import React from 'react' -import LensWriter from 'lens/ReactLensWriter' -import { bindActionCreators } from 'redux' -import { connect } from 'react-redux' -import * as Actions from '../../actions' -import _ from 'lodash' - -// Styles -import '../../../node_modules/lens/styles/lens-writer.scss' -import '../../scss/components/_substanceEditor' - -export default class SubstanceEditor extends React.Component { - constructor (props) { - super(props) - this._onSave = this._onSave.bind(this) - } - - _onSave (content, callback) { - let fragment = Object.assign(this.props.fragment, { - source: content, - presentation: content - }) - this.props.actions.updateFragment(fragment) - callback(null, content) - } - - _onFileUpload (file, callback) { - return callback(null, null) - } - - render () { - let editor - let content - if (this.props.fragment.source === '') { - content = '<article xmlns="http://substance.io/science-article/0.1.0" lang="en"><metadata><title>' + - this.props.fragment.title + '</title><abstract>hello</abstract></metadata><resources></resources>' + - '<body><p id="p1">test</p></body></article>' - } else { - content = this.props.fragment.source - } - - if (this.props.fragment) { - editor = <LensWriter - content={content} - onSave={this._onSave} - onFileUpload={this._onFileUpload} - /> - } else { - editor = <p>Loading</p> - } - - return ( - <div> - {editor} - </div> - ) - } -} - -SubstanceEditor.propTypes = { - fragment: React.PropTypes.object, - actions: React.PropTypes.object -} - -function mapStateToProps (state) { - console.log(state) - return { - fragment: _.find(state.fragments, function (f) { - return f._id === state.router.params.id - }) - } -} - -function mapDispatchToProps (dispatch) { - return { - actions: bindActionCreators(Actions, dispatch) - } -} - -export default connect( - mapStateToProps, - mapDispatchToProps -)(SubstanceEditor) diff --git a/app/components/BlogRoll/Blogpost.jsx b/app/components/BlogRoll/Blogpost.jsx index 80f069958b94ab23ac0ece314f189ea8022eabcc..1b042f2808d5dd23580739b954f463dc2f5bc308 100644 --- a/app/components/BlogRoll/Blogpost.jsx +++ b/app/components/BlogRoll/Blogpost.jsx @@ -2,8 +2,6 @@ import React from 'react' import { Row, Col } from 'react-bootstrap' import { LinkContainer } from 'react-router-bootstrap' -import '../../scss/components/_blogpost' - export default class Blogpost extends React.Component { render () { const { blogpost } = this.props diff --git a/app/components/BlogRoll/LensBlogpostSummary.jsx b/app/components/BlogRoll/LensBlogpostSummary.jsx deleted file mode 100644 index 61d4a7979c6b5df1ac63a47c11efb6b158cc97ed..0000000000000000000000000000000000000000 --- a/app/components/BlogRoll/LensBlogpostSummary.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react' -import '../../scss/components/_blogpost' -import { Row, Col } from 'react-bootstrap' -import { LinkContainer } from 'react-router-bootstrap' - -export default class LensBlogpostSummary extends React.Component { - render () { - const { blogpost } = this.props - - return ( - <div className='blogpost'> - <Row key={blogpost._id}> - <Col xs={12} md={8} mdOffset={2}> - <h2>{blogpost.title}</h2> - <div dangerouslySetInnerHTML={{__html: blogpost.presentation}}></div> - <LinkContainer to={`/${blogpost._id}`}><a>Read more</a></LinkContainer> - </Col> - </Row> - </div> - ) - } -} - -LensBlogpostSummary.propTypes = { - blogpost: React.PropTypes.object -} diff --git a/app/containers/Admin.jsx b/app/containers/Admin.jsx index f16c2c9dddcfee2f2aeff59ef32b8c42b7132ebf..327a499ec29db1cc959ee9e1f784308832da233c 100644 --- a/app/containers/Admin.jsx +++ b/app/containers/Admin.jsx @@ -16,7 +16,9 @@ class Admin extends Component { const { children } = this.props return ( <div> - <Navigation /> + <div className='bootstrap'> + <Navigation/> + </div> {children} </div> ) diff --git a/app/containers/BlogManager.jsx b/app/containers/Admin/BlogManager.jsx similarity index 57% rename from app/containers/BlogManager.jsx rename to app/containers/Admin/BlogManager.jsx index d666048074a1ed840c7e9b9a0b659bf3b1675e19..8366552238126396e8d622cacb4e1740ffe3f179 100644 --- a/app/containers/BlogManager.jsx +++ b/app/containers/Admin/BlogManager.jsx @@ -1,11 +1,11 @@ import React from 'react' import { Grid } from 'react-bootstrap' -import BlogpostList from '../components/Admin/BlogpostList' -import BlogpostCreator from '../components/Admin/BlogpostCreator' +import BlogpostList from '../../components/Admin/BlogpostList' +import BlogpostCreator from '../../components/Admin/BlogpostCreator' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import styles from '../scss/components/_manage' -import * as Actions from '../actions' +import styles from '../../scss/components/_manage' +import * as Actions from '../../actions' class BlogManager extends React.Component { constructor (props) { @@ -15,15 +15,17 @@ class BlogManager extends React.Component { render () { const { blog, blogposts, actions } = this.props return ( - <Grid> - <div blog={blog} className={styles.vote}> - <BlogpostCreator create={actions.createFragment} /> - <BlogpostList - update={actions.updateFragment} - delete={actions.deleteFragment} - blogposts={blogposts} /> - </div> - </Grid> + <div className='bootstrap'> + <Grid> + <div blog={blog} className={styles.vote}> + <BlogpostList + update={actions.updateFragment} + delete={actions.deleteFragment} + blogposts={blogposts} /> + <BlogpostCreator create={actions.createFragment} /> + </div> + </Grid> + </div> ) } } diff --git a/app/containers/Admin/EditorWrapper.jsx b/app/containers/Admin/EditorWrapper.jsx new file mode 100644 index 0000000000000000000000000000000000000000..82d974687560b608e2f96cae7a2d61db5ccd1f3d --- /dev/null +++ b/app/containers/Admin/EditorWrapper.jsx @@ -0,0 +1,73 @@ +import React from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import * as Actions from '../../actions' +import _ from 'lodash' +import fetch from 'isomorphic-fetch' + +// Which editor component to import? +import Editor from 'pubsweet-substance-components/Writer' +// import Editor from '../../../node_modules/pubsweet-components/QuillEditor' + +export default class EditorWrapper extends React.Component { + constructor (props) { + super(props) + } + + uploadFile (file, callback) { + var reader = new FileReader() //eslint-disable-line + var form = new FormData() //eslint-disable-line + form.append('file', file) + + fetch('/api/upload', { method: 'POST', body: form }) + .then(function (res) { + return res.text() + }).then(function (text) { + return callback(null, text) + }) + } + render () { + let editor + + if (this.props.fragment) { + editor = <Editor + fragment={this.props.fragment} + save={this.props.actions.updateFragment} + uploadFile={this.uploadFile} + /> + } else { + editor = <p>Loading</p> + } + + return ( + <div> + {editor} + </div> + ) + } +} + +EditorWrapper.propTypes = { + fragment: React.PropTypes.object, + actions: React.PropTypes.object +} + +function mapStateToProps (state) { + console.log(state) + return { + fragment: _.find(state.fragments, function (f) { + return f._id === state.router.params.id + }) + } +} + +function mapDispatchToProps (dispatch) { + return { + actions: bindActionCreators(Actions, dispatch) + } +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(EditorWrapper) diff --git a/app/containers/BlogRoll.jsx b/app/containers/Blog.jsx similarity index 86% rename from app/containers/BlogRoll.jsx rename to app/containers/Blog.jsx index 8e54caa03d25658a7b214aa6e381e6a40e6106cf..233623d10eb0fec443871c73f57130ae0fc2eaf3 100644 --- a/app/containers/BlogRoll.jsx +++ b/app/containers/Blog.jsx @@ -6,9 +6,9 @@ import '../scss/main' import * as Actions from '../actions' import { bindActionCreators } from 'redux' -import Blogpost from '../components/BlogRoll/LensBlogpostSummary' +import BlogpostSummary from 'pubsweet-substance-components/Summary' -class BlogRoll extends React.Component { +class Blog extends React.Component { constructor (props) { super(props) this.props.actions.hydrate() @@ -17,9 +17,9 @@ class BlogRoll extends React.Component { render () { var fragments = this.props.fragments.map(function (blogpost) { if (blogpost.status === 'published') { - return (<Blogpost + return (<BlogpostSummary key={blogpost._id} - blogpost={blogpost} + fragment={blogpost} />) } }) @@ -31,7 +31,7 @@ class BlogRoll extends React.Component { } } -BlogRoll.propTypes = { +Blog.propTypes = { // Data collection: React.PropTypes.object, fragments: React.PropTypes.array, @@ -62,4 +62,4 @@ function mapDispatchToProps (dispatch) { export default connect( mapStateToProps, mapDispatchToProps -)(BlogRoll) +)(Blog) diff --git a/app/components/BlogRoll/LensBlogpost.jsx b/app/containers/BlogpostWrapper.jsx similarity index 77% rename from app/components/BlogRoll/LensBlogpost.jsx rename to app/containers/BlogpostWrapper.jsx index 29bdd7295a4ac5e8d83c29b20a1b88208cd46316..18384c7413eac979b3b93006b83e6f4deb688905 100644 --- a/app/components/BlogRoll/LensBlogpost.jsx +++ b/app/containers/BlogpostWrapper.jsx @@ -1,16 +1,15 @@ import React from 'react' -import LensReader from 'lens/ReactLensReader' -import '../../scss/components/_blogpost' import _ from 'lodash' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { pushState } from 'redux-router' -import * as Actions from '../../actions' +import * as Actions from '../actions' -// Styles -import '../../../node_modules/lens/styles/lens-reader.scss' +// Which reader to use? +import Blogpost from 'pubsweet-substance-components/Reader' +// import Blogpost from 'pubsweet-components/QuillReader' -export default class LensBlogpost extends React.Component { +class BlogpostWrapper extends React.Component { constructor (props) { super(props) this.props.actions.hydrate() @@ -22,7 +21,7 @@ export default class LensBlogpost extends React.Component { if (blogpost) { return ( <div className='blogpost'> - <LensReader content={blogpost.source} /> + <Blogpost content={blogpost.source} /> </div> ) } else { @@ -33,7 +32,7 @@ export default class LensBlogpost extends React.Component { } } -LensBlogpost.propTypes = { +BlogpostWrapper.propTypes = { // Data blogpost: React.PropTypes.object, // Injected by React Redux @@ -64,4 +63,4 @@ function mapDispatchToProps (dispatch) { export default connect( mapStateToProps, mapDispatchToProps -)(LensBlogpost) +)(BlogpostWrapper) diff --git a/app/index.html b/app/index.html index bcfd5cd696c31e7b7eb694761bb21b712e488bdb..940c4b0fae158136febb99c74f8e1fa364b4033f 100644 --- a/app/index.html +++ b/app/index.html @@ -2,8 +2,9 @@ <html> <head> <meta charset="utf-8"> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"><!-- + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/> --> + <!-- <link rel="stylesheet" href="/assets/bootstrap.css"/> --> </head> <body> <div id="root"></div> diff --git a/app/routes.jsx b/app/routes.jsx index 16ee657d51fccc936760476b5cf49dd916131518..33a30ae55eb906c7ab080e60f83a2907d82710ed 100644 --- a/app/routes.jsx +++ b/app/routes.jsx @@ -4,16 +4,16 @@ import { Route } from 'react-router' // Admin import Admin from './containers/Admin' import About from './components/Admin/About' -import BlogManager from './containers/BlogManager' -import Editor from './components/Admin/SubstanceEditor' +import BlogManager from './containers/Admin/BlogManager' +import Editor from './containers/Admin/EditorWrapper' // Public -import BlogRoll from './containers/BlogRoll' -import Blogpost from './components/BlogRoll/LensBlogpost' +import Blog from './containers/Blog' +import Blogpost from './containers/BlogpostWrapper' export default ( <Route> - <Route path='/' component={BlogRoll}/> + <Route path='/' component={Blog}/> <Route path='/admin' component={Admin}> <Route path='manager' component={BlogManager} /> <Route path='editor/:id' component={Editor} /> diff --git a/app/scss/components/Admin/blogpost.scss b/app/scss/components/Admin/blogpost.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/scss/components/_blogpost.scss b/app/scss/components/_blogpost.scss deleted file mode 100644 index 38886c96d0bb9613e5154d55b23a70afa10cc5b8..0000000000000000000000000000000000000000 --- a/app/scss/components/_blogpost.scss +++ /dev/null @@ -1,3 +0,0 @@ -.blogpost { - padding-bottom: 2em; -} diff --git a/app/scss/components/_substanceEditor.scss b/app/scss/components/_substanceEditor.scss deleted file mode 100644 index 0780f1ac047ed9926379d93e13fd714da16d6b12..0000000000000000000000000000000000000000 --- a/app/scss/components/_substanceEditor.scss +++ /dev/null @@ -1,19 +0,0 @@ -// .content-tools-component, .le-main, .le-workspace, .lc-writer { -// top: 52px; -// } - -// .content-panel-component { -// top: 92px; -// } - -// .panel-content-inner { -// z-index: 2; -// } - -// .toc-panel-component, .le-resource { -// top: 92px; -// } - -.lc-writer { - top: 52px; -} diff --git a/app/scss/main.scss b/app/scss/main.scss index 01f3057e69f8b76314640b1d410c8d29b83c1589..e2a1cbfae4a9aaabfe2a94dae4d71627dbf2763f 100644 --- a/app/scss/main.scss +++ b/app/scss/main.scss @@ -1,3 +1,9 @@ body, html { overflow: normal; } + +$icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/'; +.bootstrap { + @import '~bootstrap-sass/assets/stylesheets/_bootstrap.scss'; +} + diff --git a/bin/webpack_server.js b/bin/webpack_server.js index 5d49e18e079e18f35d33c19b37ea7440f38cc032..ebc85fad9b765f341d5449950f75a959973ab532 100644 --- a/bin/webpack_server.js +++ b/bin/webpack_server.js @@ -11,21 +11,8 @@ var webpackConfig = require('../webpack/webpack.dev.config.js') module.exports = function () { // Fire up webpack and pass in the configuration file we created - var bundleStart = null var compiler = webpack(webpackConfig) - // Give notice to the terminal when it starts bundling - // and set the time it started - compiler.plugin('compile', function () { - console.log('Bundling ...') - bundleStart = Date.now() - }) - - // Give notice when it is done compiling, including the time it took. - compiler.plugin('done', function () { - console.log('Bundled in ' + (Date.now() - bundleStart) + 'ms!') - }) - var bundler = new webpackDevServer(compiler, { // Tell webpack to serve our bundled application from the build path. When proxying: // http://localhost:3000/assets -> http://localhost:3001/assets diff --git a/package.json b/package.json index aecb1a422e22a69140687a30412f3a91e12592e7..90b72e8eb2247c85e63b28c0ea455a942364d1ed 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test": "NODE_ENV=test ./node_modules/.bin/mocha test/*.js -R nyan", "eslint": "eslint" }, + "engines" : { "node" : ">=4.2.2" }, "dependencies": { "babel-core": "^5.5.4", "babel-loader": "^5.1.4", @@ -17,45 +18,44 @@ "bootstrap-sass": "^3.3.5", "cookie-parser": "~1.3.5", "css-loader": "^0.16.0", - "file-loader": "^0.8.4", - "html-loader": "^0.3.0", - "json-loader": "^0.5.3", - "url-loader": "^0.5.6", "debug": "~2.2.0", "dotenv": "^1.2.0", "express": "~4.13.1", "extract-text-webpack-plugin": "^0.8.1", + "file-loader": "^0.8.4", + "form-data": "^0.2.0", "history": "^1.9.1", + "html-loader": "^0.3.0", "immutable": "^3.7.4", + "isomorphic-fetch": "^2.1.1", "jade": "~1.11.0", "jquery": "^2.1.4", + "json-loader": "^0.5.3", + "leveldown": "^1.4.1", "lodash": "^3.9.3", "morgan": "~1.6.1", + "multer": "^1.1.0", "node-sass": "^3.1.2", "object-assign": "^4.0.1", - "isomorphic-fetch": "^2.1.1", + "pouchdb": "^5.0.0", + "pouchdb-find": "^0.5.0", + "pubsweet-substance-components": "git+ssh://git@gitlab.coko.foundation/pubsweet/substance-components#master", "react": "^0.14.0", "react-bootstrap": "^0.25.100-react-pre.1", "react-dom": "^0.14.0-rc1", "react-helmet": "^1.0.1", - "react-quill": "jure/react-quill", + "react-redux": "^4.0.0", "react-router": "^1.0.0-rc3", "react-router-bootstrap": "^0.19.0", - "react-redux": "^4.0.0", "redux-logger": "^2.0.2", "redux-router": "^1.0.0-beta3", "redux-thunk": "^0.1.0", "sass-loader": "^3.0.0", + "script-loader": "^0.6.1", "serve-favicon": "~2.3.0", "style-loader": "^0.12.3", - "script-loader": "^0.6.1", - "lens-writer": "substance/lens#dev", - "trix": "^0.9.0", - "simplemde": "^1.8.0", - "webpack": "^1.12.2", - "pouchdb": "^5.0.0", - "leveldown": "^1.4.1", - "pouchdb-find": "^0.5.0" + "url-loader": "^0.5.6", + "webpack": "^1.12.2" }, "devDependencies": { "babel-eslint": "^4.1.1", diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css deleted file mode 100644 index 9453385b9916ce9bc5e88d2f5d8cd8a554223590..0000000000000000000000000000000000000000 --- a/public/stylesheets/style.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - padding: 50px; - font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; -} - -a { - color: #00B7FF; -} diff --git a/routes/api.js b/routes/api.js index 3a8e61139f746f91eb009ed36a3c91de87c5fb70..8a09734c6a52ddcd6947d8822347a6405c7779a9 100644 --- a/routes/api.js +++ b/routes/api.js @@ -156,4 +156,15 @@ api.delete('/collection/fragment', function (req, res) { }) }) +// File upload API +var multer = require('multer') +var upload = multer({ + dest: 'public/uploads/', + limits: {fileSize: 1000000, files: 1} +}) +api.post('/upload', upload.single('file'), function (req, res, next) { + console.log(req.file) + return res.send(req.file.path.replace(/^public/, '')) +}) + module.exports = api diff --git a/webpack/webpack.dev.config.js b/webpack/webpack.dev.config.js index f15236518b8b97e8f175fba0f6942f0fb06b87bd..b0609e0175b33c6deddfd3dffb5cd57018fa083a 100644 --- a/webpack/webpack.dev.config.js +++ b/webpack/webpack.dev.config.js @@ -8,6 +8,8 @@ var publicPath = 'http://localhost:3001/assets/' var WEBPACK_HOST = 'localhost' var WEBPACK_PORT = 3001 +// We're including JSX components from our components package, +// but excluding its node_modules. var commonLoaders = [ { test: /\.js$|\.jsx$/, @@ -15,7 +17,20 @@ var commonLoaders = [ include: [ path.join(__dirname, '..', 'app'), path.join(__dirname, '..', 'routes'), - path.join(__dirname, '..', 'app.js') + path.join(__dirname, '..', 'app.js'), + path.join(__dirname, + '..', + 'node_modules', + 'pubsweet-substance-components' + ) + ], + exclude: [ + path.join(__dirname, + '..', + 'node_modules', + 'pubsweet-substance-components', + 'node_modules' + ) ] }, { test: /\.png$/, loader: 'url-loader' }, @@ -47,7 +62,7 @@ module.exports = [ // The output path from the view of the Javascript publicPath: publicPath }, - devtool: 'eval-source-map', + devtool: 'inline-source-map', module: { preLoaders: [{ test: /\.js$|\.jsx$/,