diff --git a/client/homebrew/navbar/issue.navitem.jsx b/client/homebrew/navbar/issue.navitem.jsx index 3631ce7..60adf4e 100644 --- a/client/homebrew/navbar/issue.navitem.jsx +++ b/client/homebrew/navbar/issue.navitem.jsx @@ -2,7 +2,12 @@ var React = require('react'); var Nav = require('naturalcrit/nav/nav.jsx'); module.exports = function(props){ - return + return report issue }; \ No newline at end of file diff --git a/client/homebrew/navbar/patreon.navitem.jsx b/client/homebrew/navbar/patreon.navitem.jsx index a7a53d3..36a51d1 100644 --- a/client/homebrew/navbar/patreon.navitem.jsx +++ b/client/homebrew/navbar/patreon.navitem.jsx @@ -3,6 +3,7 @@ var Nav = require('naturalcrit/nav/nav.jsx'); module.exports = function(props){ return { diff --git a/client/homebrew/pages/hijackPrint.js b/client/homebrew/pages/hijackPrint.js deleted file mode 100644 index e19f5fb..0000000 --- a/client/homebrew/pages/hijackPrint.js +++ /dev/null @@ -1,12 +0,0 @@ -//TODO: Depricate - -module.exports = function(shareId){ - return function(event){ - event = event || window.event; - if((event.ctrlKey || event.metaKey) && event.keyCode == 80){ - var win = window.open(`/homebrew/print/${shareId}?dialog=true`, '_blank'); - win.focus(); - event.preventDefault(); - } - }; -}; \ No newline at end of file diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 9f4dac3..08039f4 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -24,10 +24,10 @@ const HomePage = React.createClass({ renderNavbar : function(){ return - - - - Changelog + + + + What's new diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 9d7c028..2560c8b 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -47,7 +47,7 @@ const NewPage = React.createClass({ get PDF - + diff --git a/client/homebrew/pages/printPage/printPage.jsx b/client/homebrew/pages/printPage/printPage.jsx index 70ab71a..1643b23 100644 --- a/client/homebrew/pages/printPage/printPage.jsx +++ b/client/homebrew/pages/printPage/printPage.jsx @@ -3,38 +3,62 @@ const _ = require('lodash'); const cx = require('classnames'); const Markdown = require('homebrewery/markdown.js'); +const Headtags = require('vitreum/headtags'); + const PrintPage = React.createClass({ getDefaultProps: function() { return { query : {}, brew : { text : '', + style : '' } }; }, getInitialState: function() { return { - brewText: this.props.brew.text + brew: this.props.brew }; }, componentDidMount: function() { if(this.props.query.local){ - this.setState({ brewText : localStorage.getItem(this.props.query.local)}); + try{ + this.setState({ + brew : JSON.parse( + localStorage.getItem(this.props.query.local) + ) + }); + }catch(e){} } if(this.props.query.dialog) window.print(); }, + //TODO: Print page shouldn't replicate functionality in brew renderer + renderStyle : function(){ + if(!this.state.brew.style) return; + return + }, renderPages : function(){ - return _.map(this.state.brewText.split('\\page'), (page, index) => { + return _.map(this.state.brew.text.split('\\page'), (page, index) => { return
; }); }, + renderPrintInstructions : function(){ + return
+ Hey, I'm really cool instructions!!!!! + +
+ }, + render : function(){ - return
+ return
+ {this.state.brew.title} + {this.renderPrintInstructions()} + {this.renderStyle()} {this.renderPages()}
} diff --git a/client/homebrew/pages/printPage/printPage.less b/client/homebrew/pages/printPage/printPage.less index 0d9e7b6..6430ef7 100644 --- a/client/homebrew/pages/printPage/printPage.less +++ b/client/homebrew/pages/printPage/printPage.less @@ -1,3 +1,17 @@ -.printPage{ +.printPage{ + position : relative; + @media print{ + .printInstructions{ + display : none; + } + } + .printInstructions{ + position : absolute; + top : 0px; + right : 0px; + z-index : 100000; + padding : 30px; + background-color : @blue; + } } \ No newline at end of file diff --git a/package.json b/package.json index c7dd14c..c8ef3e3 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,12 @@ "dev": "node scripts/dev.js", "quick": "node scripts/quick.js", "build": "node scripts/build.js", - "phb": "node scripts/phb.js", "populate": "node scripts/populate.js", "prod": "set NODE_ENV=production&& npm run build", "postinstall": "npm run build", "start": "node server.js", + "snippet": "nodemon scripts/snippet.test.js", + "todo": "./node_modules/.bin/fixme -i node_modules/** -i build/**", "test": "mocha tests", "test:dev": "nodemon -x mocha tests || exit 0", "test:markdown": "nodemon -x mocha tests/markdown.test.js || exit 0" @@ -46,6 +47,7 @@ "chai": "^3.5.0", "chai-as-promised": "^6.0.0", "chai-subset": "^1.4.0", + "fixme": "^0.4.3", "mocha": "^3.2.0", "supertest": "^2.0.1", "supertest-as-promised": "^4.0.2" diff --git a/scripts/build.js b/scripts/build.js index 2f6af1a..fbdce82 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -2,19 +2,20 @@ const label = 'build'; console.time(label); const clean = require('vitreum/steps/clean.js'); -const jsx = require('vitreum/steps/jsx.js').partial; -const lib = require('vitreum/steps/libs.js').partial; -const less = require('vitreum/steps/less.js').partial; -const asset = require('vitreum/steps/assets.js').partial; +const jsx = require('vitreum/steps/jsx.js'); +const lib = require('vitreum/steps/libs.js'); +const less = require('vitreum/steps/less.js'); +const asset = require('vitreum/steps/assets.js'); const Proj = require('./project.json'); -clean() - .then(lib(Proj.libs)) - .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(asset(Proj.assets, ['./shared', './client'])) - .then(console.timeEnd.bind(console, label)) +Promise.resolve() + .then(()=>clean()) + .then(()=>lib(Proj.libs)) + .then(()=>jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, ['./shared'])) + .then((deps)=>less('homebrew', ['./shared'], deps)) + .then(()=>jsx('admin', './client/admin/admin.jsx', Proj.libs, ['./shared'])) + .then((deps)=>less('admin', ['./shared'], deps)) + .then(()=>asset(Proj.assets, ['./shared', './client'])) + .then(()=>console.timeEnd.bind(console, label)) .catch(console.error); \ No newline at end of file diff --git a/scripts/dev.js b/scripts/dev.js index c112e84..b79137a 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -1,21 +1,21 @@ const label = 'dev'; console.time(label); -const jsx = require('vitreum/steps/jsx.watch.js').partial; -const less = require('vitreum/steps/less.watch.js').partial; -const assets = require('vitreum/steps/assets.watch.js').partial; -const server = require('vitreum/steps/server.watch.js').partial; -const livereload = require('vitreum/steps/livereload.js').partial; +const jsx = require('vitreum/steps/jsx.watch.js'); +const less = require('vitreum/steps/less.watch.js'); +const assets = require('vitreum/steps/assets.watch.js'); +const server = require('vitreum/steps/server.watch.js'); +const livereload = require('vitreum/steps/livereload.js'); 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'])) - .then(console.timeEnd.bind(console, label)) + .then(()=>jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, './shared')) + .then((deps)=>less('homebrew', './shared', deps)) + .then(()=>jsx('admin', './client/admin/admin.jsx', Proj.libs, './shared')) + .then((deps)=>less('admin', './shared', deps)) + .then(()=>assets(Proj.assets, ['./shared', './client'])) + .then(()=>livereload()) + .then(()=>server('./server.js', ['server'])) + .then(()=>console.timeEnd.bind(console, label)) .catch(console.error) \ No newline at end of file diff --git a/scripts/notes.js b/scripts/notes.js new file mode 100644 index 0000000..0571bc0 --- /dev/null +++ b/scripts/notes.js @@ -0,0 +1,8 @@ + +require('fixme')({ + path: process.cwd(), + ignored_directories: ['node_modules/**', '.git/**', 'build/**'], + file_patterns: ['**/*.js', '**/*.jsx', '**/*.less'], + file_encoding: 'utf8', + line_length_limit: 200 +}); \ No newline at end of file diff --git a/scripts/phb.js b/scripts/phb.js deleted file mode 100644 index 945a20e..0000000 --- a/scripts/phb.js +++ /dev/null @@ -1,16 +0,0 @@ -//DEPRICATE - -const less = require('less'); -const fs = require('fs'); - - -console.log('you should not b using this'); - - -less.render(fs.readFileSync('./client/homebrew/phbStyle/phb.style.less', 'utf8'), {compress : true}) - .then((output) => { - fs.writeFileSync('./phb.standalone.css', output.css); - console.log('phb.standalone.css created!'); - }, (err) => { - console.error(err); - }); \ No newline at end of file diff --git a/scripts/snippet.test.js b/scripts/snippet.test.js new file mode 100644 index 0000000..35aa669 --- /dev/null +++ b/scripts/snippet.test.js @@ -0,0 +1,8 @@ +const snippets = require('../shared/homebrewery/snippets'); + +console.log(snippets); + +//console.log(snippets.brew.spell()); +//console.log(snippets.brew.table()); + +console.log(snippets.brew.noncasterTable()); \ No newline at end of file diff --git a/server/interface.routes.js b/server/interface.routes.js index 7bf756c..0353038 100644 --- a/server/interface.routes.js +++ b/server/interface.routes.js @@ -8,10 +8,11 @@ const mw = require('./middleware.js'); const statics = { - welcomeBrew : fs.readFileSync('./welcome.brew.md', 'utf8'), - changelog : fs.readFileSync('./changelog.md', 'utf8'), - testBrew : fs.readFileSync('./statics/test.brew.md', 'utf8'), + welcomeBrew : fs.readFileSync('./statics/welcome.brew.md', 'utf8'), + changelog : fs.readFileSync('./statics/changelog.md', 'utf8'), + faq : fs.readFileSync('./statics/faq.md', 'utf8'), + testBrew : fs.readFileSync('./statics/test.brew.md', 'utf8'), oldTest : fs.readFileSync('./statics/oldTest.brew.md', 'utf8'), }; @@ -44,6 +45,7 @@ router.get('/edit/:editId', mw.loadBrew, renderPage); //Print Page router.get('/print/:shareId', mw.viewBrew, renderPage); +router.get('/print', renderPage); //Source page router.get('/source/:sharedId', mw.viewBrew, (req, res, next)=>{ @@ -81,6 +83,17 @@ router.get('/changelog', (req, res, next) => { return next(); }, renderPage); +//faq Page +router.get('/faq', (req, res, next) => { + req.brew = { + text : statics.faq, + title : 'FAQ', + + editId : true + }; + return next(); +}, renderPage); + //New Page router.get('/new', renderPage); diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/classfeature.gen.js b/shared/depricated/snippets_old/classfeature.gen.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/classfeature.gen.js rename to shared/depricated/snippets_old/classfeature.gen.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/classtable.gen.js b/shared/depricated/snippets_old/classtable.gen.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/classtable.gen.js rename to shared/depricated/snippets_old/classtable.gen.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/coverpage.gen.js b/shared/depricated/snippets_old/coverpage.gen.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/coverpage.gen.js rename to shared/depricated/snippets_old/coverpage.gen.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/fullclass.gen.js b/shared/depricated/snippets_old/fullclass.gen.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/fullclass.gen.js rename to shared/depricated/snippets_old/fullclass.gen.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/magic.gen.js b/shared/depricated/snippets_old/magic.gen.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/magic.gen.js rename to shared/depricated/snippets_old/magic.gen.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/monsterblock.gen.js b/shared/depricated/snippets_old/monsterblock.gen.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/monsterblock.gen.js rename to shared/depricated/snippets_old/monsterblock.gen.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/snippets.js b/shared/depricated/snippets_old/snippets.js similarity index 100% rename from shared/homebrewery/brewEditor/snippetbar/snippets/snippets.js rename to shared/depricated/snippets_old/snippets.js diff --git a/shared/homebrewery/brewEditor/snippetbar/snippets/tableOfContents.gen.js b/shared/depricated/snippets_old/tableOfContents.gen.js similarity index 97% rename from shared/homebrewery/brewEditor/snippetbar/snippets/tableOfContents.gen.js rename to shared/depricated/snippets_old/tableOfContents.gen.js index 448b2f4..ed1381a 100644 --- a/shared/homebrewery/brewEditor/snippetbar/snippets/tableOfContents.gen.js +++ b/shared/depricated/snippets_old/tableOfContents.gen.js @@ -48,7 +48,7 @@ const getTOC = (pages) => { } module.exports = function(brew){ - const pages = brew.split('\\page'); + const TOC = getTOC(pages); const markdown = _.reduce(TOC, (r, g1, idx1)=>{ r.push(`- **[${idx1 + 1} ${g1.title}](#p${g1.page})**`) diff --git a/shared/homebrewery/brew.actions.js b/shared/homebrewery/brew.actions.js index 5e0b41e..e359aca 100644 --- a/shared/homebrewery/brew.actions.js +++ b/shared/homebrewery/brew.actions.js @@ -70,8 +70,9 @@ const Actions = { }, localPrint : ()=>{ - localStorage.setItem('print', Store.getBrewText()); - window.open('/print?dialog=true&local=print','_blank'); + const key = 'print'; + localStorage.setItem(key, JSON.stringify(Store.getBrew())); + window.open(`/print?dialog=true&local=${key}`,'_blank'); }, print : ()=>{ window.open(`/print/${Store.getBrew().shareId}?dialog=true`, '_blank').focus(); diff --git a/shared/homebrewery/brewEditor/brewEditor.jsx b/shared/homebrewery/brewEditor/brewEditor.jsx index 721e481..d6fe57c 100644 --- a/shared/homebrewery/brewEditor/brewEditor.jsx +++ b/shared/homebrewery/brewEditor/brewEditor.jsx @@ -3,9 +3,7 @@ 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 Menubar = require('./menubar/menubar.jsx'); const splice = function(str, index, inject){ @@ -32,6 +30,10 @@ const BrewEditor = React.createClass({ view : 'code', //'code', 'style', 'meta' }; }, + isCode : function(){ return this.state.view == 'code' }, + isStyle : function(){ return this.state.view == 'style' }, + isMeta : function(){ return this.state.view == 'meta' }, + componentDidMount: function() { this.updateEditorSize(); @@ -53,11 +55,16 @@ const BrewEditor = React.createClass({ handleInject : function(injectText){ - const lines = this.props.value.split('\n'); - lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText); + const text = (this.isCode() ? this.props.brew.text : this.props.brew.style); - this.handleTextChange(lines.join('\n')); - this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length); + const lines = text.split('\n'); + const cursorPos = this.refs.codeEditor.getCursorPosition(); + lines[cursorPos.line] = splice(lines[cursorPos.line], cursorPos.ch, injectText); + + this.refs.codeEditor.setCursorPosition(cursorPos.line, cursorPos.ch + injectText.length); + + if(this.state.view == 'code') this.props.onCodeChange(lines.join('\n')); + if(this.state.view == 'style') this.props.onStyleChange(lines.join('\n')); }, @@ -87,6 +94,9 @@ const BrewEditor = React.createClass({ //MOve this to a util.sj file highlightPageLines : function(){ if(!this.refs.codeEditor) return; + if(!this.isCode()) return; + + const codeMirror = this.refs.codeEditor.codeMirror; const lineNumbers = _.reduce(this.props.brew.text.split('\n'), (r, line, lineNumber)=>{ @@ -95,6 +105,11 @@ const BrewEditor = React.createClass({ r.push(lineNumber); } + if(line.indexOf('\\column') === 0){ + codeMirror.addLineClass(lineNumber, 'text', 'columnSplit'); + r.push(lineNumber); + } + if(_.startsWith(line, '{{') || _.startsWith(line, '}}')){ codeMirror.addLineClass(lineNumber, 'text', 'block'); } @@ -116,19 +131,19 @@ const BrewEditor = React.createClass({ renderEditor : function(){ - if(this.state.view == 'meta'){ + if(this.isMeta()){ return } - if(this.state.view == 'style'){ + if(this.isStyle()){ return } - if(this.state.view == 'code'){ + if(this.isCode()){ return - {/* - - */} diff --git a/shared/homebrewery/brewEditor/brewEditor.less b/shared/homebrewery/brewEditor/brewEditor.less index a47dc69..48e3e08 100644 --- a/shared/homebrewery/brewEditor/brewEditor.less +++ b/shared/homebrewery/brewEditor/brewEditor.less @@ -9,9 +9,13 @@ border-bottom : #333 solid 1px; } .block{ - color : blue; + color : purple; //font-style: italic; } + .columnSplit{ + font-style : italic; + color : grey; + } } .brewJump{ diff --git a/shared/homebrewery/brewEditor/menubar/menubar.jsx b/shared/homebrewery/brewEditor/menubar/menubar.jsx index ed47e08..3191197 100644 --- a/shared/homebrewery/brewEditor/menubar/menubar.jsx +++ b/shared/homebrewery/brewEditor/menubar/menubar.jsx @@ -1,19 +1,60 @@ - const React = require('react'); const _ = require('lodash'); const cx = require('classnames'); +const SnippetMap = require('./snippet.map.js'); +const SnippetGroup = require('./snippetGroup/snippetGroup.jsx'); + const Menubar = React.createClass({ getDefaultProps: function() { return { - view : '', + view : 'code', onViewChange : ()=>{}, onSnippetInject : ()=>{}, }; }, + + //TODO: remove + renderDevGroup : function(){ + const Snippets = require('homebrewery/snippets/brew'); + + const snippets = _.map(Snippets, (gen, name)=>{ + return { + name, + gen, + icon : 'fa-question' + } + }) + + return + }, + + renderSnippets : function(){ + if(this.props.view == 'meta') return ; + + let mapping; + if(this.props.view == 'code') mapping = SnippetMap.brew; + if(this.props.view == 'style') mapping = SnippetMap.style; + + let groups = _.map(mapping, (group)=>{ + return + }); + + groups = groups.concat(this.renderDevGroup()); + + return
{groups}
+ }, render: function(){ return
+ {this.renderSnippets()} +
diff --git a/shared/homebrewery/brewEditor/menubar/menubar.less b/shared/homebrewery/brewEditor/menubar/menubar.less index 653e82c..e857528 100644 --- a/shared/homebrewery/brewEditor/menubar/menubar.less +++ b/shared/homebrewery/brewEditor/menubar/menubar.less @@ -32,4 +32,9 @@ } } } + + .snippets{ + display : flex; + height : 100%; + } } \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/menubar/snippet.map.js b/shared/homebrewery/brewEditor/menubar/snippet.map.js new file mode 100644 index 0000000..85571de --- /dev/null +++ b/shared/homebrewery/brewEditor/menubar/snippet.map.js @@ -0,0 +1,48 @@ +const Snippets = require('homebrewery/snippets'); + +module.exports = { + brew : [ + { + name : 'PHB', + icon : 'fa-book', + snippets : [ + { + name : 'Spell', + icon : 'fa-magic', + gen : Snippets.brew.spell + }, + { + name : 'Table', + icon : 'fa-table', + gen : Snippets.brew.table + }, + + ] + }, + { + name : 'Mods', + icon : 'fa-gear', + snippets : [] + } + ], + + style : [ + { + name : 'Print', + icon : 'fa-print', + snippets : [ + { + name : 'Ink Friendly', + icon : 'fa-tint', + gen : Snippets.style.inkFriendly + }, + { + name : 'A4 Page Size', + icon : 'fa-file', + gen : Snippets.style.a4 + }, + + ] + } + ] +} \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/menubar/snippetGroup/snippetGroup.jsx b/shared/homebrewery/brewEditor/menubar/snippetGroup/snippetGroup.jsx new file mode 100644 index 0000000..fd36d7a --- /dev/null +++ b/shared/homebrewery/brewEditor/menubar/snippetGroup/snippetGroup.jsx @@ -0,0 +1,41 @@ + +const React = require('react'); +const _ = require('lodash'); +const cx = require('classnames'); + +const SnippetGroup = React.createClass({ + getDefaultProps: function() { + return { + name : '', + icon : 'fa-rocket', + snippets : [], + onClick : function(){}, + }; + }, + handleSnippetClick : function(snippet){ + this.props.onClick(snippet.gen()); + }, + renderSnippets : function(){ + return _.map(this.props.snippets, (snippet)=>{ + return
+ + {snippet.name} +
+ }) + }, + + render : function(){ + return
+
+ + {this.props.name} +
+
+ {this.renderSnippets()} +
+
+ }, + +}); + +module.exports = SnippetGroup; diff --git a/shared/homebrewery/brewEditor/menubar/snippetGroup/snippetGroup.less b/shared/homebrewery/brewEditor/menubar/snippetGroup/snippetGroup.less new file mode 100644 index 0000000..9dab435 --- /dev/null +++ b/shared/homebrewery/brewEditor/menubar/snippetGroup/snippetGroup.less @@ -0,0 +1,56 @@ +.snippetGroup{ + //display : inline-block; + display : flex; + height : 100%; + align-items : center; + + //height : @menuHeight; + padding : 0px 5px; + cursor : pointer; + font-size : 0.6em; + font-weight : 800; + ///line-height : @menuHeight; + text-transform : uppercase; + border-right : 1px solid black; + i{ + vertical-align : middle; + margin-right : 3px; + font-size : 1.2em; + } + &:hover, &.selected{ + background-color : #999; + } + .text{ + //line-height : @menuHeight; + .groupName{ + font-size : 10px; + } + } + &:hover{ + .dropdown{ + visibility : visible; + } + } + .dropdown{ + position : absolute; + top : 100%; + visibility : hidden; + z-index : 1000; + margin-left : -5px; + padding : 0px; + background-color : #ddd; + .snippet{ + .animate(background-color); + padding : 10px; + cursor : pointer; + font-size : 10px; + i{ + margin-right : 8px; + font-size : 13px; + } + &:hover{ + background-color : #999; + } + } + } +} \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/snippetbar/snippetbar.jsx b/shared/homebrewery/brewEditor/snippetbar/snippetbar.jsx deleted file mode 100644 index 29c6b43..0000000 --- a/shared/homebrewery/brewEditor/snippetbar/snippetbar.jsx +++ /dev/null @@ -1,94 +0,0 @@ -const React = require('react'); -const _ = require('lodash'); -const cx = require('classnames'); - - -const Snippets = require('./snippets/snippets.js'); - -const execute = function(val, brew){ - if(_.isFunction(val)) return val(brew); - return val; -} - - - -const Snippetbar = React.createClass({ - getDefaultProps: function() { - return { - brew : '', - onInject : ()=>{}, - onToggle : ()=>{}, - showmeta : false - }; - }, - - handleSnippetClick : function(injectedText){ - this.props.onInject(injectedText) - }, - - renderSnippetGroups : function(){ - return _.map(Snippets, (snippetGroup)=>{ - return - }) - }, - - render : function(){ - return
- {this.renderSnippetGroups()} -
- -
-
- } -}); - -module.exports = Snippetbar; - - - - - - -const SnippetGroup = React.createClass({ - getDefaultProps: function() { - return { - brew : '', - groupName : '', - icon : 'fa-rocket', - snippets : [], - onSnippetClick : function(){}, - }; - }, - handleSnippetClick : function(snippet){ - this.props.onSnippetClick(execute(snippet.gen, this.props.brew)); - }, - renderSnippets : function(){ - return _.map(this.props.snippets, (snippet)=>{ - return
- - {snippet.name} -
- }) - }, - - render : function(){ - return
-
- - {this.props.groupName} -
-
- {this.renderSnippets()} -
-
- }, - -}); \ No newline at end of file diff --git a/shared/homebrewery/brewEditor/snippetbar/snippetbar.less b/shared/homebrewery/brewEditor/snippetbar/snippetbar.less deleted file mode 100644 index 45a6efe..0000000 --- a/shared/homebrewery/brewEditor/snippetbar/snippetbar.less +++ /dev/null @@ -1,72 +0,0 @@ - -.snippetBar{ - @height : 25px; - position : relative; - height : @height; - background-color : #ddd; - .toggleMeta{ - position : absolute; - top : 0px; - right : 0px; - height : @height; - width : @height; - cursor : pointer; - line-height : @height; - text-align : center; - &:hover, &.selected{ - background-color : #999; - } - } - .snippetGroup{ - display : inline-block; - height : @height; - padding : 0px 5px; - cursor : pointer; - font-size : 0.6em; - font-weight : 800; - line-height : @height; - text-transform : uppercase; - border-right : 1px solid black; - i{ - vertical-align : middle; - margin-right : 3px; - font-size : 1.2em; - } - &:hover, &.selected{ - background-color : #999; - } - .text{ - line-height : @height; - .groupName{ - font-size : 10px; - } - } - &:hover{ - .dropdown{ - visibility : visible; - } - } - .dropdown{ - position : absolute; - top : 100%; - visibility : hidden; - z-index : 1000; - margin-left : -5px; - padding : 0px; - background-color : #ddd; - .snippet{ - .animate(background-color); - padding : 5px; - cursor : pointer; - font-size : 10px; - i{ - margin-right : 8px; - font-size : 13px; - } - &:hover{ - background-color : #999; - } - } - } - } -} \ No newline at end of file diff --git a/shared/homebrewery/brewInterface/brewInterface.jsx b/shared/homebrewery/brewInterface/brewInterface.jsx index 1b5b17c..65387a2 100644 --- a/shared/homebrewery/brewInterface/brewInterface.jsx +++ b/shared/homebrewery/brewInterface/brewInterface.jsx @@ -7,9 +7,9 @@ const BrewRenderer = require('../brewRenderer/brewRenderer.smart.jsx'); const BrewInterface = React.createClass({ - handleSplitMove : function(){ - console.log('split move!'); + const BrewEditor = this.refs.editor.refs.wrappedComponent; + BrewEditor.updateEditorSize(); }, render: function(){ return diff --git a/shared/homebrewery/brewRenderer/brewRenderer.jsx b/shared/homebrewery/brewRenderer/brewRenderer.jsx index f140fdf..bcce8c6 100644 --- a/shared/homebrewery/brewRenderer/brewRenderer.jsx +++ b/shared/homebrewery/brewRenderer/brewRenderer.jsx @@ -133,6 +133,11 @@ const BrewRenderer = React.createClass({ return this.lastRender; }, + //TODO: This is pretty bad + renderStyle : function(){ + return + }, + render : function(){ if(this.props.brew.version == 1) return ; @@ -146,7 +151,7 @@ const BrewRenderer = React.createClass({ - + {this.renderStyle()}
{this.renderPages()} diff --git a/shared/homebrewery/markdown.js b/shared/homebrewery/markdown.js index 32380a0..288dedc 100644 --- a/shared/homebrewery/markdown.js +++ b/shared/homebrewery/markdown.js @@ -26,11 +26,18 @@ renderer.paragraph = function(text){ return res; }; +renderer.image = function(href, title, text){ + return ``; +}; + module.exports = { marked : Markdown, render : (rawBrewText)=>{ blockCount = 0; + + rawBrewText = rawBrewText.replace(/\\column/g, '{{columnSplit }}') + let html = Markdown(rawBrewText, {renderer : renderer, sanitize: true}); //Close all hanging block tags html += _.times(blockCount, ()=>{return '
'}).join('\n'); diff --git a/shared/homebrewery/phb_style/img/footer_flip.png b/shared/homebrewery/phb_style/img/footer_flip.png new file mode 100644 index 0000000..6e512af Binary files /dev/null and b/shared/homebrewery/phb_style/img/footer_flip.png differ diff --git a/shared/homebrewery/phb_style/img/monster_bg.jpg b/shared/homebrewery/phb_style/img/monster_bg.jpg new file mode 100644 index 0000000..d22f839 Binary files /dev/null and b/shared/homebrewery/phb_style/img/monster_bg.jpg differ diff --git a/shared/homebrewery/phb_style/img/monstor_border.png b/shared/homebrewery/phb_style/img/monster_border.png similarity index 100% rename from shared/homebrewery/phb_style/img/monstor_border.png rename to shared/homebrewery/phb_style/img/monster_border.png diff --git a/shared/homebrewery/phb_style/img/note_border - Copy.png b/shared/homebrewery/phb_style/img/note_border - Copy.png new file mode 100644 index 0000000..bf7b301 Binary files /dev/null and b/shared/homebrewery/phb_style/img/note_border - Copy.png differ diff --git a/shared/homebrewery/phb_style/img/note_border.pdn b/shared/homebrewery/phb_style/img/note_border.pdn new file mode 100644 index 0000000..51016cf Binary files /dev/null and b/shared/homebrewery/phb_style/img/note_border.pdn differ diff --git a/shared/homebrewery/phb_style/img/note_border_shadow.png b/shared/homebrewery/phb_style/img/note_border_shadow.png new file mode 100644 index 0000000..87dd2bb Binary files /dev/null and b/shared/homebrewery/phb_style/img/note_border_shadow.png differ diff --git a/shared/homebrewery/phb_style/img/shadow_border.pdn b/shared/homebrewery/phb_style/img/shadow_border.pdn new file mode 100644 index 0000000..46681cc Binary files /dev/null and b/shared/homebrewery/phb_style/img/shadow_border.pdn differ diff --git a/shared/homebrewery/phb_style/img/shadow_border.png b/shared/homebrewery/phb_style/img/shadow_border.png new file mode 100644 index 0000000..4a07c8b Binary files /dev/null and b/shared/homebrewery/phb_style/img/shadow_border.png differ diff --git a/shared/homebrewery/phb_style/phb.blocks.less b/shared/homebrewery/phb_style/phb.blocks.less new file mode 100644 index 0000000..26d39fb --- /dev/null +++ b/shared/homebrewery/phb_style/phb.blocks.less @@ -0,0 +1,211 @@ + +/////////////////// +.spell{ + ul:first-of-type{ + margin-top : -0.5em; + margin-bottom : 0.5em; + + list-style-type : none; + &+p{ + text-indent : 0em; + } + } +} +.monster{ + .breakAvoid(); + .pseudoBorder(); + .pseudoShadow(); + padding : 17px 14px; + table:nth-of-type(1){ + margin-bottom : 0.4em; + margin-top : 0.4em; + color : @crimson; + tbody tr { background-color: transparent }; + } + ul:nth-of-type(1),ul:nth-of-type(2){ + list-style: none; + padding-left : 1em; + text-indent : -1em; + margin-bottom : 0.5em; + strong{ + color : @crimson; + } + } + &:before{ + top : 8px; + right : 7px; + bottom : 19px; + left : 7px; + background-color : #FDF1DC; + border-image-slice : 8; + border-image-source : @monsterBorder; + border-image-width : 8px; + } + &.wide{ + column-count : 2; + } +} +.note{ + .useSansSerif(); + .breakAvoid(); + .pseudoBorder(); + .pseudoShadow(); + margin : 9px 0px; + padding : 17px 17px; + &:before{ + top : 9px; + right : 9px; + bottom : 19px; + left : 9px; + background-color : @green; + border-width : 11px; + border-image-outset : 9px 0px; + border-image-slice : 11; + border-image-source : @noteBorder; + } + h2,h3,h4{ + .useSansSerif(); + color : black; + } + p, ul{ + font-size : 0.352cm; + line-height : 1.1em; + } + &.alt{ + &:before{ + border-style : solid; + border-width : 7px; + border-image-outset : 4px; + border-image-slice : 12; + border-image-source : @descriptiveBorder; + } + } +} +.frame{ + .breakAvoid(); + .pseudoBorder(); + padding : 25px 17px; + &:before{ + top : 25px; + right : 17px; + bottom : 25px; + left : 17px; + background-color : white; + border-image-outset : 25px 17px; + border-image-slice : 150 200 150 200; + border-image-source : @frameBorder; + border-image-width : 47px; + } +} +.footnote{ + position : absolute; + right : 80px; + bottom : 28px; + z-index : 150; + width : 200px; + font-size : 0.9em; + color : @gold; + text-align : right; +} +//***************************** +// * TABLE OF CONTENTS +// *****************************/ +.toc{ + h1{ + text-align : center; + } + li{ + margin-bottom : 3px; + strong, em::after{ + font-family : BookInsanity; + font-size : 13px; + font-style : normal; + font-weight : 500; + color : black; + } + em{ + display : block; + overflow : hidden; + width : auto; + font-style : normal; + white-space : nowrap; + &:after{ + content : " .............................................................................................................."; + } + } + strong{ + float : right; + margin-left : 4px; + } + h3{ + margin-top : 15px; + em{ color : @crimson; } + em::after{ display : none; } + } + h4{ + margin-top : 10px; + em{ color : @crimson; } + } + } + a{ + color : black; + text-decoration : none; + &:hover{ + text-decoration : underline; + } + } + ul{ + padding-left : 0; + list-style-type : none; + } +} +.wide{ + column-span : all; + -webkit-column-span : all; + -moz-column-span : all; +} +.oneColumn{ + column-count : 1; +// column-gap : 1cm; +} +.twoColumn{ + column-count : 2; + //column-fill: auto; + ////column-gap : 1cm; +} +.threeColumn{ + column-count : 3; + //column-gap : 1cm; +} +.fourColumn{ + column-count : 4; + //column-gap : 1cm; +} +.columnSplit{ + visibility : hidden; + -webkit-column-break-bfore : always; + break-before : column; +} +.brushed{ + border-image-outset : 25px 17px; + border-image-repeat : round; + border-image-slice : 1250 1250 1250 1250; + border-image-width : 1250px; + border-image-source : url('http : //i.imgur.com/nzPYZyD.png'); +} +//basics +.left{ + text-align : left; +} +.right{ + text-align : right; +} +.center{ + text-align : center; +} +.bold{ + font-weight : 800; +} +.sansSerif{ + .useSansSerif(); +} \ No newline at end of file diff --git a/shared/homebrewery/phb_style/phb.colors.less b/shared/homebrewery/phb_style/phb.colors.less index 6a28432..35f82f2 100644 --- a/shared/homebrewery/phb_style/phb.colors.less +++ b/shared/homebrewery/phb_style/phb.colors.less @@ -8,8 +8,6 @@ @monsterStatBackground : #FDF1DC; -@teal : blue; - .colorElements(@color){ table tbody{ @@ -17,8 +15,24 @@ background-color : @color; } } + &.note:before{ + background-color: @color; + } } +@crimson : #58180D; +@red : #9c2b1b; +@gold : #c9ad6a; //brown? +@green : #e0e5c1; +@yellow : #faf7ea; //same as background? +@teal : blue; +@blue : blue; + //TODO make a color mixin generator .teal{ .colorElements(@teal); } +.blue{ .colorElements(@blue); } +.green{ .colorElements(@green); } +.yellow{ .colorElements(@yellow); } +.gold{ .colorElements(@gold); } +.red{ .colorElements(@red); } diff --git a/shared/homebrewery/phb_style/phb.elements.less b/shared/homebrewery/phb_style/phb.elements.less new file mode 100644 index 0000000..bebe734 --- /dev/null +++ b/shared/homebrewery/phb_style/phb.elements.less @@ -0,0 +1,172 @@ +pre{ + font-family : monospace; + background-color : @yellow; + padding : 12px; + border: 1px solid #bfbfbf; + white-space: pre-wrap; + color : #333; + -webkit-column-break-inside : avoid; + column-break-inside : avoid; +} + + +hr{ + visibility : visible; + height : 6px; + margin : 4px 0px; + background-image : @dividerImg; + background-size : 100% 100%; + border : none; +} + + +p{ + padding-bottom : 0.8em; + line-height : 1.3em; + &+p{ + margin-top : -0.8em; + } +} + +blockquote{ + font-style : italic; + &>p{ + line-height: 1.8em; + &:first-child::first-line{ + + //TODO: Find the right font for block quotes + font-style: normal; + font-family: ScalySansSmallCaps; + + + } + } + .cite{ + font-style: normal; + text-align: right; + } + + +} + +//Indents after p or lists +p+p, ul+p, ol+p{ + text-indent : 1em; +} +img{ + z-index : -1; +} +strong{ + font-weight : bold; + letter-spacing : 0.03em; +} +em{ + font-style : italic; +} +sup{ + vertical-align : super; + font-size : smaller; + line-height : 0; +} +sub{ + vertical-align : sub; + font-size : smaller; + line-height : 0; +} +//***************************** +// * HEADERS +// *****************************/ +h1,h2,h3,h4{ + margin-top : 0.2em; + margin-bottom : 0.2em; + font-family : MrEaves; + font-weight : 800; + color : @headerText; +} +h1{ + column-span : all; + font-size : 0.987cm; + -webkit-column-span : all; + -moz-column-span : all; + &+p::first-letter{ + float : left; + font-family : Solbera; + font-size : 10em; + color : #222; + line-height : 0.8em; + } +} +h2{ + font-size : 0.705cm; +} +h3{ + font-size : 0.529cm; + border-bottom : 2px solid @headerUnderline; +} +h4{ + margin-bottom : 0.00em; + font-size : 0.458cm; +} +h5{ + margin-bottom : 0.2em; + font-family : ScalySansSmallCaps; + font-size : 0.423cm; + font-weight : 900; +} + + +//****************************** +// LISTS +//****************************** +ul ul,ol ol,ul ol,ol ul{ + margin-bottom : 0px; + margin-left : 1.5em; +} +li{ + -webkit-column-break-inside : avoid; + column-break-inside : avoid; +} +ul{ + margin-bottom : 0.8em; + padding-left : 1.4em; + line-height : 1.3em; + list-style-position : outside; + list-style-type : disc; +} +ol{ + margin-bottom : 0.8em; + padding-left : 1.4em; + line-height : 1.3em; + list-style-position : outside; + list-style-type : decimal; +} + + +//***************************** +// * TABLE +// *****************************/ +table{ + .useSansSerif(); + width : 100%; + margin-bottom : 1em; + font-size : 10pt; + thead{ + font-weight : 800; + th{ + vertical-align : bottom; + padding-bottom : 0.3em; + padding-right : 0.1em; + padding-left : 0.1em; + } + } + tbody{ + tr{ + td{ + padding : 0.3em 0.1em; + } + &:nth-child(odd){ + background-color : @green; + } + } + } +} \ No newline at end of file diff --git a/shared/homebrewery/phb_style/phb.fonts.less b/shared/homebrewery/phb_style/phb.fonts.less index 976972f..e6ec1a8 100644 --- a/shared/homebrewery/phb_style/phb.fonts.less +++ b/shared/homebrewery/phb_style/phb.fonts.less @@ -53,18 +53,3 @@ font-weight: normal; font-style: normal; } - -//TODO: move the useSansSerif into here - -.useSansSerif(){ - font-family : ScalySans; - em{ - font-family : ScalySans; - font-style : italic; - } - strong{ - font-family : ScalySans; - font-weight : 800; - letter-spacing : -0.02em; - } -} \ No newline at end of file diff --git a/shared/homebrewery/phb_style/phb.img.less b/shared/homebrewery/phb_style/phb.img.less index 7e3a597..c2f8303 100644 --- a/shared/homebrewery/phb_style/phb.img.less +++ b/shared/homebrewery/phb_style/phb.img.less @@ -1,12 +1,16 @@ @footerImg : url('/assets/homebrewery/phb_style/img/footer.png'); +@footerFlipImg : url('/assets/homebrewery/phb_style/img/footer_flip.png'); @dividerImg : url('/assets/homebrewery/phb_style/img/divider.png'); @frameBorder : url('/assets/homebrewery/phb_style/img/frame_border.png'); @monsterBorder : url('/assets/homebrewery/phb_style/img/monster_border.png'); @noteBorder : url('/assets/homebrewery/phb_style/img/note_border.png'); @descriptiveBorder : url('/assets/homebrewery/phb_style/img/desc_border.png'); +@shadowBorder : url('/assets/homebrewery/phb_style/img/shadow_border.png'); + @phbBG : url('/assets/homebrewery/phb_style/img/phb_bg.jpg'); @darkBG : url('/assets/homebrewery/phb_style/img/phb_dark_bg.jpg'); @dmgBG : url('/assets/homebrewery/phb_style/img/dmg_bg.jpg'); +@monsterBG : url('/assets/homebrewery/phb_style/img/monster_bg.jpg'); diff --git a/shared/homebrewery/phb_style/phb.less b/shared/homebrewery/phb_style/phb.less index 00c5515..e9adf63 100644 --- a/shared/homebrewery/phb_style/phb.less +++ b/shared/homebrewery/phb_style/phb.less @@ -1,3 +1,6 @@ + +//TODO: Remove this +/* @media print { .phb.v2{ .descriptive, blockquote{ @@ -5,34 +8,16 @@ } } } - +*/ .phb.v2{ + @import './phb.mixins.less'; @import './phb.fonts.less'; @import './phb.colors.less'; @import './phb.img.less'; - - - @page { margin: 0; } - - - .useColumns(@multiplier : 1){ - column-count : 2; - column-fill : auto; - column-gap : 1cm; - column-width : 8cm * @multiplier; - -webkit-column-count : 2; - -moz-column-count : 2; - -webkit-column-width : 8cm * @multiplier; - -moz-column-width : 8cm * @multiplier; - -webkit-column-gap : 1cm; - -moz-column-gap : 1cm; - } - & *{ - -webkit-print-color-adjust : exact; - } - .useColumns(); + @import './phb.blocks.less'; + @import './phb.elements.less'; counter-increment : phb-page-numbers; position : relative; z-index : 15; @@ -42,6 +27,10 @@ width : 215.9mm; padding : 1.0cm 1.7cm; padding-bottom : 1.5cm; + column-count : 2; + column-fill : auto; + column-gap : 1cm; + column-width : 8cm; background-color : @background; background-image : @phbBG; font-family : BookInsanity; @@ -49,150 +38,64 @@ text-rendering : optimizeLegibility; page-break-before : always; page-break-after : always; + @page { margin: 0; } //TODO: ???? + & *{ + -webkit-print-color-adjust : exact; + } + //***************************** + // * FOOTER + // *****************************/ + &:after{ + content : "Made with The Homebrewery"; + position : absolute; + bottom : 0px; + left : 0px; + z-index : 100; + height : 50px; + width : 100%; + background-image : @footerImg; + background-size : cover; + padding: 28px 63px; + box-sizing: border-box; + color : lighten(@gold, 0%); + font-size: 0.7em; + } + &:nth-child(even){ + &:after{ + background-image: @footerFlipImg; + text-align: right; + } + &:before{ + left : 2px; + } + .footnote{ + left : 80px; + text-align : left; + } + } + &:before{ + content : counter(phb-page-numbers); + position : absolute; + right : 2px; + bottom : 22px; + width : 50px; + font-size : 0.9em; + color : @gold; + text-align : center; + } //***************************** // * BASE // *****************************/ - p{ - padding-bottom : 0.8em; - line-height : 1.3em; - &+p{ - margin-top : -0.8em; - } - } - ul{ - margin-bottom : 0.8em; - padding-left : 1.4em; - line-height : 1.3em; - list-style-position : outside; - list-style-type : disc; - } - ol{ - margin-bottom : 0.8em; - padding-left : 1.4em; - line-height : 1.3em; - list-style-position : outside; - list-style-type : decimal; - } - //Indents after p or lists - p+p, ul+p, ol+p{ - text-indent : 1em; - } - img{ - z-index : -1; - } - strong{ - font-weight : bold; - letter-spacing : 0.03em; - } - em{ - font-style : italic; - } - sup{ - vertical-align : super; - font-size : smaller; - line-height : 0; - } - sub{ - vertical-align : sub; - font-size : smaller; - line-height : 0; - } - //***************************** - // * HEADERS - // *****************************/ - h1,h2,h3,h4{ - margin-top : 0.2em; - margin-bottom : 0.2em; - font-family : MrEaves; - font-weight : 800; - color : @headerText; - } - h1{ - column-span : all; - font-size : 0.987cm; - -webkit-column-span : all; - -moz-column-span : all; - &+p::first-letter{ - float : left; - font-family : Solbera; - font-size : 10em; - color : #222; - line-height : 0.8em; - } - } - h2{ - font-size : 0.705cm; - } - h3{ - font-size : 0.529cm; - border-bottom : 2px solid @headerUnderline; - } - h4{ - margin-bottom : 0.00em; - font-size : 0.458cm; - } - h5{ - margin-bottom : 0.2em; - font-family : ScalySansSmallCaps; - font-size : 0.423cm; - font-weight : 900; - } - //***************************** - // * TABLE - // *****************************/ - table{ - .useSansSerif(); - width : 100%; - margin-bottom : 1em; - font-size : 10pt; - thead{ - font-weight : 800; - th{ - vertical-align : bottom; - padding-bottom : 0.3em; - padding-right : 0.1em; - padding-left : 0.1em; - } - } - tbody{ - tr{ - td{ - padding : 0.3em 0.1em; - } - &:nth-child(odd){ - background-color : @noteGreen; - } - } - } - } - //***************************** - // * NOTE - // *****************************/ - blockquote{ - .useSansSerif(); - box-sizing : border-box; - margin-bottom : 1em; - padding : 5px 10px; - background-color : @noteGreen; - border-style : solid; - border-width : 11px; - border-image : @noteBorder 11; - border-image-outset : 9px 0px; - box-shadow : 1px 4px 14px #888; - p, ul{ - font-size : 0.352cm; - line-height : 1.1em; - } - } //If a note starts a column, give it space at the top to render border - pre+blockquote, h2+blockquote, h3+blockquote, h4+blockquote, h5+blockquote { - margin-top : 13px; - } + //pre+blockquote, h2+blockquote, h3+blockquote, h4+blockquote, h5+blockquote { + // margin-top : 13px; + //} //***************************** // * MONSTER STAT BLOCK // *****************************/ + /* hr+blockquote{ position : relative; padding-top : 15px; @@ -252,107 +155,46 @@ border : none; } } - //Full Width - hr+hr+blockquote{ - .useColumns(0.96); - } - //***************************** - // * FOOTER - // *****************************/ - &:after{ - content : ""; - position : absolute; - bottom : 0px; - left : 0px; - z-index : 100; - height : 50px; - width : 100%; - background-image : @footerImg; - background-size : cover; - } - &:nth-child(even){ - &:after{ - transform : scaleX(-1); - } - .pageNumber{ - left : 2px; - } - .footnote{ - left : 80px; - text-align : left; - } - } - .pageNumber{ - position : absolute; - right : 2px; - bottom : 22px; - width : 50px; - font-size : 0.9em; - color : #c9ad6a; - text-align : center; - &.auto::after { - content : counter(phb-page-numbers); - } - } - .footnote{ - position : absolute; - right : 80px; - bottom : 32px; - z-index : 150; - width : 200px; - font-size : 0.8em; - color : #c9ad6a; - text-align : right; - } + //***************************** // * EXTRAS // *****************************/ - hr{ - visibility : hidden; - margin : 0px; - } //Modified unorder list, used in spells - hr+ul{ - margin-bottom : 0.5em; - padding-left : 1em; - text-indent : -1em; - list-style-type : none; - } + // hr+ul{ + // margin-bottom : 0.5em; + // padding-left : 1em; + // text-indent : -1em; + // list-style-type : none; + // } //Column Break + /* pre, code{ visibility : hidden; -webkit-column-break-after : always; break-after : always; -moz-column-break-after : always; } + */ //Avoid breaking up + /* p,blockquote,table{ z-index : 15; -webkit-column-break-inside : avoid; column-break-inside : avoid; overflow: hidden; /* Firefox fix */ - } //Better spacing for spell blocks - h4+p+hr+ul{ - margin-top : -0.5em - } - //Text indent right after table - table+p{ - text-indent : 1em; - } + // h4+p+hr+ul{ + // margin-top : -0.5em + // } + // //Text indent right after table + // table+p{ + // text-indent : 1em; + // } // Nested lists - ul ul,ol ol,ul ol,ol ul{ - margin-bottom : 0px; - margin-left : 1.5em; - } - li{ - -webkit-column-break-inside : avoid; - column-break-inside : avoid; - } - //***************************** // * SPELL LIST // *****************************/ + /* .spellList{ .useSansSerif(); column-count : 4; @@ -378,42 +220,43 @@ //***************************** // * PRINT // *****************************/ - &.print{ - blockquote{ - box-shadow : none; - } - } - + // &.print{ + // blockquote{ + // box-shadow : none; + // } + // } //***************************** // * WIDE // *****************************/ + /* .wide{ column-span : all; -webkit-column-span : all; -moz-column-span : all; - } + }*/ //***************************** // * CLASS TABLE // *****************************/ - .classTable{ - margin-top : 25px; - margin-bottom : 40px; - border-collapse : separate; - background-color : white; - border : initial; - border-style : solid; - border-image-outset : 25px 17px; - border-image-repeat : round; - border-image-slice : 150 200 150 200; - border-image-source : @frameBorder; - border-image-width : 47px; - h5{ - margin-bottom : 10px; - } - } + // .classTable{ + // margin-top : 25px; + // margin-bottom : 40px; + // border-collapse : separate; + // background-color : white; + // border : initial; + // border-style : solid; + // border-image-outset : 25px 17px; + // border-image-repeat : round; + // border-image-slice : 150 200 150 200; + // border-image-source : @frameBorder; + // border-image-width : 47px; + // h5{ + // margin-bottom : 10px; + // } + // } //***************************** // * CLASS TABLE // *****************************/ + /* .descriptive{ display : block-inline; margin-bottom : 1em; @@ -445,61 +288,36 @@ pre+.descriptive{ margin-top : 8px; } - //***************************** - // * TABLE OF CONTENTS - // *****************************/ - .toc{ - -webkit-column-break-inside : avoid; - column-break-inside : avoid; - a{ - color : black; - text-decoration : none; - &:hover{ - text-decoration : underline; - } - } - ul{ - padding-left : 0; - list-style-type : none; - } - &>ul>li{ - margin-bottom : 10px; - } - } - - - + */ //***************************** // * Old Stuff // *****************************/ - - //Double hr for full width elements - hr+hr+blockquote{ - column-span : all; - -webkit-column-span : all; - -moz-column-span : all; - } - + // //Double hr for full width elements + // hr+hr+blockquote{ + // column-span : all; + // -webkit-column-span : all; + // -moz-column-span : all; + // } //***************************** // * CLASS TABLE // *****************************/ - hr+table{ - margin-top : -5px; - margin-bottom : 50px; - padding-top : 10px; - border-collapse : separate; - background-color : white; - border : initial; - border-style : solid; - border-image-outset : 37px 17px; - border-image-repeat : round; - border-image-slice : 150 200 150 200; - border-image-source : @frameBorder; - border-image-width : 47px; - } - h5+hr+table{ - column-span : all; - -webkit-column-span : all; - -moz-column-span : all; - } + // hr+table{ + // margin-top : -5px; + // margin-bottom : 50px; + // padding-top : 10px; + // border-collapse : separate; + // background-color : white; + // border : initial; + // border-style : solid; + // border-image-outset : 37px 17px; + // border-image-repeat : round; + // border-image-slice : 150 200 150 200; + // border-image-source : @frameBorder; + // border-image-width : 47px; + // } + // h5+hr+table{ + // column-span : all; + // -webkit-column-span : all; + // -moz-column-span : all; + // } } \ No newline at end of file diff --git a/shared/homebrewery/phb_style/phb.mixins.less b/shared/homebrewery/phb_style/phb.mixins.less new file mode 100644 index 0000000..b8d1e49 --- /dev/null +++ b/shared/homebrewery/phb_style/phb.mixins.less @@ -0,0 +1,48 @@ +.breakAvoid(){ + column-break-inside : avoid; + -webkit-column-break-inside : avoid; +} +.pseudoBorder(){ + position : relative; + &:before{ + content : ''; + position : absolute; + z-index : -2; + box-sizing : border-box; + border-style : solid; + border-image-repeat : round; + } +} + +.pseudoShadow(){ + position : relative; + &:after{ + content : ''; + position : absolute; + z-index : -1; + box-sizing : border-box; + top : 4px; + right : 0px; + bottom : 10px; + left : 0px; + border-style : solid; + border-image-repeat : round; + border-image-slice : 13 13; + border-image-source : @shadowBorder; + border-image-width : 11px; + } +} + + +.useSansSerif(){ + font-family : ScalySans; + em{ + font-family : ScalySans; + font-style : italic; + } + strong{ + font-family : ScalySans; + font-weight : 800; + letter-spacing : -0.02em; + } +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/class.snippet.js b/shared/homebrewery/snippets/brew/class.snippet.js new file mode 100644 index 0000000..9e84757 --- /dev/null +++ b/shared/homebrewery/snippets/brew/class.snippet.js @@ -0,0 +1,82 @@ +const _ = require('lodash'); +const Data = require('./random.data.js'); + +const getFeature = (level)=>{ + let res = [] + if(_.includes([4,6,8,12,14,16,19], level+1)){ + res = ['Ability Score Improvement'] + } + res = _.union(res, _.sampleSize(Data.abilities, _.sample([0,1,1,1,1,1]))); + if(!res.length) return '─'; + return res.join(', '); +}; + + +module.exports = { + + casterTable : ()=>{ + + let featureScore = 1 + const rows = _.map(Data.levels, (lvlText, level)=>{ + featureScore += _.random(0,1); + return '| ' + [ + lvlText, + '+'+Math.floor(level/4 + 2), + getFeature(level), + '+'+featureScore + ].join(' | ') + ' |'; + }).join('\n'); + + return `{{frame,wide +##### ${Data.rand('classes')} +| Level | Proficiency Bonus | Features | Cantrips Known | Spells Known | 1st | 2nd | 3rd | 4th | 5th | 6th | 7th | 8th | 9th | +|:---:|:---:|:---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| +${rows} +}}`; + }, + + + halfcasterTable : ()=>{ + let featureScore = 1 + const rows = _.map(Data.levels, (lvlText, level)=>{ + featureScore += _.random(0,1); + return '| ' + [ + lvlText, + '+'+Math.floor(level/4 + 2), + getFeature(level), + '+'+featureScore + ].join(' | ') + ' |'; + }).join('\n'); + + + return `{{frame,wide +##### ${Data.rand('classes')} +| Level | Proficiency Bonus | Features | 1st | 2nd | 3rd | 4th | 5th | +|:---:|:---:|:---|:---:|:---:|:---:|:---:|:---:| +${rows} +}}`; + + }, + + noncasterTable : ()=>{ + let featureScore = 1 + const rows = _.map(Data.levels, (lvlText, level)=>{ + featureScore += _.random(0,1); + return '| ' + [ + lvlText, + '+'+Math.floor(level/4 + 2), + getFeature(level), + '+'+featureScore + ].join(' | ') + ' |'; + }).join('\n'); + + return `{{frame +##### ${Data.rand('classes')} +| Level | Proficiency Bonus | Features | ${Data.rand('abilities')} | +|:---:|:---:|:---|:---:| +${rows} +}}`; + } + + +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/index.js b/shared/homebrewery/snippets/brew/index.js new file mode 100644 index 0000000..0cb4d4f --- /dev/null +++ b/shared/homebrewery/snippets/brew/index.js @@ -0,0 +1,19 @@ +const _ = require('lodash'); + +module.exports = _.merge( + require('./spell.snippet.js'), + require('./table.snippet.js'), + require('./class.snippet.js'), + require('./note.snippet.js'), + require('./monster.snippet.js'), + require('./toc.snippet.js') + + + //wide + //colors + //brushed + //font + //alignment + + +); \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/monster.snippet.js b/shared/homebrewery/snippets/brew/monster.snippet.js new file mode 100644 index 0000000..ad41335 --- /dev/null +++ b/shared/homebrewery/snippets/brew/monster.snippet.js @@ -0,0 +1,74 @@ +const _ = require('lodash'); +const Data = require('./random.data.js'); + + +const getStats = function(){ + return '|' + _.times(6, function(){ + const num = _.random(1,20); + const mod = Math.ceil(num/2 - 5) + return num + " (" + (mod >= 0 ? '+'+mod : mod ) + ")" + }).join('|') + '|'; +} + +const getAttributes = ()=>{ + + + + + return ` +- **Saving Throws** +- **Condition Immunities** " + genList(["groggy", "swagged", "weak-kneed", "buzzed", "groovy", "melancholy", "drunk"], 3), +- **Senses** passive Perception " + _.random(3, 20), +- **Languages** ${Data.rand(["Common", "Pottymouth", "Gibberish", "Latin", "Jive"], 2).join(', ')} +- **Challenge** ${_.random(0, 15)} (${_.random(10,10000)} XP) +`; + +} + +const getAbilities = ()=>{ + +} + +const getActions = ()=>{ + + +} + + +module.exports = { + monster : ()=>{ + + const stats = ''; + + return `{{monster +## ${Data.rand('creatures')} +*${Data.rand('sizes')}, ${Data.rand('alignments')}* + +--- + +- **Armor Class** ${_.random(10,20)} +- **Hit Points** ${_.random(1, 150)} (1d4 + 5) +- **Speed** ${ _.random(0,50)} ft + +--- + +|STR|DEX|CON|INT|WIS|CHA| +|:---:|:---:|:---:|:---:|:---:|:---:| +${getStats()} + +--- + +${getAttributes()} + +--- + +Abilities + + +### Actions + +}}` + + + } +}; \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/note.snippet.js b/shared/homebrewery/snippets/brew/note.snippet.js new file mode 100644 index 0000000..18c9233 --- /dev/null +++ b/shared/homebrewery/snippets/brew/note.snippet.js @@ -0,0 +1,22 @@ +const _ = require('lodash'); +const Data = require('./random.data.js'); + + +module.exports = { + note : ()=>{ + return `{{note +##### ${Data.rand('abilities')} +${Data.rand('sentences', 6, 4).join(' ')} +}}` + + }, + + altnote : ()=>{ + return `{{note,alt +##### ${Data.rand('abilities')} +${Data.rand('sentences', 6, 4).join(' ')} +}}` + } + + +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/random.data.js b/shared/homebrewery/snippets/brew/random.data.js new file mode 100644 index 0000000..d360a2d --- /dev/null +++ b/shared/homebrewery/snippets/brew/random.data.js @@ -0,0 +1,421 @@ +const _ = require('lodash'); + +const Data = { + rand : (name, max = 1, min = 1)=>{ + const data = (Data[name] ? Data[name] : name); + return _.sampleSize(data, _.random(min, max)); + }, + + titles : [ + `The Burning Gallows`, + `The Ring of Nenlast`, + `Below the Blind Tavern`, + `Below the Hungering River`, + `Before Bahamut's Land`, + `The Cruel Grave from Within`, + `The Strength of Trade Road`, + `Through The Raven Queen's Worlds`, + `Within the Settlement`, + `The Crown from Within`, + `The Merchant Within the Battlefield`, + `Ioun's Fading Traveler`, + `The Legion Ingredient`, + `The Explorer Lure`, + `Before the Charming Badlands`, + `The Living Dead Above the Fearful Cage`, + `Vecna's Hidden Sage`, + `Bahamut's Demonspawn`, + `Across Gruumsh's Elemental Chaos`, + `The Blade of Orcus`, + `Beyond Revenge`, + `Brain of Insanity`, + `Breed Battle!, A New Beginning`, + `Evil Lake, A New Beginning`, + `Invasion of the Gigantic Cat, Part II`, + `Kraken War 2020`, + `The Body Whisperers`, + `The Diabolical Tales of the Ape-Women`, + `The Doctor Immortal`, + `The Doctor from Heaven`, + `Azure Core`, + `Core Battle`, + `Core of Heaven: The Guardian of Amazement`, + `Deadly Amazement III`, + `Dry Chaos IX`, + `Gate Thunder`, + `Guardian: Skies of the Dark Wizard`, + `Lute of Eternity`, + `Mercury's Planet: Brave Evolution`, + `Ruby of Atlantis: The Quake of Peace`, + `Vyse's Skies`, + `White Greatness III`, + `Yellow Divinity`, + `Zidane's Ghost` + ], + + subtitles : [ + `In an ominous universe, a botanist opposes terrorism.`, + `In a demon-haunted city, in an age of lies and hate, a physicist tries to find an ancient treasure and battles a mob of aliens.`, + `In a land of corruption, two cyberneticists and a dungeon delver search for freedom.`, + `In an evil empire of horror, two rangers battle the forces of hell.`, + `In a lost city, in an age of sorcery, a librarian quests for revenge.`, + `In a universe of illusions and danger, three time travellers and an adventurer search for justice.`, + `In a forgotten universe of barbarism, in an era of terror and mysticism, a virtual reality programmer and a spy try to find vengance and battle crime.`, + `In a universe of demons, in an era of insanity and ghosts, three bodyguards and a bodyguard try to find vengance.`, + `In a kingdom of corruption and battle, seven artificial intelligences try to save the last living fertile woman.`, + `In a universe of virutal reality and agony, in an age of ghosts and ghosts, a fortune-teller and a wanderer try to avert the apocalypse.`, + `In a crime-infested kingdom, three martial artists quest for the truth and oppose evil.`, + `In a terrifying universe of lost souls, in an era of lost souls, eight dancers fight evil.`, + `In a galaxy of confusion and insanity, three martial artists and a duke battle a mob of psychics.`, + `In an amazing kingdom, a wizard and a secretary hope to prevent the destruction of mankind.`, + `In a kingdom of deception, a reporter searches for fame.`, + `In a hellish empire, a swordswoman and a duke try to find the ultimate weapon and battle a conspiracy.`, + `In an evil galaxy of illusion, in a time of technology and misery, seven psychiatrists battle crime.`, + `In a dark city of confusion, three swordswomen and a singer battle lawlessness.`, + `In an ominous empire, in an age of hate, two philosophers and a student try to find justice and battle a mob of mages intent on stealing the souls of the innocent.`, + `In a kingdom of panic, six adventurers oppose lawlessness.`, + `In a land of dreams and hopelessness, three hackers and a cyborg search for justice.`, + `On a planet of mysticism, three travelers and a fire fighter quest for the ultimate weapon and oppose evil.`, + `In a wicked universe, five seers fight lawlessness.`, + `In a kingdom of death, in an era of illusion and blood, four colonists search for fame.`, + `In an amazing kingdom, in an age of sorcery and lost souls, eight space pirates quest for freedom.`, + `In a cursed empire, five inventors oppose terrorism.`, + `On a crime-ridden planet of conspiracy, a watchman and an artificial intelligence try to find love and oppose lawlessness.`, + `In a forgotten land, a reporter and a spy try to stop the apocalypse.`, + `In a forbidden land of prophecy, a scientist and an archivist oppose a cabal of barbarians intent on stealing the souls of the innocent.`, + `On an infernal world of illusion, a grave robber and a watchman try to find revenge and combat a syndicate of mages intent on stealing the source of all magic.`, + `In a galaxy of dark magic, four fighters seek freedom.`, + `In an empire of deception, six tomb-robbers quest for the ultimate weapon and combat an army of raiders.`, + `In a kingdom of corruption and lost souls, in an age of panic, eight planetologists oppose evil.`, + `In a galaxy of misery and hopelessness, in a time of agony and pain, five planetologists search for vengance.`, + `In a universe of technology and insanity, in a time of sorcery, a computer techician quests for hope.`, + `On a planet of dark magic and barbarism, in an age of horror and blasphemy, seven librarians search for fame.`, + `In an empire of dark magic, in a time of blood and illusions, four monks try to find the ultimate weapon and combat terrorism.`, + `In a forgotten empire of dark magic, six kings try to prevent the destruction of mankind.`, + `In a galaxy of dark magic and horror, in an age of hopelessness, four marines and an outlaw combat evil.`, + `In a mysterious city of illusion, in an age of computerization, a witch-hunter tries to find the ultimate weapon and opposes an evil corporation.`, + `In a damned kingdom of technology, a virtual reality programmer and a fighter seek fame.`, + `In a hellish kingdom, in an age of blasphemy and blasphemy, an astrologer searches for fame.`, + `In a damned world of devils, an alien and a ranger quest for love and oppose a syndicate of demons.`, + `In a cursed galaxy, in a time of pain, seven librarians hope to avert the apocalypse.`, + `In a crime-infested galaxy, in an era of hopelessness and panic, three champions and a grave robber try to solve the ultimate crime.` + ], + + classes : [ + 'Archivist', + 'Armadillomaster', + 'Beat Priest', + 'Beer Mentalist', + 'Berserker-Typist', + 'Bonsai Hooligan', + 'Candy Finder', + 'Coffeemancer', + 'Concierge', + 'Corn Theif', + 'Cottonsmith', + 'Dirtmistress', + 'Fancyman', + 'Fishmongerer', + 'Fletcher', + 'Flow Robber', + 'Haberdasher', + 'Hamster Lady', + 'Jam Robber', + 'Linguist', + 'Lizard Trainer', + 'Manicurist', + 'Markermaster', + 'Mint Handler', + 'Narwhalologer', + 'Notary', + 'Otter Mentalist', + 'Plastic Diviner', + 'Rhymemancer', + 'Rum Buster', + 'Whaleologer', + ], + + + gear : [ + `a squeegee`, + '6 rubber chickens', + '10 lint fluffs', + '1 button', + 'a cherished lost sock', + 'a small doll', + 'hopes and dreams', + '1st born child', + '3rd born child', + 'a crushed button worth at least 1cp', + 'discarded gum wrapper', + `Broch of Air Blasts`, + `Elven Leather Armor`, + `Glaive of the Deathly Viper`, + `Mystical Eagle's Ointment of the Eagles`, + `Mystical Scintillating Cudgel`, + `Wise Thinker's Anklet`, + `The four fragments of the Disk of Madness` + ], + + + + spellNames : [ + "Astral Rite of Acne", + "Create Acne", + "Cursed Ramen Erruption", + "Dark Chant of the Dentists", + "Erruption of Immaturity", + "Flaming Disc of Inconvenience", + "Heal Bad Hygene", + "Heavenly Transfiguration of the Cream Devil", + "Hellish Cage of Mucus", + "Irritate Peanut Butter Fairy", + "Luminous Erruption of Tea", + "Mystic Spell of the Poser", + "Sorcerous Enchantment of the Chimneysweep", + "Steak Sauce Ray", + "Talk to Groupie", + "Astonishing Chant of Chocolate", + "Astounding Pasta Puddle", + "Ball of Annoyance", + "Cage of Yarn", + "Control Noodles Elemental", + "Create Nervousness", + "Cure Baldness", + "Cursed Ritual of Bad Hair", + "Dispell Piles in Dentist", + "Eliminate Florists", + "Illusionary Transfiguration of the Babysitter", + "Necromantic Armor of Salad Dressing", + "Occult Transfiguration of Foot Fetish", + "Protection from Mucus Giant", + "Tinsel Blast", + "Alchemical Evocation of the Goths", + "Call Fangirl", + "Divine Spell of Crossdressing", + "Dominate Ramen Giant", + "Eliminate Vindictiveness in Gym Teacher", + "Extra-Planar Spell of Irritation", + "Induce Whining in Babysitter", + "Invoke Complaining", + "Magical Enchantment of Arrogance", + "Occult Globe of Salad Dressing", + "Overwhelming Enchantment of the Chocolate Fairy", + "Sorcerous Dandruff Globe", + "Spiritual Invocation of the Costumers", + "Ultimate Rite of the Confetti Angel", + "Ultimate Ritual of Mouthwash", + + ], + + effects : [ + 'Induces politicians to parade through the streets naked, and makes the nearest unbetrothed prince or princess dance around the maypole making dirty jokes.', + 'Tricks enchanted princesses to spin straw into gold, and makes princesses trapped in towers steal from the rich and give to the poor.', + 'Drives the man or woman of your dreams to jump up and down on the spot, and makes angry dragons grow onions wherever they walk.', + 'Causes enchanted talking animals to fall down dead, and makes large pumpkins attract love-struck unicorns.', + 'Induces officers of the law to adopt small, fluffy bunnies as pets, and makes enchanted wooden puppets vomit gold coins.', + 'Causes accountants to give you all of their possessions, and makes officers of the law grow mushrooms out of their ears.', + 'Induces goats to eat until they burst, and makes men with small heads vomit gold coins.', + 'Tricks enchanted princesses to turn into small pumpkins, and makes evil landlords declare themselves king.', + 'Induces your enemies to steal from the palace cook, and makes rich merchants propose marriage.', + 'Causes evil landlords to vomit gold coins, and makes the nearest unbetrothed prince or princess drink beer.', + 'Induces men with small heads to grow mushrooms out of their ears, and makes witches steal from the rich and give to the poor.', + `Conjures food with energy equal to whatever was used to cast the spell.`, + `Allows a living target to withstand extreme cold.`, + `Conjures a thick fog that acts as a smoke screen.`, + `Creates a bubble in which time is stopped for a short period.`, + `Creates several bolts of shadowy energy.`, + `Causes a living target to panic for a period of time.`, + `Creates a floating scroll and quill that'll write down everything the caster or target says for a period of time.`, + `Causes whoever is targeted to enter a state of confusion for a period of time.`, + `Creates a magical barrier that blocks all with dark intentions or dark influences over them.`, + `Creates a bolt of demonic energy.`, + `Causes whoever is targeted to drop whatever they're holding.` + ], + + effects2 : [ + 'Unless they pass a Constitution save, the creature gains 1 level of Exhaustion.', + 'Pushed 5 feet unless they pass a Strength save. ', + 'Unless they pass a Wisdom save, the creature is Charmed.', + 'Unless they pass a Wisdom save, the creature is Frightened. The creature can remake this save on each of their turns.', + 'Unless they pass a Wisdom save, the creature is Frightened. The creature can remake this save on each of their turns.', + 'Unless they pass a Wisdom save, the creature is Paralyzed. The creature can remake this save on each of their turns.', + 'Pushed 25 feet unless they pass a Strength save. ', + 'Unless they pass a Constitution save, the creature is Poisoned. The creature can remake this save on each of their turns.', + 'Unless they pass a Wisdom save, the creature is Charmed.', + 'Unless they pass a Constitution save, the creature is Slowed. The creature can remake this save on each of their turns.', + 'Unless they pass a Constitution save, the creature is Slowed. The creature can remake this save on each of their turns.', + 'Knocked Prone unless they pass a Dexterity save. ', + 'Unless they pass a Constitution save, the creature is Deafened. The creature can remake this save on each of their turns.', + 'Knocked Prone unless they pass a Dexterity save. ', + 'Unless they pass a Constitution save, the creature gains 1 level of Exhaustion.', + 'Knocked Prone unless they pass a Dexterity save. ', + 'Unless they pass a Constitution save, the creature is Deafened. The creature can remake this save on each of their turns.', + 'Unless they pass a Constitution save, the creature gains 1 level of Exhaustion.', + 'Pushed 20 feet unless they pass a Strength save. ', + 'Resistance to Radiant damage until 1 round' + + ], + + attacks : [ + `Aquatic Press of the Romantic Demons`, + `Barbarian Raider Pinch of the Cemetary`, + `Beetle Hold of the Fangs`, + `Confident Badger Pinch of Lyres`, + `Emperor's Roll of the Nine Volcanos`, + `Firey Rake of the Endings`, + `Fortuitous Underhook of the Wolves`, + `God's Knee of Blessings`, + `Hawk Dance`, + `Heavenly Rat's Roll`, + `Hellish Meteor`, + `High Noose of the Ruthless Guardian`, + `Hold of Poisons`, + `King Drop of the Fighting Protectors`, + `Leg Clap of the Dogs`, + `Northeastern Seventeen Cats Claw`, + `Phantasmal Plague Finger`, + `Pose of Perfect Sunsets`, + `Seal Hammer of the Forty Sages`, + `Shaman Pull of Destructions`, + `Southeastern Automaton Pull`, + `Southwestern Eighty Chants Clap`, + `Tackle of Foul Leaves`, + `Tornado of the Uncounted Hawks`, + `Yielding Throw of the Mills`, + ], + + abilities : [ + "Astrological Botany", + "Astrological Chemistry", + "Biochemical Sorcery", + "Civil Alchemy", + "Consecrated Biochemistry", + "Demonic Anthropology", + "Divinatory Mineralogy", + "Genetic Banishing", + "Hermetic Geography", + "Immunological Incantations", + "Nuclear Illusionism", + "Ritual Astronomy", + "Seismological Divination", + "Spiritual Biochemistry", + "Statistical Occultism", + "Police Necromancer", + "Sixgun Poisoner", + "Pharmaceutical Gunslinger", + "Infernal Banker", + "Spell Analyst", + "Gunslinger Corruptor", + "Torque Interfacer", + "Exo Interfacer", + "Gunpowder Torturer", + "Orbital Gravedigger", + "Phased Linguist", + "Mathematical Pharmacist", + "Plasma Outlaw", + "Malefic Chemist", + "Police Cultist" + ], + + alignments : [ + "Annoying Evil", + "Chaotic Gossipy", + "Chaotic Sloppy", + "Depressed Neutral", + "Lawful Bogus", + "Lawful Coy", + "Manic-Depressive Evil", + "Narrow-Minded Neutral", + "Neutral Annoying", + "Neutral Ignorant", + "Oedpipal Neutral", + "Silly Neutral", + "Unoriginal Neutral", + "Weird Neutral", + "Wordy Evil", + "Unaligned", + "Lawful Gossipy", + "Neurotic Good", + "Sarcastic Evil", + "Snotty Neutral", + "Wannabe Good" + ], + + sizes : ['Microscopic', 'Tiny', 'Small', 'Medium', 'Large', 'Gargantuan', 'Stupidly vast'], + levels : ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", "20th"], + + + sentences : [ + `The suspicion arises the narrator of the tale is actually a demon.`, + `There is a predicted hurricane - but it's not what was expected, and this complicates the plans of the protagonist.`, + `The antagonist's believes their life has changed for the strange - this turns out to be this is due to being lied to by others`, + `An accidental cuddle leads to complications.`, + `It's revealed that everything that is happening is all a dream.`, + `There is a sudden hurricane.`, + `The alternate protagonist is revealed to be a different race/species than thought, which suddenly makes what's going on much clearer.`, + `Thanks to alien forces, the characters end up in the earth's past.`, + `Thanks to alien forces, the secondary protagonist ends up in a world after an apocalypse.`, + `Due to a panic attack a character has to get psychological therapy.`, + ], + + + + creatures : [ + "All-devouring Baseball Imp", + "All-devouring Gumdrop Wraith", + "Chocolate Hydra", + "Devouring Peacock", + "Economy-sized Colossus of the Lemonade Stand", + "Ghost Pigeon", + "Gibbering Duck", + "Sparklemuffin Peacock Spider", + "Gum Elemental", + "Illiterate Construct of the Candy Store", + "Ineffable Chihuahua", + "Irritating Death Hamster", + "Irritating Gold Mouse", + "Juggernaut Snail", + "Juggernaut of the Sock Drawer", + "Koala of the Cosmos", + "Mad Koala of the West", + "Milk Djinni of the Lemonade Stand", + "Mind Ferret", + "Mystic Salt Spider", + "Necrotic Halitosis Angel", + "Pinstriped Famine Sheep", + "Ritalin Leech", + "Shocker Kangaroo", + "Stellar Tennis Juggernaut", + "Wailing Quail of the Sun", + "Angel Pigeon", + "Anime Sphinx", + "Bored Avalanche Sheep of the Wasteland", + "Devouring Nougat Sphinx of the Sock Drawer", + "Djinni of the Footlocker", + "Ectoplasmic Jazz Devil", + "Flatuent Angel", + "Gelatinous Duck of the Dream-Lands", + "Gelatinous Mouse", + "Golem of the Footlocker", + "Lich Wombat", + "Mechanical Sloth of the Past", + "Milkshake Succubus", + "Puffy Bone Peacock of the East", + "Rainbow Manatee", + "Rune Parrot", + "Sand Cow", + "Sinister Vanilla Dragon", + "Snail of the North", + "Spider of the Sewer", + "Stellar Sawdust Leech", + "Storm Anteater of Hell", + "Stupid Spirit of the Brewery", + "Time Kangaroo", + "Tomb Poodle" + + ] + +}; + +module.exports = Data; \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/spell.snippet.js b/shared/homebrewery/snippets/brew/spell.snippet.js new file mode 100644 index 0000000..658dfc1 --- /dev/null +++ b/shared/homebrewery/snippets/brew/spell.snippet.js @@ -0,0 +1,41 @@ +const _ = require('lodash'); +const Data = require('./random.data.js'); + + +const levels = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th']; +const schools = ['abjuration', 'conjuration', 'divination', 'enchantment', 'evocation', 'illusion', 'necromancy', 'transmutation']; + + + +module.exports = { + spell : ()=>{ + + let components = _.sampleSize(['V', 'S', 'M'], _.random(1,3)).join(', '); + if(components.indexOf('M') !== -1){ + components += ` (${Data.rand('gear',3).join(', ')})` + } + + const duration = _.sample([ + 'Until dispelled', + '1 round', + 'Instantaneous', + 'Concentration, up to 10 minutes', + '1 hour' + ]); + + const description = Data.rand('effects', 2).concat(Data.rand('effects2')).join(' '); + + + return `{{spell +#### ${_.sample(Data.spellNames)} +*${_.sample(levels)}-level ${_.sample(schools)}* +- **Casting Time:** ${_.sample(['1 action', 'Reaction', '10 minutes', '1 hour'])} +- **Range:** ${_.sample(['Self', 'Touch', '30 feet', '60 feet'])} +- **Components:** ${components} +- **Duration:** ${duration} + +${description} +}}`; + + } +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/table.snippet.js b/shared/homebrewery/snippets/brew/table.snippet.js new file mode 100644 index 0000000..00ad1ff --- /dev/null +++ b/shared/homebrewery/snippets/brew/table.snippet.js @@ -0,0 +1,62 @@ +const _ = require('lodash'); +const Data = require('./random.data.js'); + + + +/* +- Roll +- Level +- Cost + +- spell lists +- cost +- Class + +*/ + + +const columns = { + roll : (rows)=>{ + return _.concat([`d${rows}`, ':---:'], _.times(rows, (i)=>i+1)); + }, + level : (rows)=>{ + return _.concat([`${_.sample(Data.classes)} Level`, ':---:'], _.times(rows, (i)=>Data.levels[i*2])); + }, + + spell : (rows)=>{ + return _.concat(['Spells', ':---'], _.times(rows, (i)=>{ + return `_${Data.rand('spellNames', 2).join(', ')}_` + })); + }, + cost : (rows)=>{ + return _.concat([`Cost`, '---:'], _.times(rows, (i)=>{ + return _.sample(['1 gp', '10 gp', '5 cp', '10,000 gp', '200 sp', '1 pp', '2 gp']); + })); + }, + gear : (rows)=>{ + return _.concat([_.sample(['Equipment', 'Reward', 'Treasure']), ':---'], _.times(rows, (i)=>{ + return Data.rand('gear'); + })); + } +} + + +module.exports = { + table : () => { + const rows = _.sample([4,6,8,10]); + + const cols = [ + columns.roll(rows), + columns.level(rows), + columns.gear(rows) + ]; + + return _.times(rows + 2, (i)=>{ + if(i==1){ + return '|' + _.map(cols, (col)=>col[i]).join('|') + '|'; + }else{ + return '| ' + _.map(cols, (col)=>col[i]).join(' | ') + ' |'; + } + }).join('\n'); + } +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/brew/toc.snippet.js b/shared/homebrewery/snippets/brew/toc.snippet.js new file mode 100644 index 0000000..bd41168 --- /dev/null +++ b/shared/homebrewery/snippets/brew/toc.snippet.js @@ -0,0 +1,112 @@ +const _ = require('lodash'); +const Store = require('homebrewery/brew.store.js'); + +const getTOC = (text) => { + const pages = text.split('\\page'); + const add1 = (title, page)=>{ + res.push({ + title : title, + page : page + 1, + children : [] + }); + } + const add2 = (title, page)=>{ + if(!_.last(res)) add1('', page); + _.last(res).children.push({ + title : title, + page : page + 1, + children : [] + }); + } + const add3 = (title, page)=>{ + if(!_.last(res)) add1('', page); + if(!_.last(_.last(res).children)) add2('', page); + _.last(_.last(res).children).children.push({ + title : title, + page : page + 1, + children : [] + }); + } + + let res = []; + _.each(pages, (page, pageNum)=>{ + const lines = page.split('\n'); + _.each(lines, (line) => { + if(_.startsWith(line, '# ')){ + const title = line.replace('# ', ''); + add1(title, pageNum) + } + if(_.startsWith(line, '## ')){ + const title = line.replace('## ', ''); + add2(title, pageNum); + } + if(_.startsWith(line, '### ')){ + const title = line.replace('### ', ''); + add3(title, pageNum); + } + }) + }); + return res; +} + + +module.exports = { + //TODO: TOC not perfect yet + + toc : (text)=>{ + text = text || Store.getBrewCode(); + + console.log(getTOC(text)); + + const TOC = getTOC(text) + + const markdown = _.reduce(TOC, (r, g1, idx1)=>{ + r.push(`- ### [**${g1.page}** *${g1.title}*](#p${g1.page})`) + if(g1.children.length){ + _.each(g1.children, (g2, idx2) => { + r.push(` - #### [**${g2.page}** *${g2.title}*](#p${g2.page})`) + if(g2.children.length){ + _.each(g2.children, (g3, idx3) => { + r.push(` - [**${g3.page}** *${g3.title}*](#p${g3.page})`) + }); + } + }); + } + return r; + }, []).join('\n'); + + + + return `{{toc +# Contents + +${markdown} + +}}`; +/* + +- ### [**4** *Preface*](#p3) +- ### [**5** *Introduction*](#p3) + - [**5** *Worlds of Adventure*](#p5) + - [**6** *Using This Book*](#p5) + - [**6** *How to Play*](#p5) + - [**7** *Adventures*](#p5) + +- ### [**5** *Introduction*](#p3) + - #### [**5** *Worlds of Adventure*](#p5) + - [**6** *Using This Book*](#p5) + - [**6** *How to Play*](#p5) + - #### [**7** *Adventures*](#p5) + + + + + + + +}} + + +`;*/ + } +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/index.js b/shared/homebrewery/snippets/index.js new file mode 100644 index 0000000..3311a8c --- /dev/null +++ b/shared/homebrewery/snippets/index.js @@ -0,0 +1,4 @@ +module.exports = { + brew : require('./brew'), + style : require('./style') +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/style/a4.snippet.js b/shared/homebrewery/snippets/style/a4.snippet.js new file mode 100644 index 0000000..bc62d33 --- /dev/null +++ b/shared/homebrewery/snippets/style/a4.snippet.js @@ -0,0 +1,8 @@ +module.exports = { + a4 : ()=>{ + return `.phb{ + width : 210mm; + height : 296.8mm; +}`; + } +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/style/bg.snippet.js b/shared/homebrewery/snippets/style/bg.snippet.js new file mode 100644 index 0000000..b898f0e --- /dev/null +++ b/shared/homebrewery/snippets/style/bg.snippet.js @@ -0,0 +1,12 @@ +module.exports = { + dmg : ()=>{ + return `.phb{ + background-image: url('/assets/homebrewery/phb_style/img/dmg_bg.jpg'); +}`; + }, + dark: ()=>{ + return `.phb{ + background-image: url('/assets/homebrewery/phb_style/img/phb_dark_bg.jpg'); +}`; + } +} \ No newline at end of file diff --git a/shared/homebrewery/snippets/style/index.js b/shared/homebrewery/snippets/style/index.js new file mode 100644 index 0000000..bdf313a --- /dev/null +++ b/shared/homebrewery/snippets/style/index.js @@ -0,0 +1,7 @@ +const _ = require('lodash'); + +module.exports = _.merge( + require('./ink.snippet.js'), + require('./a4.snippet.js'), + require('./bg.snippet.js') +); diff --git a/shared/homebrewery/snippets/style/ink.snippet.js b/shared/homebrewery/snippets/style/ink.snippet.js new file mode 100644 index 0000000..ffd6d1e --- /dev/null +++ b/shared/homebrewery/snippets/style/ink.snippet.js @@ -0,0 +1,9 @@ + + +module.exports = { + inkFriendly : ()=>{ + return `.phb{ background : white;} +.phb img{ display : none;} +.phb hr+blockquote{background : white;}`; + } +} \ No newline at end of file diff --git a/shared/naturalcrit/nav/nav.jsx b/shared/naturalcrit/nav/nav.jsx index 6439548..0f7ce49 100644 --- a/shared/naturalcrit/nav/nav.jsx +++ b/shared/naturalcrit/nav/nav.jsx @@ -38,28 +38,29 @@ var Nav = { href : null, newTab : false, onClick : function(){}, - color : null + color : null, + collaspe : false }; }, handleClick : function(){ this.props.onClick(); }, render : function(){ - var classes = cx('navItem', this.props.color, this.props.className); + var classes = cx('navItem', this.props.color, this.props.className, {collaspe : this.props.collaspe}); var icon; if(this.props.icon) icon = ; - const props = _.omit(this.props, ['newTab']); + const props = _.omit(this.props, ['newTab', 'collaspe']); if(this.props.href){ return - {this.props.children} + {this.props.children} {icon} }else{ return
- {this.props.children} + {this.props.children} {icon}
} diff --git a/shared/naturalcrit/nav/nav.less b/shared/naturalcrit/nav/nav.less index 94ce5ca..72d3027 100644 --- a/shared/naturalcrit/nav/nav.less +++ b/shared/naturalcrit/nav/nav.less @@ -1,3 +1,4 @@ + nav{ background-color : #333; .navContent{ @@ -41,6 +42,7 @@ nav{ } .navItem{ .animate(background-color); + display : inline-block; padding : 8px 12px; cursor : pointer; background-color : #333; @@ -53,6 +55,28 @@ nav{ margin-left : 5px; font-size : 13px; } + &.collaspe{ + overflow : hidden; + i{ + margin-left : 0px; + } + span{ + display : inline-block; + visibility : hidden; + overflow : hidden; + width : 0px; + white-space : nowrap; + } + &:hover{ + span{ + visibility : visible; + width : auto; + } + i{ + margin-left : 5px; + } + } + } &.tealLight:hover{ background-color : @tealLight }; &.teal:hover{ background-color : @teal }; &.greenLight:hover{ background-color : @greenLight }; diff --git a/changelog.md b/statics/changelog.md similarity index 97% rename from changelog.md rename to statics/changelog.md index cc60014..a6da7f7 100644 --- a/changelog.md +++ b/statics/changelog.md @@ -1,5 +1,9 @@ # changelog + +The self-discovery aspect of the snippets isn't working out. + + ## BIG NEWS With the next major release of Homebrewery, v3.0.0, this tool *will no longer support raw HTML input for brew code*. Most issues and errors users are having are because of this feature and it's become too taxing to help and fix these issues. diff --git a/statics/faq.md b/statics/faq.md new file mode 100644 index 0000000..59eb9bd --- /dev/null +++ b/statics/faq.md @@ -0,0 +1,107 @@ +- Submitting work created on this site to DMs Guild + + +# I lost my brew? +- If you made any edits with an account, you can go to that account's page +- Homebrewery stores the last handful of brews you've viewed or edited under the recent brews tab +- Check your browser history for the edit link +- If all of that fails, find the share link, open the source and copy it into a new brew. + + +# Images +Image basics +- background images +- Adding brushes + + +How to make spacers + + +- How to skip page numbers +- How to set page number +- How to hide footers +#p1:before, #p1:after{ display:none } +#p2:before{ counter-reset: phb-page-numbers 30; } + + +- blockquotes, cite + +styling images + + +# Print +- Saving ink +- Changing page size +- Printing to PDF + + + +## Changing backgrounds +{{wide +In style +``` +#p3{ + background-image : url('/assets/homebrewery/phb_style/img/dmg_bg.jpg') +} + +``` +}} + +## Changes in v3 + +``` ``` -> \column + + +\page + +## Columns +{{wide,twoColumn +This is how columns work sdfsdfsdf +``` +{{twoColumn + +| d4 | Manicurist Level | Equipment | +|:---:|:---:|:---| +| 1 | 1st | The four fragments of the Disk of Madness | +| 2 | 3rd | Broch of Air Blasts | +| 3 | 5th | The four fragments of the Disk of Madness | +| 4 | 7th | 3rd born child | + + +| d4 | Manicurist Level | Equipment | +|:---:|:---:|:---| +| 1 | 1st | The four fragments of the Disk of Madness | +| 2 | 3rd | Broch of Air Blasts | +| 3 | 5th | The four fragments of the Disk of Madness | +| 4 | 7th | 3rd born child | + +}} + +``` + +\column + + +{{twoColumn + +| d4 | Manicurist Level | Equipment | +|:---:|:---:|:---| +| 1 | 1st | The four fragments of the Disk of Madness | +| 2 | 3rd | Broch of Air Blasts | +| 3 | 5th | The four fragments of the Disk of Madness | +| 4 | 7th | 3rd born child | + + +| d4 | Manicurist Level | Equipment | +|:---:|:---:|:---| +| 1 | 1st | The four fragments of the Disk of Madness | +| 2 | 3rd | Broch of Air Blasts | +| 3 | 5th | The four fragments of the Disk of Madness | +| 4 | 7th | 3rd born child | + +}} + +}} + +this is after + diff --git a/statics/test.brew.md b/statics/test.brew.md index fdd7f82..9fe7bb0 100644 --- a/statics/test.brew.md +++ b/statics/test.brew.md @@ -18,22 +18,53 @@ Like this tool? Want to buy me a beer? [Head here](https://www.patreon.com/stolk This tool will **always** be free, never have ads, and I will never offer any "premium" features or whatever. +{{note,yellow,alt +##### PDF Exporting + PDF Printing works best in Chrome. If you are having quality/consistency issues, try using Chrome to print instead. + + After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up. + * Set the **Destination** to "Save as PDF" + * Set **Paper Size** to "Letter" + * If you are printing on A4 paper, make sure to have the "A4 page size snippet" in your brew + * In **Options** make sure "Background Images" is selected. + * Hit print and enjoy! You're done! + + If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print ->##### PDF Exporting -> PDF Printing works best in Chrome. If you are having quality/consistency issues, try using Chrome to print instead. +}} + +> This is a cool blockquote fdgfgsfg sfd sdfsdfsdfsdfsdfsdf sdfsdfsdfssdfsdffgsdfgsdfg +> You know? > -> After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up. -> * Set the **Destination** to "Save as PDF" -> * Set **Paper Size** to "Letter" -> * If you are printing on A4 paper, make sure to have the "A4 page size snippet" in your brew -> * In **Options** make sure "Background Images" is selected. -> * Hit print and enjoy! You're done! -> -> If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print +> One with quotes and what not +> yeah yeah yeah +> {{cite -- Very cool person }} +{{note +##### PDF Exporting + PDF Printing works best in Chrome. If you are having quality/consistency issues, try using Chrome to print instead. + + After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up. + * Set the **Destination** to "Save as PDF" + * Set **Paper Size** to "Letter" + * If you are printing on A4 paper, make sure to have the "A4 page size snippet" in your brew + * In **Options** make sure "Background Images" is selected. + * Hit print and enjoy! You're done! + + If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print + + +}} + + +![test](http://i.imgur.com/hMna6G0.png) + ``` +cool stuff + + ``` ## Big things coming in v3.0.0 @@ -55,18 +86,15 @@ If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana]( - - -
1
-
PART 1 | FANCINESS
+{{footnote PART 1 | FANCINESS }} \page -{{classTable,wide +{{frame,wide ##### The Archivist | Level | Proficiency Bonus | Features | Statistical Occultism| |:---:|:---:|:---|:---:| diff --git a/welcome.brew.md b/statics/welcome.brew.md similarity index 100% rename from welcome.brew.md rename to statics/welcome.brew.md