1
0
mirror of https://github.com/stolksdorf/homebrewery.git synced 2025-12-23 03:31:29 +00:00

Merge branch 'v2.1'

This commit is contained in:
Scott Tolksdorf
2016-05-29 13:46:47 -04:00
202 changed files with 31419 additions and 31216 deletions

View File

@@ -1,5 +1,12 @@
# changelog # changelog
### Sunday, 29/05/2016 - v2.1.0
- Finally added a syntax for doing spell lists. A bit in-depth about why this took so long. Essentially I'm running out of syntax to use in stardard Markdown. There are too many unique elements in the PHB-style to be mapped. I solved this earlier by stacking certain elements together (eg. an `<hr>` before a `blockquote` turns it into moster state block), but those are getting unweildly. I would like to simply wrap these in `div`s with classes, but unfortunately Markdown stops processing when within HTML blocks. To get around this I wrote my own override to the Markdown parser and lexer to process Markdown within a simple div class wrapper. This should open the door for more unique syntaxes in the future. Big step!
- Override Ctrl+P (and cmd+P) to launch to the print page. Many people try to just print either the editing or share page to get a PDF. While this dones;t make much sense, I do get a ton of issues about it. So now if you try to do this, it'll just bring you imediately to the print page. Everybody wins!
- The onboarding flow has also been confusing a few users (Homepage -> new -> save -> edit page). If you edit the Homepage text now, a Call to Action to save your work will pop-up.
- Added a 'Recently Edited' and 'Recently Viewed' nav item to the edit and share page respectively. Each will remember the last 8 items you edited or viewed and when you viewed it. Makes use of the new title attribute of brews to easy navigatation.
- Paragraphs now indent properly after lists (thanks u/slitjen!)
### Friday, 27/05/2016 - v2.0.6 ### Friday, 27/05/2016 - v2.0.6
- Updated the issue template for (hopefully) better reporting - Updated the issue template for (hopefully) better reporting
- Added suggestion to use chrome while PDF printing - Added suggestion to use chrome while PDF printing
@@ -17,7 +24,7 @@
- Bumped up the allowed entity size for extra-large brew (Thanks for reporting it dickboner93) - Bumped up the allowed entity size for extra-large brew (Thanks for reporting it dickboner93)
- Added a little error box when a save fails with a custom link to reporting the issue on github. - Added a little error box when a save fails with a custom link to reporting the issue on github.
/page \page
### Saturday, 14/05/2016 - v2.0.0 (finally!) ### Saturday, 14/05/2016 - v2.0.0 (finally!)

View File

@@ -3,6 +3,19 @@ var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var Markdown = require('marked'); var Markdown = require('marked');
var renderer = new Markdown.Renderer();
//Processes the markdown within an HTML block if it's just a class-wrapper
renderer.html = function (html) {
if(_.startsWith(html, '<div class=') && _.endsWith(_.trim(html), '</div>')){
var openTag = html.substring(0, html.indexOf('>')+1);
html = html.substring(html.indexOf('>')+1);
html = html.substring(0, html.lastIndexOf('</div>'));
return `${openTag} ${Markdown(html)} </div>`;
}
return html;
}
var PAGE_HEIGHT = 1056 + 30; var PAGE_HEIGHT = 1056 + 30;
@@ -64,7 +77,7 @@ var BrewRenderer = React.createClass({
}, },
renderPage : function(pageText, index){ renderPage : function(pageText, index){
return <div className='phb' dangerouslySetInnerHTML={{__html:Markdown(pageText)}} key={index} /> return <div className='phb' dangerouslySetInnerHTML={{__html:Markdown(pageText, {renderer : renderer})}} key={index} />
}, },
renderPages : function(){ renderPages : function(){

View File

@@ -0,0 +1,91 @@
var _ = require('lodash');
var 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",
];
module.exports = {
spellList : function(){
var levels = ['Cantrips (0 Level)', '2nd Level', '3rd Level', '4th Level', '5th Level', '6th Level', '7th Level', '8th Level', '9th Level'];
var content = _.map(levels, (level)=>{
var spells = _.map(_.sampleSize(spellNames, _.random(5, 15)), (spell)=>{
return `- ${spell}`;
}).join('\n');
return `##### ${level} \n${spells} \n`;
}).join('\n');
return `<div class='spellList'>\n${content}\n</div>`;
},
spell : function(){
var level = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"];
var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"];
var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', ');
if(components.indexOf("M") !== -1){
components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
}
return [
"#### " + _.sample(spellNames),
"*" + _.sample(level) + "-level " + _.sample(spellSchools) + "*",
"___",
"- **Casting Time:** 1 action",
"- **Range:** " + _.sample(["Self", "Touch", "30 feet", "60 feet"]),
"- **Components:** " + components,
"- **Duration:** " + _.sample(["Until dispelled", "1 round", "Instantaneous", "Concentration, up to 10 minutes", "1 hour"]),
"",
"A flame, equivalent in brightness to a torch, springs from from an object that you touch. ",
"The effect look like a regular flame, but it creates no heat and doesn't use oxygen. ",
"A *continual flame* can be covered or hidden but not smothered or quenched.",
"\n\n\n"
].join('\n');
}
}

View File

@@ -1,11 +1,10 @@
var SpellGen = require('./spell.gen.js'); var MagicGen = require('./magic.gen.js');
var ClassTableGen = require('./classtable.gen.js'); var ClassTableGen = require('./classtable.gen.js');
var MonsterBlockGen = require('./monsterblock.gen.js'); var MonsterBlockGen = require('./monsterblock.gen.js');
var ClassFeatureGen = require('./classfeature.gen.js'); var ClassFeatureGen = require('./classfeature.gen.js');
var FullClassGen = require('./fullclass.gen.js'); var FullClassGen = require('./fullclass.gen.js');
module.exports = [ module.exports = [
{ {
@@ -67,7 +66,12 @@ module.exports = [
{ {
name : 'Spell', name : 'Spell',
icon : 'fa-magic', icon : 'fa-magic',
gen : SpellGen, gen : MagicGen.spell,
},
{
name : 'Spell List',
icon : 'fa-list',
gen : MagicGen.spellList,
}, },
{ {
name : 'Class Feature', name : 'Class Feature',
@@ -171,5 +175,3 @@ module.exports = [
}, },
] ]

View File

@@ -1,78 +0,0 @@
var _ = require('lodash');
module.exports = function(){
var 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",
];
var level = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"];
var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"];
var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', ');
if(components.indexOf("M") !== -1){
components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
}
return [
"#### " + _.sample(spellNames),
"*" + _.sample(level) + "-level " + _.sample(spellSchools) + "*",
"___",
"- **Casting Time:** 1 action",
"- **Range:** " + _.sample(["Self", "Touch", "30 feet", "60 feet"]),
"- **Components:** " + components,
"- **Duration:** " + _.sample(["Until dispelled", "1 round", "Instantaneous", "Concentration, up to 10 minutes", "1 hour"]),
"",
"A flame, equivalent in brightness to a torch, springs from from an object that you touch. ",
"The effect look like a regular flame, but it creates no heat and doesn't use oxygen. ",
"A *continual flame* can be covered or hidden but not smothered or quenched.",
"\n\n\n"
].join('\n');
}

View File

@@ -11,7 +11,7 @@ var Navbar = React.createClass({
<Nav.item href='/homebrew' className='homebrewLogo'> <Nav.item href='/homebrew' className='homebrewLogo'>
<div>The Homebrewery</div> <div>The Homebrewery</div>
</Nav.item> </Nav.item>
<Nav.item>v2.0.6</Nav.item> <Nav.item>v2.1.0</Nav.item>
</Nav.section> </Nav.section>
{this.props.children} {this.props.children}
</Nav.base> </Nav.base>

View File

@@ -16,9 +16,9 @@
.editTitle.navItem{ .editTitle.navItem{
padding : 2px 12px; padding : 2px 12px;
input{ input{
width : 250px;
margin : 0; margin : 0;
padding : 2px; padding : 2px;
width : 250px;
background-color : #444; background-color : #444;
font-family : 'Open Sans', sans-serif; font-family : 'Open Sans', sans-serif;
font-size : 12px; font-size : 12px;
@@ -32,8 +32,8 @@
display : inline-block; display : inline-block;
vertical-align : bottom; vertical-align : bottom;
margin-left : 8px; margin-left : 8px;
text-align : right;
color : #666; color : #666;
text-align : right;
&.max{ &.max{
color : @red; color : @red;
} }
@@ -54,5 +54,42 @@
} }
} }
} }
.recent.navItem{
position : relative;
.dropdown{
position : absolute;
top : 28px;
left : 0px;
z-index : 10000;
width : 100%;
.item{
.animate(background-color);
position : relative;
display : block;
box-sizing : border-box;;
padding : 13px 5px;
background-color : #333;
color : white;
text-decoration : none;
border-top : 1px solid #888;
&:hover{
background-color : @blue;
}
.title{
display : inline-block;
overflow : hidden;
width : 100%;
text-overflow : ellipsis;
white-space : nowrap;
}
.time{
position : absolute;
right : 2px;
bottom : 2px;
font-size : 0.7em;
color : #888;
}
}
}
}
} }

View File

@@ -0,0 +1,118 @@
var React = require('react');
var _ = require('lodash');
var cx = require('classnames');
var Moment = require('moment');
var Nav = require('naturalcrit/nav/nav.jsx');
var BaseItem = React.createClass({
getDefaultProps: function() {
return {
storageKey : '',
text : '',
currentBrew:{
title : '',
id : '',
url : ''
}
};
},
getInitialState: function() {
return {
showDropdown: false,
brews : []
};
},
componentDidMount: function() {
var brews = JSON.parse(localStorage.getItem(this.props.storageKey) || '[]');
brews = _.filter(brews, (brew)=>{
return brew.id !== this.props.currentBrew.id;
});
brews.unshift({
id : this.props.currentBrew.id,
url : this.props.currentBrew.url,
title : this.props.currentBrew.title,
ts : Date.now()
});
brews = _.slice(brews, 0, 8);
localStorage.setItem(this.props.storageKey, JSON.stringify(brews));
this.setState({
brews : brews
});
},
handleDropdown : function(show){
this.setState({
showDropdown : show
})
},
renderDropdown : function(){
if(!this.state.showDropdown) return null;
var items = _.map(this.state.brews, (brew)=>{
return <a href={brew.url} className='item' key={brew.id} target='_blank'>
<span className='title'>{brew.title}</span>
<span className='time'>{Moment(brew.ts).fromNow()}</span>
</a>
});
return <div className='dropdown'>{items}</div>
},
render : function(){
return <Nav.item icon='fa-clock-o' color='grey' className='recent'
onMouseEnter={this.handleDropdown.bind(null, true)}
onMouseLeave={this.handleDropdown.bind(null, false)}>
{this.props.text}
{this.renderDropdown()}
</Nav.item>
},
});
module.exports = {
viewed : React.createClass({
getDefaultProps: function() {
return {
brew : {
title : '',
shareId : ''
}
};
},
render : function(){
return <BaseItem text='recently viewed' storageKey='naturalCrit-homebrew-recently-viewed'
currentBrew={{
id : this.props.brew.shareId,
title : this.props.brew.title,
url : `/homebrew/share/${this.props.brew.shareId}`
}}
/>
},
}),
edited : React.createClass({
getDefaultProps: function() {
return {
brew : {
title : '',
editId : ''
}
};
},
render : function(){
return <BaseItem text='recently edited' storageKey='naturalCrit-homebrew-recently-edited'
currentBrew={{
id : this.props.brew.editId,
title : this.props.brew.title,
url : `/homebrew/edit/${this.props.brew.editId}`
}}
/>
},
}),
}

View File

@@ -9,12 +9,15 @@ var Navbar = require('../../navbar/navbar.jsx');
var EditTitle = require('../../navbar/editTitle.navitem.jsx'); var EditTitle = require('../../navbar/editTitle.navitem.jsx');
var ReportIssue = require('../../navbar/issue.navitem.jsx'); var ReportIssue = require('../../navbar/issue.navitem.jsx');
var PrintLink = require('../../navbar/print.navitem.jsx'); var PrintLink = require('../../navbar/print.navitem.jsx');
var RecentlyEdited = require('../../navbar/recent.navitem.jsx').edited;
var SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
var Editor = require('../../editor/editor.jsx'); var Editor = require('../../editor/editor.jsx');
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
var HijackPrint = require('../hijackPrint.js');
const SAVE_TIMEOUT = 3000; const SAVE_TIMEOUT = 3000;
@@ -54,10 +57,13 @@ var EditPage = React.createClass({
if(this.state.isSaving || this.state.isPending){ if(this.state.isSaving || this.state.isPending){
return 'You have unsaved changes!'; return 'You have unsaved changes!';
} }
} };
document.onkeydown = HijackPrint(this.props.brew.shareId);
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
window.onbeforeunload = function(){}; window.onbeforeunload = function(){};
document.onkeydown = function(){};
}, },
handleSplitMove : function(){ handleSplitMove : function(){
@@ -170,6 +176,7 @@ var EditPage = React.createClass({
</Nav.section> </Nav.section>
<Nav.section> <Nav.section>
{this.renderSaveButton()} {this.renderSaveButton()}
<RecentlyEdited brew={this.props.brew} />
<Nav.item newTab={true} href={'/homebrew/share/' + this.props.brew.shareId} color='teal' icon='fa-share-alt'> <Nav.item newTab={true} href={'/homebrew/share/' + this.props.brew.shareId} color='teal' icon='fa-share-alt'>
Share Share
</Nav.item> </Nav.item>

View File

@@ -0,0 +1,10 @@
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();
}
};
};

View File

@@ -1,6 +1,7 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var request = require("superagent");
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
var Navbar = require('../../navbar/navbar.jsx'); var Navbar = require('../../navbar/navbar.jsx');
@@ -24,6 +25,18 @@ var HomePage = React.createClass({
text: this.props.welcomeText text: this.props.welcomeText
}; };
}, },
handleSave : function(){
request.post('/homebrew/api')
.send({
title : 'Change This',
text : this.state.text
})
.end((err, res)=>{
if(err) return;
var brew = res.body;
window.location = '/homebrew/edit/' + brew.editId;
});
},
handleSplitMove : function(){ handleSplitMove : function(){
this.refs.editor.update(); this.refs.editor.update();
}, },
@@ -60,6 +73,10 @@ var HomePage = React.createClass({
</SplitPane> </SplitPane>
</div> </div>
<div className={cx('floatingSaveButton', {show : this.props.welcomeText != this.state.text})} onClick={this.handleSave}>
Save current <i className='fa fa-save' />
</div>
<a href='/homebrew/new' className='floatingNewButton'> <a href='/homebrew/new' className='floatingNewButton'>
Create your own <i className='fa fa-magic' /> Create your own <i className='fa fa-magic' />
</a> </a>

View File

@@ -1,4 +1,3 @@
.homePage{ .homePage{
position : relative; position : relative;
a.floatingNewButton{ a.floatingNewButton{
@@ -8,6 +7,7 @@
right : 70px; right : 70px;
bottom : 70px; bottom : 70px;
z-index : 100; z-index : 100;
z-index : 5001;
padding : 1em; padding : 1em;
background-color : @orange; background-color : @orange;
font-size : 1.5em; font-size : 1.5em;
@@ -18,4 +18,26 @@
background-color : darken(@orange, 20%); background-color : darken(@orange, 20%);
} }
} }
.floatingSaveButton{
.animateAll();
position : absolute;
display : block;
right : 200px;
bottom : 90px;
z-index : 100;
z-index : 5000;
padding : 0.8em;
cursor : pointer;
background-color : @blue;
font-size : 0.8em;
color : white;
text-decoration : none;
box-shadow : 3px 3px 15px black;
&:hover{
background-color : darken(@blue, 20%);
}
&.show{
right : 350px;
}
}
} }

View File

@@ -8,17 +8,6 @@ The Homebrewery makes the creation and sharing of authentic looking Fifth-Editio
#### Features
* Monster Stat Blocks
* Full class tables
* Notes and Tables
* Images
* Page numbering and footers
* Vertical spacing, column breaks, and multiple pages
### Editing and Sharing ### Editing and Sharing
When you create your own homebrew you will be given a *edit url* and a *share url*. Any changes you make will be automatically saved to the database within a few seconds. Anyone with the edit url will be able to make edits to your homebrew. So be careful about who you share it with. When you create your own homebrew you will be given a *edit url* and a *share url*. Any changes you make will be automatically saved to the database within a few seconds. Anyone with the edit url will be able to make edits to your homebrew. So be careful about who you share it with.
@@ -33,20 +22,9 @@ This tool will **always** be free, never have ads, and I will never offer any "p
Have an idea of how to make The Homebrewery better? Or did you find something that wasn't quite right? Head [here](https://github.com/stolksdorf/NaturalCrit/issues/new) and let me know!. Have an idea of how to make The Homebrewery better? Or did you find something that wasn't quite right? Head [here](https://github.com/stolksdorf/NaturalCrit/issues/new) and let me know!.
```
```
## New Things in v2.0.0!
What's new in the latest update? Check out the full changelog [here](/homebrew/changelog)
* **A whole new look** The site has been re-built from the ground up!
* **Better editor and Split Pane** Syntax highlighting will make writing your brews even easier, and now you can customize how large your editor is.
* **More reliable rendering** Lots of work has been put into making the rendering more reliable, not just for web, but also for PDFs
* **PDF Printing on Chrome** You don't need to use Chrome Canary anymore!
* ** Performance Improvements** The site should load faster, save faster, and render large brews *much* faster.
* **Patreon page** If you like this tool and want to show some thanks you can [head here](https://www.patreon.com/stolksdorf).
>##### PDF Exporting >##### 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. > 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 the **Destination** to "Save as PDF"
> * Set **Paper Size** to "Letter" > * Set **Paper Size** to "Letter"
@@ -54,11 +32,32 @@ What's new in the latest update? Check out the full changelog [here](/homebrew/c
> * In **Options** make sure "Background Images" is selected. > * In **Options** make sure "Background Images" is selected.
> * Hit print and enjoy! You're done! > * Hit print and enjoy! You're done!
> >
> PDF Printing works best in Chrome. If you are having quality/consistency issues, try using Chrome to print instead.
>
> If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print > If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print
```
```
## New Things in v2.1.0!
What's new in the latest update? Check out the full changelog [here](/homebrew/changelog)
* **Spell Lists** Tweaking the Markdown lexer and parser, I can now do nested Markdown within HTML blocks. Which means the available syntax I can use has vastly increased. Spell Lists are just the first of many new elements.
* **Recently Viewed/Edited** The Homebrewery now remembers which brews you've been editing and viewing. Check the navbar to quickly jump around to these.
* **Print Command Capturing** Pressing ctrl+p/cmd+p on any edit or share page will now jump you straight to the print page. Much more intutive.
## V2 Overhaul
A lot of <i class='fa fa-heart'></i> has been put into version 2 of The Homebrewery. Here are the highlights:
* **A whole new look** The site has been re-built from the ground up!
* **Better editor and split pane** Syntax highlighting will make writing your brews even easier, and now you can customize how large your editor is.
* **More reliable rendering** Lots of work has been put into making the rendering more reliable, not just for web, but also for PDFs
* **PDF Printing on Chrome** You don't need to use Chrome Canary anymore!
* ** Performance Improvements** The site should load faster, save faster, and render large brews *much* faster.
* **Patreon page** If you like this tool and want to show some thanks you can [head here](https://www.patreon.com/stolksdorf).

View File

@@ -4,11 +4,13 @@ var cx = require('classnames');
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
var Navbar = require('../../navbar/navbar.jsx'); var Navbar = require('../../navbar/navbar.jsx');
var PrintLink = require('../../navbar/print.navitem.jsx'); var PrintLink = require('../../navbar/print.navitem.jsx');
var RecentlyViewed = require('../../navbar/recent.navitem.jsx').viewed;
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
var HijackPrint = require('../hijackPrint.js');
var SharePage = React.createClass({ var SharePage = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
@@ -23,6 +25,13 @@ var SharePage = React.createClass({
}; };
}, },
componentDidMount: function() {
document.onkeydown = HijackPrint(this.props.brew.shareId);
},
componentWillUnmount: function() {
document.onkeydown = function(){};
},
render : function(){ render : function(){
return <div className='sharePage page'> return <div className='sharePage page'>
<Navbar> <Navbar>
@@ -31,6 +40,7 @@ var SharePage = React.createClass({
</Nav.section> </Nav.section>
<Nav.section> <Nav.section>
<RecentlyViewed brew={this.props.brew} />
<PrintLink shareId={this.props.brew.shareId} /> <PrintLink shareId={this.props.brew.shareId} />
<Nav.item href={'/homebrew/source/' + this.props.brew.shareId} color='teal' icon='fa-code'> <Nav.item href={'/homebrew/source/' + this.props.brew.shareId} color='teal' icon='fa-code'>
source source

View File

@@ -59,22 +59,25 @@
line-height : 1.3em; line-height : 1.3em;
&+p{ &+p{
margin-top : -0.8em; margin-top : -0.8em;
text-indent : 1em;
} }
} }
ul{ ul{
margin-bottom : 0.8em; margin-bottom : 0.8em;
padding-left : 1.4em;
line-height : 1.3em; line-height : 1.3em;
list-style-position : outside; list-style-position : outside;
list-style-type : disc; list-style-type : disc;
padding-left: 1.4em;
} }
ol{ ol{
margin-bottom : 0.8em; margin-bottom : 0.8em;
padding-left : 1.4em;
line-height : 1.3em; line-height : 1.3em;
list-style-position : outside; list-style-position : outside;
list-style-type : decimal; list-style-type : decimal;
padding-left: 1.4em; }
//Indents after p or lists
p+p, ul+p, ol+p{
text-indent : 1em;
} }
img{ img{
z-index : -1; z-index : -1;
@@ -222,8 +225,8 @@
margin : 0; margin : 0;
column-span : 1; column-span : 1;
background-color : transparent; background-color : transparent;
border-image : none;
border-style : none; border-style : none;
border-image : none;
-webkit-column-span : 1; -webkit-column-span : 1;
tbody{ tbody{
tr:nth-child(odd), tr:nth-child(even){ tr:nth-child(odd), tr:nth-child(even){
@@ -339,7 +342,7 @@
-moz-column-span : all; -moz-column-span : all;
} }
//Column Break //Column Break
pre{ pre, code{
visibility : hidden; visibility : hidden;
-webkit-column-break-after : always; -webkit-column-break-after : always;
break-after : always; break-after : always;
@@ -367,6 +370,31 @@
} }
} }
//***************************** //*****************************
// * SPELL LIST
// *****************************/
.phb .spellList{
.useSansSerif();
column-count : 4;
column-span : all;
-webkit-column-span : all;
-moz-column-span : all;
ul+h5{
margin-top : 15px;
}
p, ul{
font-size : 0.352cm;
line-height : 1.3em;
}
ul{
margin-bottom : 0.5em;
padding-left : 1em;
text-indent : -1em;
list-style-type : none;
-webkit-column-break-inside : auto;
column-break-inside : auto;
}
}
//*****************************
// * PRINT // * PRINT
// *****************************/ // *****************************/
.phb.print{ .phb.print{

View File

@@ -1,7 +1,7 @@
{ {
"name": "naturalcrit", "name": "naturalcrit",
"description": "D&D Tools for the discerning DM", "description": "D&D Tools for the discerning DM",
"version": "2.0.6", "version": "2.1.0",
"scripts": { "scripts": {
"postinstall": "gulp prod", "postinstall": "gulp prod",
"start": "node server.js" "start": "node server.js"

View File

@@ -208,21 +208,25 @@ table {
} }
.phb p + p { .phb p + p {
margin-top: -0.8em; margin-top: -0.8em;
text-indent: 1em;
} }
.phb ul { .phb ul {
margin-bottom: 0.8em; margin-bottom: 0.8em;
padding-left: 1.4em;
line-height: 1.3em; line-height: 1.3em;
list-style-position: outside; list-style-position: outside;
list-style-type: disc; list-style-type: disc;
padding-left: 1.4em;
} }
.phb ol { .phb ol {
margin-bottom: 0.8em; margin-bottom: 0.8em;
padding-left: 1.4em;
line-height: 1.3em; line-height: 1.3em;
list-style-position: outside; list-style-position: outside;
list-style-type: decimal; list-style-type: decimal;
padding-left: 1.4em; }
.phb p + p,
.phb ul + p,
.phb ol + p {
text-indent: 1em;
} }
.phb img { .phb img {
z-index: -1; z-index: -1;
@@ -384,8 +388,8 @@ table {
margin: 0; margin: 0;
column-span: 1; column-span: 1;
background-color: transparent; background-color: transparent;
border-image: none;
border-style: none; border-style: none;
border-image: none;
-webkit-column-span: 1; -webkit-column-span: 1;
} }
.phb hr + blockquote hr + table tbody tr:nth-child(odd), .phb hr + blockquote hr + table tbody tr:nth-child(odd),
@@ -492,7 +496,8 @@ table {
-webkit-column-span: all; -webkit-column-span: all;
-moz-column-span: all; -moz-column-span: all;
} }
.phb pre { .phb pre,
.phb code {
visibility: hidden; visibility: hidden;
-webkit-column-break-after: always; -webkit-column-break-after: always;
break-after: always; break-after: always;
@@ -521,6 +526,38 @@ table {
margin-bottom: 0px; margin-bottom: 0px;
margin-left: 1.5em; margin-left: 1.5em;
} }
.phb .spellList {
font-family: ScalySans;
column-count: 4;
column-span: all;
-webkit-column-span: all;
-moz-column-span: all;
}
.phb .spellList em {
font-family: ScalySans;
font-style: italic;
}
.phb .spellList strong {
font-family: ScalySans;
font-weight: 800;
letter-spacing: -0.02em;
}
.phb .spellList ul + h5 {
margin-top: 15px;
}
.phb .spellList p,
.phb .spellList ul {
font-size: 0.352cm;
line-height: 1.3em;
}
.phb .spellList ul {
margin-bottom: 0.5em;
padding-left: 1em;
text-indent: -1em;
list-style-type: none;
-webkit-column-break-inside: auto;
column-break-inside: auto;
}
.phb.print blockquote { .phb.print blockquote {
box-shadow: none; box-shadow: none;
} }

View File

@@ -1,85 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
var modes = ["clike", "css", "javascript"];
for (var i = 0; i < modes.length; ++i)
CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
function continueComment(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), mode, inserts = [];
for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head, token = cm.getTokenAt(pos);
if (token.type != "comment") return CodeMirror.Pass;
var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;
if (!mode) mode = modeHere;
else if (mode != modeHere) return CodeMirror.Pass;
var insert = null;
if (mode.blockCommentStart && mode.blockCommentContinue) {
var end = token.string.indexOf(mode.blockCommentEnd);
var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {
// Comment ended, don't continue it
} else if (token.string.indexOf(mode.blockCommentStart) == 0) {
insert = full.slice(0, token.start);
if (!/^\s*$/.test(insert)) {
insert = "";
for (var j = 0; j < token.start; ++j) insert += " ";
}
} else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
found + mode.blockCommentContinue.length > token.start &&
/^\s*$/.test(full.slice(0, found))) {
insert = full.slice(0, found);
}
if (insert != null) insert += mode.blockCommentContinue;
}
if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
if (found > -1) {
insert = line.slice(0, found);
if (/\S/.test(insert)) insert = null;
else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
}
}
if (insert == null) return CodeMirror.Pass;
inserts[i] = "\n" + insert;
}
cm.operation(function() {
for (var i = ranges.length - 1; i >= 0; i--)
cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
});
}
function continueLineCommentEnabled(cm) {
var opt = cm.getOption("continueComments");
if (opt && typeof opt == "object")
return opt.continueLineComment !== false;
return true;
}
CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
if (prev && prev != CodeMirror.Init)
cm.removeKeyMap("continueComment");
if (val) {
var key = "Enter";
if (typeof val == "string")
key = val;
else if (typeof val == "object" && val.key)
key = val.key;
var map = {name: "continueComment"};
map[key] = continueComment;
cm.addKeyMap(map);
}
});
});

View File

@@ -1,32 +0,0 @@
.CodeMirror-dialog {
position: absolute;
left: 0; right: 0;
background: inherit;
z-index: 15;
padding: .1em .8em;
overflow: hidden;
color: inherit;
}
.CodeMirror-dialog-top {
border-bottom: 1px solid #eee;
top: 0;
}
.CodeMirror-dialog-bottom {
border-top: 1px solid #eee;
bottom: 0;
}
.CodeMirror-dialog input {
border: none;
outline: none;
background: transparent;
width: 20em;
color: inherit;
font-family: monospace;
}
.CodeMirror-dialog button {
font-size: 70%;
}

View File

@@ -51,12 +51,12 @@ var Nav = {
if(this.props.icon) icon = <i className={'fa ' + this.props.icon} />; if(this.props.icon) icon = <i className={'fa ' + this.props.icon} />;
if(this.props.href){ if(this.props.href){
return <a href={this.props.href} className={classes} target={this.props.newTab ? '_blank' : '_self'}> return <a {...this.props} className={classes} target={this.props.newTab ? '_blank' : '_self'} >
{this.props.children} {this.props.children}
{icon} {icon}
</a> </a>
}else{ }else{
return <div className={classes} onClick={this.handleClick}> return <div {...this.props} className={classes} onClick={this.handleClick} >
{this.props.children} {this.props.children}
{icon} {icon}
</div> </div>