diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index ea969c4..82dab8f 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -2,11 +2,12 @@ const React = require('react'); const _ = require('lodash'); const cx = require('classnames'); -const Markdown = require('naturalcrit/markdown.js'); +const Markdown = require('homebrewery/markdown.js'); const ErrorBar = require('./errorBar/errorBar.jsx'); -//TODO: move to the brew renderer const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx') +const Store = require('homebrewery/brew.store.js'); + const PAGE_HEIGHT = 1056; const PPR_THRESHOLD = 50; @@ -14,24 +15,19 @@ const PPR_THRESHOLD = 50; const BrewRenderer = React.createClass({ getDefaultProps: function() { return { - text : '', + brewText : '', errors : [] }; }, getInitialState: function() { - const pages = this.props.text.split('\\page'); + const pages = this.props.brewText.split('\\page'); return { viewablePageNumber: 0, height : 0, isMounted : false, - - usePPR : true, - pages : pages, - usePPR : pages.length >= PPR_THRESHOLD, - - errors : [] + usePPR : pages.length >= PPR_THRESHOLD }; }, height : 0, @@ -49,7 +45,7 @@ const BrewRenderer = React.createClass({ componentWillReceiveProps: function(nextProps) { if(this.refs.pages && this.refs.pages.firstChild) this.pageHeight = this.refs.pages.firstChild.clientHeight; - const pages = nextProps.text.split('\\page'); + const pages = nextProps.brewText.split('\\page'); this.setState({ pages : pages, usePPR : pages.length >= PPR_THRESHOLD diff --git a/client/homebrew/brewRenderer/brewRenderer.smart.jsx b/client/homebrew/brewRenderer/brewRenderer.smart.jsx new file mode 100644 index 0000000..6f1d97d --- /dev/null +++ b/client/homebrew/brewRenderer/brewRenderer.smart.jsx @@ -0,0 +1,10 @@ +const Store = require('homebrewery/brew.store.js'); +const BrewRenderer = require('./brewRenderer.jsx'); + + +module.exports = Store.createSmartComponent(BrewRenderer, () => { + return { + brewText : Store.getBrewText(), + errors : Store.getErrors() + } +}); \ No newline at end of file diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 2f79078..3a22c3d 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -6,7 +6,6 @@ const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); const SnippetBar = require('./snippetbar/snippetbar.jsx'); const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); - const splice = function(str, index, inject){ return str.slice(0, index) + inject + str.slice(index); }; @@ -138,8 +137,3 @@ const Editor = React.createClass({ module.exports = Editor; - - - - - diff --git a/client/homebrew/editor/editor.smart.jsx b/client/homebrew/editor/editor.smart.jsx new file mode 100644 index 0000000..79ca834 --- /dev/null +++ b/client/homebrew/editor/editor.smart.jsx @@ -0,0 +1,13 @@ +const Actions = require('homebrewery/brew.actions.js'); +const Store = require('homebrewery/brew.store.js'); + +const Editor = require('./editor.jsx') + +module.exports = Store.createSmartComponent(Editor, ()=>{ + return { + value : Store.getBrewText(), + onChange : Actions.updateBrewText, + metadata : Store.getMetaData(), + onMetadataChange : Actions.updateMetaData, + }; +}); \ No newline at end of file diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index d4dcdfb..eb90542 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -3,12 +3,13 @@ const _ = require('lodash'); const cx = require('classnames'); const CreateRouter = require('pico-router').createRouter; +const Actions = require('homebrewery/brew.actions.js'); const HomePage = require('./pages/homePage/homePage.jsx'); const EditPage = require('./pages/editPage/editPage.jsx'); const UserPage = require('./pages/userPage/userPage.jsx'); const SharePage = require('./pages/sharePage/sharePage.jsx'); -const NewPage = require('./pages/newPage/newPage.jsx'); +const NewPage = require('./pages/newPage/newPage.jsx'); const ErrorPage = require('./pages/errorPage/errorPage.jsx'); const PrintPage = require('./pages/printPage/printPage.jsx'); @@ -20,21 +21,21 @@ const Homebrew = React.createClass({ welcomeText : '', changelog : '', version : '0.0.0', - account : null, - brew : { - title : '', - text : '', - shareId : null, - editId : null, - createdAt : null, - updatedAt : null, - } + account : undefined, + brew : {} }; }, componentWillMount: function() { + //TODO: remove global.account = this.props.account; global.version = this.props.version; + Actions.init({ + version : this.props.version, + brew : this.props.brew, + account : this.props.account + }); + Router = CreateRouter({ '/edit/:id' : (args) => { diff --git a/client/homebrew/navbar/account.navitem.jsx b/client/homebrew/navbar/account.navitem.jsx index 9f5829c..6b33f90 100644 --- a/client/homebrew/navbar/account.navitem.jsx +++ b/client/homebrew/navbar/account.navitem.jsx @@ -8,9 +8,11 @@ module.exports = function(props){ } let url = ''; + /* if(typeof window !== 'undefined'){ url = window.location.href } + */ return login diff --git a/client/homebrew/navbar/navbar.jsx b/client/homebrew/navbar/navbar.jsx index 8ab3856..b3bf05f 100644 --- a/client/homebrew/navbar/navbar.jsx +++ b/client/homebrew/navbar/navbar.jsx @@ -2,24 +2,20 @@ const React = require('react'); const _ = require('lodash'); const Nav = require('naturalcrit/nav/nav.jsx'); +const Store = require('homebrewery/brew.store.js'); const Navbar = React.createClass({ getInitialState: function() { return { - //showNonChromeWarning : false, - ver : '0.0.0' + showNonChromeWarning : false, }; }, - componentDidMount: function() { //const isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); this.setState({ - //showNonChromeWarning : !isChrome, - ver : window.version + showNonChromeWarning : !isChrome, }) }, - -/* renderChromeWarning : function(){ if(!this.state.showNonChromeWarning) return; return @@ -29,7 +25,6 @@ const Navbar = React.createClass({ }, -*/ render : function(){ return @@ -37,7 +32,7 @@ const Navbar = React.createClass({
The Homebrewery
- {`v${this.state.ver}`} + {`v${Store.getVersion()}`} {/*this.renderChromeWarning()*/}
diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index cc0e27b..3cd3a99 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -15,7 +15,8 @@ const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); const Editor = require('../../editor/editor.jsx'); const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); -const Markdown = require('naturalcrit/markdown.js'); +const Markdown = require('homebrewery/markdown.js'); + const SAVE_TIMEOUT = 3000; diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index a1ffecc..b5a34b1 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -1,7 +1,6 @@ const React = require('react'); const _ = require('lodash'); const cx = require('classnames'); -const request = require("superagent"); const Nav = require('naturalcrit/nav/nav.jsx'); const Navbar = require('../../navbar/navbar.jsx'); @@ -12,42 +11,34 @@ const AccountNavItem = require('../../navbar/account.navitem.jsx'); const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); -const Editor = require('../../editor/editor.jsx'); -const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); +const Editor = require('../../editor/editor.smart.jsx'); +const BrewRenderer = require('../../brewRenderer/brewRenderer.smart.jsx'); +const BrewInterface = require('homebrewery/brewInterface/brewInterface.jsx'); + + +const Actions = require('homebrewery/brew.actions.js'); +//const Store = require('homebrewery/brew.store.js'); const HomePage = React.createClass({ getDefaultProps: function() { return { welcomeText : '', - ver : '0.0.0' }; }, - getInitialState: function() { - return { - text: this.props.welcomeText - }; - }, - handleSave : function(){ - request.post('/api') - .send({ - text : this.state.text - }) - .end((err, res)=>{ - if(err) return; - var brew = res.body; - window.location = '/edit/' + brew.editId; - }); - }, - handleSplitMove : function(){ - this.refs.editor.update(); - }, - handleTextChange : function(text){ - this.setState({ - text : text + componentWillMount: function() { + Actions.init({ + brew : { + text : this.props.welcomeText + } }); }, + + handleSave : function(){ + Actions.saveNew(); + }, + renderNavbar : function(){ return @@ -70,15 +61,13 @@ const HomePage = React.createClass({ render : function(){ return
{this.renderNavbar()} -
- - - - +
-
+
Save current
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 25a0c1e..46d0fe2 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -3,7 +3,7 @@ const _ = require('lodash'); const cx = require('classnames'); const request = require("superagent"); -const Markdown = require('naturalcrit/markdown.js'); +const Markdown = require('homebrewery/markdown.js'); const Nav = require('naturalcrit/nav/nav.jsx'); const Navbar = require('../../navbar/navbar.jsx'); diff --git a/client/homebrew/pages/printPage/printPage.jsx b/client/homebrew/pages/printPage/printPage.jsx index b6ecfd8..91f1785 100644 --- a/client/homebrew/pages/printPage/printPage.jsx +++ b/client/homebrew/pages/printPage/printPage.jsx @@ -1,7 +1,7 @@ const React = require('react'); const _ = require('lodash'); const cx = require('classnames'); -const Markdown = require('naturalcrit/markdown.js'); +const Markdown = require('homebrewery/markdown.js'); const PrintPage = React.createClass({ getDefaultProps: function() { diff --git a/scripts/dev.js b/scripts/dev.js index 6fda537..c112e84 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -12,10 +12,8 @@ const Proj = require('./project.json'); Promise.resolve() .then(jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, './shared')) .then(less('homebrew', './shared')) - .then(jsx('admin', './client/admin/admin.jsx', Proj.libs, './shared')) .then(less('admin', './shared')) - .then(assets(Proj.assets, ['./shared', './client'])) .then(livereload()) .then(server('./server.js', ['server'])) diff --git a/shared/homebrewery/brew.actions.js b/shared/homebrewery/brew.actions.js new file mode 100644 index 0000000..1a9f99a --- /dev/null +++ b/shared/homebrewery/brew.actions.js @@ -0,0 +1,34 @@ +const dispatch = require('pico-flux').dispatch; + +const request = require('superagent'); +const Store = require('./brew.store.js'); + +const Actions = { + init : (initState) => { + Store.init(initState); + }, + setBrew : (brew) => { + dispatch('SET_BREW', brew); + }, + updateBrewText : (brewText) => { + dispatch('UPDATE_BREW_TEXT', brewText) + }, + updateMetaData : (meta) => { + dispatch('UPDATE_META', meta); + }, + + + + saveNew : () => { + //TODO: Maybe set the status? + request.post('/api') + .send(Store.getBrew()) + .end((err, res)=>{ + if(err) return; + const brew = res.body; + window.location = '/edit/' + brew.editId; + }); + } +}; + +module.exports = Actions; \ No newline at end of file diff --git a/shared/homebrewery/brew.store.js b/shared/homebrewery/brew.store.js new file mode 100644 index 0000000..e521d98 --- /dev/null +++ b/shared/homebrewery/brew.store.js @@ -0,0 +1,61 @@ +const _ = require('lodash'); +const flux = require('pico-flux'); + +const Markdown = require('homebrewery/markdown.js'); + +let State = { + version : '0.0.0', + + brew : { + text : '', + shareId : undefined, + editId : undefined, + createdAt : undefined, + updatedAt : undefined, + + title : '', + description : '', + tags : '', + published : false, + authors : [], + systems : [] + }, + + errors : [] +}; + +const Store = flux.createStore({ + SET_BREW : (brew) => { + State.brew = brew; + }, + UPDATE_BREW_TEXT : (brewText) => { + State.brew.text = brewText; + State.errors = Markdown.validate(brewText); + }, + UPDATE_META : (meta) => { + State.brew = _.merge({}, State.brew, meta); + } +}); + + +Store.init = (state)=>{ + State = _.merge({}, State, state); +}; +Store.getBrew = ()=>{ + return State.brew; +}; +Store.getBrewText = ()=>{ + return State.brew.text; +}; +Store.getMetaData = ()=>{ + return _.omit(State.brew, ['text']); +}; +Store.getErrors = ()=>{ + return State.errors; +}; + +Store.getVersion = ()=>{ + return State.version; +}; + +module.exports = Store; \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/brewEditor.jsx b/shared/homebrewery/brewEditor/brewEditor.jsx new file mode 100644 index 0000000..a8fa891 --- /dev/null +++ b/shared/homebrewery/brewEditor/brewEditor.jsx @@ -0,0 +1,121 @@ +const React = require('react'); +const _ = require('lodash'); +const cx = require('classnames'); + +const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); +const SnippetBar = require('./snippetbar/snippetbar.jsx'); +const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); + +const splice = function(str, index, inject){ + return str.slice(0, index) + inject + str.slice(index); +}; + +const SNIPPETBAR_HEIGHT = 25; + +const BrewEditor = React.createClass({ + getDefaultProps: function() { + return { + value : '', + onChange : ()=>{}, + + metadata : {}, + onMetadataChange : ()=>{}, + }; + }, + getInitialState: function() { + return { + showMetadataEditor: false + }; + }, + cursorPosition : { + line : 0, + ch : 0 + }, + + componentDidMount: function() { + this.updateEditorSize(); + this.highlightPageLines(); + window.addEventListener("resize", this.updateEditorSize); + }, + componentWillUnmount: function() { + window.removeEventListener("resize", this.updateEditorSize); + }, + + updateEditorSize : function() { + let paneHeight = this.refs.main.parentNode.clientHeight; + paneHeight -= SNIPPETBAR_HEIGHT + 1; + this.refs.codeEditor.codeMirror.setSize(null, paneHeight); + }, + + handleTextChange : function(text){ + this.props.onChange(text); + }, + handleCursorActivty : function(curpos){ + this.cursorPosition = curpos; + }, + handleInject : function(injectText){ + const lines = this.props.value.split('\n'); + lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText); + + this.handleTextChange(lines.join('\n')); + this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length); + }, + handgleToggle : function(){ + this.setState({ + showMetadataEditor : !this.state.showMetadataEditor + }) + }, + + //Called when there are changes to the editor's dimensions + update : function(){ + this.refs.codeEditor.updateSize(); + }, + + highlightPageLines : function(){ + if(!this.refs.codeEditor) return; + const codeMirror = this.refs.codeEditor.codeMirror; + + const lineNumbers = _.reduce(this.props.value.split('\n'), (r, line, lineNumber)=>{ + if(line.indexOf('\\page') !== -1){ + codeMirror.addLineClass(lineNumber, 'background', 'pageLine'); + r.push(lineNumber); + } + return r; + }, []); + return lineNumbers + }, + + renderMetadataEditor : function(){ + if(!this.state.showMetadataEditor) return; + return + }, + + render : function(){ + + this.highlightPageLines(); + + return( +
+ + {this.renderMetadataEditor()} + +
+ ); + } +}); + +module.exports = BrewEditor; + diff --git a/shared/homebrewery/brewEditor/brewEditor.less b/shared/homebrewery/brewEditor/brewEditor.less new file mode 100644 index 0000000..4d3cf4a --- /dev/null +++ b/shared/homebrewery/brewEditor/brewEditor.less @@ -0,0 +1,15 @@ + +.brewEditor{ + position : relative; + width : 100%; + .codeEditor{ + height : 100%; + + .pageLine{ + background-color: fade(@blue, 30%); + border-bottom : #333 solid 1px; + + + } + } +} \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/brewEditor.smart.jsx b/shared/homebrewery/brewEditor/brewEditor.smart.jsx new file mode 100644 index 0000000..2dc647c --- /dev/null +++ b/shared/homebrewery/brewEditor/brewEditor.smart.jsx @@ -0,0 +1,13 @@ +const Actions = require('homebrewery/brew.actions.js'); +const Store = require('homebrewery/brew.store.js'); + +const BrewEditor = require('./brewEditor.jsx') + +module.exports = Store.createSmartComponent(BrewEditor, ()=>{ + return { + value : Store.getBrewText(), + onChange : Actions.updateBrewText, + metadata : Store.getMetaData(), + onMetadataChange : Actions.updateMetaData, + }; +}); \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/metadataEditor/metadataEditor.jsx b/shared/homebrewery/brewEditor/metadataEditor/metadataEditor.jsx new file mode 100644 index 0000000..694e9db --- /dev/null +++ b/shared/homebrewery/brewEditor/metadataEditor/metadataEditor.jsx @@ -0,0 +1,175 @@ +const React = require('react'); +const _ = require('lodash'); +const cx = require('classnames'); +const request = require("superagent"); + +const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder'] + +const MetadataEditor = React.createClass({ + getDefaultProps: function() { + return { + metadata: { + editId : null, + title : '', + description : '', + tags : '', + published : false, + authors : [], + systems : [] + }, + onChange : ()=>{} + }; + }, + + handleFieldChange : function(name, e){ + this.props.onChange(_.merge({}, this.props.metadata, { + [name] : e.target.value + })) + }, + handleSystem : function(system, e){ + if(e.target.checked){ + this.props.metadata.systems.push(system); + }else{ + this.props.metadata.systems = _.without(this.props.metadata.systems, system); + } + this.props.onChange(this.props.metadata); + }, + handlePublish : function(val){ + this.props.onChange(_.merge({}, this.props.metadata, { + published : val + })); + }, + + handleDelete : function(){ + if(!confirm("are you sure you want to delete this brew?")) return; + if(!confirm("are you REALLY sure? You will not be able to recover it")) return; + + request.get('/api/remove/' + this.props.metadata.editId) + .send() + .end(function(err, res){ + window.location.href = '/'; + }); + }, + + getRedditLink : function(){ + const meta = this.props.metadata; + const title = `${meta.title} [${meta.systems.join(' ')}]`; + const text = `Hey guys! I've been working on this homebrew. I'd love your feedback. Check it out. + +**[Homebrewery Link](http://homebrewery.naturalcrit.com/share/${meta.shareId})**`; + + return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title)}&text=${encodeURIComponent(text)}`; + }, + + renderSystems : function(){ + return _.map(SYSTEMS, (val)=>{ + return + }); + }, + + renderPublish : function(){ + if(this.props.metadata.published){ + return + }else{ + return + } + }, + + renderDelete : function(){ + if(!this.props.metadata.editId) return; + + return
+ +
+ +
+
+ }, + + renderAuthors : function(){ + let text = 'None.'; + if(this.props.metadata.authors.length){ + text = this.props.metadata.authors.join(', '); + } + return
+ +
+ {text} +
+
+ }, + + renderShareToReddit : function(){ + if(!this.props.metadata.shareId) return; + + return
+ + +
+ }, + + render : function(){ + return
+
+ + +
+
+ +