diff --git a/changelog.md b/changelog.md index f4a7300b3..663b6752a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,18 @@ # changelog +### Saturday, 03/12/2016 - v2.6.0 +- Added report back to the edit page +- Changed metaeditor icon +- Added a button to quickly share your brew to reddit :) +- Disabled Partial Page Rendering unless your brew hits 75 pages or longer +- The brew renderer will now try and use your first page to judge the page size of each of your brews. This allows you now to set landscape and other weird sizes and everthing should work fine :) +- UI on the user page improved (thanks u/PalaNolho) +- Fixed lists not breaking across columns (thanks u/tyson-nw) +- Added a table of contents snippet (thanks u/tullisar) +- Added a multicolumn snippet + + + ### Thursday, 01/12/2016 - Added in a snippet for a split table - Added an account nav item to new page diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index b81bbb3ba..7e1c432aa 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -1,13 +1,14 @@ -var React = require('react'); -var _ = require('lodash'); -var cx = require('classnames'); +const React = require('react'); +const _ = require('lodash'); +const cx = require('classnames'); -var Markdown = require('naturalcrit/markdown.js'); -var ErrorBar = require('./errorBar/errorBar.jsx'); +const Markdown = require('naturalcrit/markdown.js'); +const ErrorBar = require('./errorBar/errorBar.jsx'); -var PAGE_HEIGHT = 1056 + 30; +const PAGE_HEIGHT = 1056; +const PPR_THRESHOLD = 50; -var BrewRenderer = React.createClass({ +const BrewRenderer = React.createClass({ getDefaultProps: function() { return { text : '', @@ -15,16 +16,23 @@ var BrewRenderer = React.createClass({ }; }, getInitialState: function() { + const pages = this.props.text.split('\\page'); + return { viewablePageNumber: 0, height : 0, isMounted : false, + usePPR : true, + + pages : pages, + usePPR : pages.length >= PPR_THRESHOLD, + errors : [] }; }, - totalPages : 0, height : 0, + pageHeight : PAGE_HEIGHT, componentDidMount: function() { this.updateSize(); @@ -34,7 +42,21 @@ var BrewRenderer = React.createClass({ window.removeEventListener("resize", this.updateSize); }, + componentWillReceiveProps: function(nextProps) { + if(this.refs.pages.firstChild) this.pageHeight = this.refs.pages.firstChild.clientHeight; + + const pages = nextProps.text.split('\\page'); + this.setState({ + pages : pages, + usePPR : pages.length >= PPR_THRESHOLD + }) + }, + updateSize : function() { + setTimeout(()=>{ + if(this.refs.pages.firstChild) this.pageHeight = this.refs.pages.firstChild.clientHeight; + }, 1); + this.setState({ height : this.refs.main.parentNode.clientHeight, isMounted : true @@ -43,12 +65,9 @@ var BrewRenderer = React.createClass({ handleScroll : function(e){ this.setState({ - viewablePageNumber : Math.floor(e.target.scrollTop / PAGE_HEIGHT) + viewablePageNumber : Math.floor(e.target.scrollTop / this.pageHeight) }); }, - //Implement later - scrollToPage : function(pageNumber){ - }, shouldRender : function(pageText, index){ if(!this.state.isMounted) return false; @@ -66,7 +85,15 @@ var BrewRenderer = React.createClass({ renderPageInfo : function(){ return
- {this.state.viewablePageNumber + 1} / {this.totalPages} + {this.state.viewablePageNumber + 1} / {this.state.pages.length} +
+ }, + + renderPPRmsg : function(){ + if(!this.state.usePPR) return; + + return
+ Partial Page Renderer enabled, because your brew is so large. May effect rendering.
}, @@ -81,15 +108,18 @@ var BrewRenderer = React.createClass({ }, renderPages : function(){ - var pages = this.props.text.split('\\page'); - this.totalPages = pages.length; + if(this.state.usePPR){ + return _.map(this.state.pages, (page, index)=>{ + if(this.shouldRender(page, index)){ + return this.renderPage(page, index); + }else{ + return this.renderDummyPage(index); + } + }); + } - return _.map(pages, (page, index)=>{ - if(this.shouldRender(page, index)){ - return this.renderPage(page, index); - }else{ - return this.renderDummyPage(index); - } + return _.map(this.state.pages, (page, index)=>{ + return this.renderPage(page, index); }); }, @@ -101,10 +131,11 @@ var BrewRenderer = React.createClass({ -
+
{this.renderPages()}
{this.renderPageInfo()} + {this.renderPPRmsg()}
} }); diff --git a/client/homebrew/brewRenderer/brewRenderer.less b/client/homebrew/brewRenderer/brewRenderer.less index 8a854dd29..c893dbac4 100644 --- a/client/homebrew/brewRenderer/brewRenderer.less +++ b/client/homebrew/brewRenderer/brewRenderer.less @@ -16,6 +16,17 @@ font-weight : 800; color : white; } + .ppr_msg{ + position : absolute; + left : 0px; + bottom : 0; + z-index : 1000; + padding : 8px 10px; + background-color : #333; + font-size : 10px; + font-weight : 800; + color : white; + } .pages{ margin : 30px 0px; &>.phb{ diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index f25ec8a58..407d9c242 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -82,7 +82,11 @@ const Editor = React.createClass({ render : function(){ return(
- + {this.renderMetadataEditor()} { return
}, + renderShareToReddit : function(){ + if(!this.props.metadata.shareId) return; + + return
+ +
+ + + +
+
+ }, + render : function(){ - console.log(this.props.metadata); return
@@ -140,6 +164,8 @@ const MetadataEditor = React.createClass({
+ {this.renderShareToReddit()} + {this.renderDelete()} diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 89683e0e0..c3141f0d4 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -67,6 +67,11 @@ .button(@red); } } + .reddit.field .value{ + button{ + .button(@purple); + } + } .authors.field .value{ font-size: 0.8em; line-height : 1.5em; diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 2f93fbe1b..ffccbbf83 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -5,8 +5,8 @@ const cx = require('classnames'); const Snippets = require('./snippets/snippets.js'); -const execute = function(val){ - if(_.isFunction(val)) return val(); +const execute = function(val, brew){ + if(_.isFunction(val)) return val(brew); return val; } @@ -15,6 +15,7 @@ const execute = function(val){ const Snippetbar = React.createClass({ getDefaultProps: function() { return { + brew : '', onInject : ()=>{}, onToggle : ()=>{}, showmeta : false @@ -28,6 +29,7 @@ const Snippetbar = React.createClass({ renderSnippetGroups : function(){ return _.map(Snippets, (snippetGroup)=>{ return - + } @@ -58,6 +60,7 @@ module.exports = Snippetbar; const SnippetGroup = React.createClass({ getDefaultProps: function() { return { + brew : '', groupName : '', icon : 'fa-rocket', snippets : [], @@ -65,7 +68,7 @@ const SnippetGroup = React.createClass({ }; }, handleSnippetClick : function(snippet){ - this.props.onSnippetClick(execute(snippet.gen)); + this.props.onSnippetClick(execute(snippet.gen, this.props.brew)); }, renderSnippets : function(){ return _.map(this.props.snippets, (snippet)=>{ diff --git a/client/homebrew/editor/snippetbar/snippets/snippets.js b/client/homebrew/editor/snippetbar/snippets/snippets.js index 60a0f2327..bcb1df96f 100644 --- a/client/homebrew/editor/snippetbar/snippets/snippets.js +++ b/client/homebrew/editor/snippetbar/snippets/snippets.js @@ -4,6 +4,7 @@ var MonsterBlockGen = require('./monsterblock.gen.js'); var ClassFeatureGen = require('./classfeature.gen.js'); var FullClassGen = require('./fullclass.gen.js'); var CoverPageGen = require('./coverpage.gen.js'); +var TableOfContentsGen = require('./tableOfContents.gen.js'); module.exports = [ @@ -70,6 +71,12 @@ module.exports = [ gen : "[Click here](#p3) to go to page 3\n" }, + { + name : "Table of Contents", + icon : 'fa-book', + gen : TableOfContentsGen + }, + ] }, diff --git a/client/homebrew/editor/snippetbar/snippets/tableOfContents.gen.js b/client/homebrew/editor/snippetbar/snippets/tableOfContents.gen.js new file mode 100644 index 000000000..448b2f4e1 --- /dev/null +++ b/client/homebrew/editor/snippetbar/snippets/tableOfContents.gen.js @@ -0,0 +1,72 @@ +const _ = require('lodash'); + +const getTOC = (pages) => { + 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 = 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})**`) + if(g1.children.length){ + _.each(g1.children, (g2, idx2) => { + r.push(` - [${idx1 + 1}.${idx2 + 1} ${g2.title}](#p${g2.page})`); + if(g2.children.length){ + _.each(g2.children, (g3, idx3) => { + r.push(` - [${idx1 + 1}.${idx2 + 1}.${idx3 + 1} ${g3.title}](#p${g3.page})`); + }); + } + }); + } + return r; + }, []).join('\n'); + + return `
+##### Table Of Contents +${markdown} +
\n`; +} \ No newline at end of file diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index db5adb2fa..64c61f8c2 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -193,6 +193,7 @@ const EditPage = React.createClass({ {this.renderSaveButton()} {/**/} + Share diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 6bf1e58e1..c15a8ecf6 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -5,6 +5,7 @@ const cx = require('classnames'); const Nav = require('naturalcrit/nav/nav.jsx'); const Navbar = require('../../navbar/navbar.jsx'); const PrintLink = require('../../navbar/print.navitem.jsx'); +const ReportIssue = require('../../navbar/issue.navitem.jsx'); //const RecentlyViewed = require('../../navbar/recent.navitem.jsx').viewed; const Account = require('../../navbar/account.navitem.jsx'); @@ -34,10 +35,12 @@ const SharePage = React.createClass({ }, handleControlKeys : function(e){ if(!(e.ctrlKey || e.metaKey)) return; - e.stopPropagation(); - e.preventDefault(); const P_KEY = 80; - if(e.keyCode == P_KEY) window.open(`/print/${this.props.brew.shareId}?dialog=true`, '_blank').focus(); + if(e.keyCode == P_KEY){ + window.open(`/print/${this.props.brew.shareId}?dialog=true`, '_blank').focus(); + e.stopPropagation(); + e.preventDefault(); + } }, render : function(){ @@ -48,6 +51,7 @@ const SharePage = React.createClass({ + {/**/} diff --git a/client/homebrew/pages/userPage/brewItem/brewItem.jsx b/client/homebrew/pages/userPage/brewItem/brewItem.jsx index c74a736be..fe694b2e1 100644 --- a/client/homebrew/pages/userPage/brewItem/brewItem.jsx +++ b/client/homebrew/pages/userPage/brewItem/brewItem.jsx @@ -15,23 +15,39 @@ const BrewItem = React.createClass({ }; }, + renderEditLink: function(){ + if(!this.props.brew.editId) return; + + return + + + }, + render : function(){ const brew = this.props.brew; - return
-

{brew.title}

-

{brew.description}

+ return
+

{brew.title}

+

{brew.description}


-
    -
  • Authors: {brew.authors.join(', ')}
  • -
  • - Last updated: - {moment(brew.updatedAt).fromNow()} -
  • -
  • Views: {brew.views}
  • -
- Share link - {(!!brew.editId ? Edit link : null)} +
+ + {brew.authors.join(', ')} + + + {brew.views} + + + {moment(brew.updatedAt).fromNow()} + +
+ +
+ + + + {this.renderEditLink()} +
} }); diff --git a/client/homebrew/pages/userPage/brewItem/brewItem.less b/client/homebrew/pages/userPage/brewItem/brewItem.less index 226399044..3dcbd5090 100644 --- a/client/homebrew/pages/userPage/brewItem/brewItem.less +++ b/client/homebrew/pages/userPage/brewItem/brewItem.less @@ -1,19 +1,60 @@ .brewItem{ + position : relative; display : inline-block; vertical-align : top; - width : 25%; + box-sizing : border-box; + box-sizing : border-box; + overflow : hidden; + width : 48%; + margin-right : 15px; margin-bottom : 15px; + padding : 5px 15px 5px 8px; + padding-right : 15px; + border : 1px solid #c9ad6a; + border-radius : 5px; -webkit-column-break-inside : avoid; page-break-inside : avoid; break-inside : avoid; - p.description{ - overflow : hidden; - width : 90%; - text-overflow : ellipsis; - white-space : nowrap; + h4{ + margin-bottom : 5px; + font-size : 2.2em; } - a{ - margin-right : 10px; + .info{ + font-family : ScalySans; + font-size : 1.2em; + &>span{ + margin-right : 15px; + } + } + &:hover{ + .links{ + opacity : 1; + } + } + &:nth-child(2n + 1){ + margin-right : 0px; + } + .links{ + .animate(opacity); + position : absolute; + top : 0px; + right : 0px; + height : 100%; + width : 2em; + opacity : 0; + background-color : fade(black, 60%); + text-align : center; + a{ + .animate(opacity); + display : block; + margin : 8px 0px; + opacity : 0.6; + font-size : 1.3em; + color : white; + &:hover{ + opacity : 1; + } + } } } \ No newline at end of file diff --git a/client/homebrew/pages/userPage/userPage.jsx b/client/homebrew/pages/userPage/userPage.jsx index 19f2a5c40..6d583e90a 100644 --- a/client/homebrew/pages/userPage/userPage.jsx +++ b/client/homebrew/pages/userPage/userPage.jsx @@ -10,11 +10,11 @@ const Account = require('../../navbar/account.navitem.jsx'); const BrewItem = require('./brewItem/brewItem.jsx'); const brew = { - title : 'test', + title : 'SUPER Long title woah now', authors : [] } -//const BREWS = _.times(25, ()=>{ return brew}); +const BREWS = _.times(25, ()=>{ return brew}); const UserPage = React.createClass({ @@ -26,9 +26,11 @@ const UserPage = React.createClass({ }, renderBrews : function(brews){ - if(!brews || !brews.length) return
No Brews.
+ if(!brews || !brews.length) return
No Brews.
; - return _.map(brews, (brew, idx) => { + const sortedBrews = _.sortBy(brews, (brew)=>{ return brew.title; }); + + return _.map(sortedBrews, (brew, idx) => { return }); }, diff --git a/client/homebrew/pages/userPage/userPage.less b/client/homebrew/pages/userPage/userPage.less index b2f257ab7..dcd0d6360 100644 --- a/client/homebrew/pages/userPage/userPage.less +++ b/client/homebrew/pages/userPage/userPage.less @@ -17,7 +17,7 @@ .phb{ .noColumns(); height : auto; - min-height : 350px; + min-height : 279.4mm; margin : 20px auto; &::after{ display : none; @@ -27,6 +27,7 @@ font-size : 1.3em; font-style : italic; } + } } } \ No newline at end of file diff --git a/client/homebrew/phbStyle/phb.style.less b/client/homebrew/phbStyle/phb.style.less index 7a5736fc7..80a9d0933 100644 --- a/client/homebrew/phbStyle/phb.style.less +++ b/client/homebrew/phbStyle/phb.style.less @@ -15,7 +15,7 @@ body { counter-reset : phb-page-numbers; } *{ - -webkit-print-color-adjust: exact; + -webkit-print-color-adjust : exact; } .useSansSerif(){ font-family : ScalySans; @@ -332,7 +332,7 @@ body { -moz-column-break-after : always; } //Avoid breaking up - p,ul,blockquote,table{ + p,blockquote,table{ z-index : 15; -webkit-column-break-inside : avoid; column-break-inside : avoid; @@ -351,6 +351,10 @@ body { margin-bottom : 0px; margin-left : 1.5em; } + li{ + -webkit-column-break-inside : avoid; + column-break-inside : avoid; + } } //***************************** // * SPELL LIST @@ -445,4 +449,25 @@ body { } .phb pre+.descriptive{ margin-top : 8px; +} +//***************************** +// * TABLE OF CONTENTS +// *****************************/ +.phb .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; + } } \ No newline at end of file diff --git a/package.json b/package.json index 4675d0dd7..e67844dfa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", - "version": "2.5.2", + "version": "2.6.0", "scripts": { "build": "node_modules/.bin/gulp prod", "watch": "node_modules/.bin/gulp", diff --git a/phb.standalone.css b/phb.standalone.css index adcf20c11..9133af9de 100644 --- a/phb.standalone.css +++ b/phb.standalone.css @@ -518,7 +518,6 @@ body { -moz-column-break-after: always; } .phb p, -.phb ul, .phb blockquote, .phb table { z-index: 15; @@ -540,6 +539,10 @@ body { margin-bottom: 0px; margin-left: 1.5em; } +.phb li { + -webkit-column-break-inside: avoid; + column-break-inside: avoid; +} .phb .spellList { font-family: ScalySans; column-count: 4; @@ -627,3 +630,21 @@ body { .phb pre + .descriptive { margin-top: 8px; } +.phb .toc { + -webkit-column-break-inside: avoid; + column-break-inside: avoid; +} +.phb .toc a { + color: black; + text-decoration: none; +} +.phb .toc a:hover { + text-decoration: underline; +} +.phb .toc ul { + padding-left: 0; + list-style-type: none; +} +.phb .toc > ul > li { + margin-bottom: 10px; +} diff --git a/shared/naturalcrit/nav/nav.jsx b/shared/naturalcrit/nav/nav.jsx index 84429a90d..6439548b3 100644 --- a/shared/naturalcrit/nav/nav.jsx +++ b/shared/naturalcrit/nav/nav.jsx @@ -50,13 +50,15 @@ var Nav = { var icon; if(this.props.icon) icon = ; + const props = _.omit(this.props, ['newTab']); + if(this.props.href){ - return + return {this.props.children} {icon} }else{ - return
+ return
{this.props.children} {icon}