Merge branch 'borderShadows' into v3
@@ -2,7 +2,12 @@ var React = require('react');
|
|||||||
var Nav = require('naturalcrit/nav/nav.jsx');
|
var Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
|
||||||
module.exports = function(props){
|
module.exports = function(props){
|
||||||
return <Nav.item newTab={true} href='https://github.com/stolksdorf/homebrewery/issues' color='red' icon='fa-bug'>
|
return <Nav.item
|
||||||
|
{...props}
|
||||||
|
newTab={true}
|
||||||
|
href='https://github.com/stolksdorf/homebrewery/issues'
|
||||||
|
color='red'
|
||||||
|
icon='fa-bug'>
|
||||||
report issue
|
report issue
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
};
|
};
|
||||||
@@ -3,6 +3,7 @@ var Nav = require('naturalcrit/nav/nav.jsx');
|
|||||||
|
|
||||||
module.exports = function(props){
|
module.exports = function(props){
|
||||||
return <Nav.item
|
return <Nav.item
|
||||||
|
{...props}
|
||||||
className='patreon'
|
className='patreon'
|
||||||
newTab={true}
|
newTab={true}
|
||||||
href='https://www.patreon.com/stolksdorf'
|
href='https://www.patreon.com/stolksdorf'
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ var Nav = require('naturalcrit/nav/nav.jsx');
|
|||||||
const VIEW_KEY = 'homebrewery-recently-viewed';
|
const VIEW_KEY = 'homebrewery-recently-viewed';
|
||||||
const EDIT_KEY = 'homebrewery-recently-edited';
|
const EDIT_KEY = 'homebrewery-recently-edited';
|
||||||
|
|
||||||
|
//DEPRICATED
|
||||||
|
|
||||||
|
|
||||||
var BaseItem = React.createClass({
|
var BaseItem = React.createClass({
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
return {
|
return {
|
||||||
@@ -28,6 +31,8 @@ var BaseItem = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
|
console.log('Recent nav item is depricated');
|
||||||
|
|
||||||
var brews = JSON.parse(localStorage.getItem(this.props.storageKey) || '[]');
|
var brews = JSON.parse(localStorage.getItem(this.props.storageKey) || '[]');
|
||||||
|
|
||||||
brews = _.filter(brews, (brew)=>{
|
brews = _.filter(brews, (brew)=>{
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -24,10 +24,10 @@ const HomePage = React.createClass({
|
|||||||
renderNavbar : function(){
|
renderNavbar : function(){
|
||||||
return <Navbar>
|
return <Navbar>
|
||||||
<Nav.section>
|
<Nav.section>
|
||||||
<PatreonNavItem />
|
<PatreonNavItem collaspe={true} />
|
||||||
<IssueNavItem />
|
<IssueNavItem collaspe={true} />
|
||||||
<Nav.item newTab={true} href='/changelog' color='purple' icon='fa-file-text-o'>
|
<Nav.item newTab={true} href='/changelog' color='purple' icon='fa-star' collaspe={true}>
|
||||||
Changelog
|
What's new
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
<RecentNavItem.both />
|
<RecentNavItem.both />
|
||||||
<AccountNavItem />
|
<AccountNavItem />
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const NewPage = React.createClass({
|
|||||||
<Nav.item color='purple' icon='fa-file-pdf-o' onClick={Actions.localPrint}>
|
<Nav.item color='purple' icon='fa-file-pdf-o' onClick={Actions.localPrint}>
|
||||||
get PDF
|
get PDF
|
||||||
</Nav.item>
|
</Nav.item>
|
||||||
<Items.Issue />
|
<Items.Issue collaspe={true} />
|
||||||
<Items.Account />
|
<Items.Account />
|
||||||
</Nav.section>
|
</Nav.section>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
|
|||||||
@@ -3,38 +3,62 @@ const _ = require('lodash');
|
|||||||
const cx = require('classnames');
|
const cx = require('classnames');
|
||||||
const Markdown = require('homebrewery/markdown.js');
|
const Markdown = require('homebrewery/markdown.js');
|
||||||
|
|
||||||
|
const Headtags = require('vitreum/headtags');
|
||||||
|
|
||||||
const PrintPage = React.createClass({
|
const PrintPage = React.createClass({
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
return {
|
return {
|
||||||
query : {},
|
query : {},
|
||||||
brew : {
|
brew : {
|
||||||
text : '',
|
text : '',
|
||||||
|
style : ''
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
brewText: this.props.brew.text
|
brew: this.props.brew
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
if(this.props.query.local){
|
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();
|
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 <style>{this.state.brew.style.replace(/;/g, ' !important;')}</style>
|
||||||
|
},
|
||||||
renderPages : function(){
|
renderPages : function(){
|
||||||
return _.map(this.state.brewText.split('\\page'), (page, index) => {
|
return _.map(this.state.brew.text.split('\\page'), (page, index) => {
|
||||||
return <div
|
return <div
|
||||||
className='phb'
|
className='phb v2'
|
||||||
id={`p${index + 1}`}
|
id={`p${index + 1}`}
|
||||||
dangerouslySetInnerHTML={{__html:Markdown.render(page)}}
|
dangerouslySetInnerHTML={{__html:Markdown.render(page)}}
|
||||||
key={index} />;
|
key={index} />;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
renderPrintInstructions : function(){
|
||||||
|
return <div className='printInstructions'>
|
||||||
|
Hey, I'm really cool instructions!!!!!
|
||||||
|
|
||||||
|
</div>
|
||||||
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return <div>
|
return <div className='printPage'>
|
||||||
|
<Headtags.title>{this.state.brew.title}</Headtags.title>
|
||||||
|
{this.renderPrintInstructions()}
|
||||||
|
{this.renderStyle()}
|
||||||
{this.renderPages()}
|
{this.renderPages()}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,12 @@
|
|||||||
"dev": "node scripts/dev.js",
|
"dev": "node scripts/dev.js",
|
||||||
"quick": "node scripts/quick.js",
|
"quick": "node scripts/quick.js",
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js",
|
||||||
"phb": "node scripts/phb.js",
|
|
||||||
"populate": "node scripts/populate.js",
|
"populate": "node scripts/populate.js",
|
||||||
"prod": "set NODE_ENV=production&& npm run build",
|
"prod": "set NODE_ENV=production&& npm run build",
|
||||||
"postinstall": "npm run build",
|
"postinstall": "npm run build",
|
||||||
"start": "node server.js",
|
"start": "node server.js",
|
||||||
|
"snippet": "nodemon scripts/snippet.test.js",
|
||||||
|
"todo": "./node_modules/.bin/fixme -i node_modules/** -i build/**",
|
||||||
"test": "mocha tests",
|
"test": "mocha tests",
|
||||||
"test:dev": "nodemon -x mocha tests || exit 0",
|
"test:dev": "nodemon -x mocha tests || exit 0",
|
||||||
"test:markdown": "nodemon -x mocha tests/markdown.test.js || exit 0"
|
"test:markdown": "nodemon -x mocha tests/markdown.test.js || exit 0"
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"chai-as-promised": "^6.0.0",
|
"chai-as-promised": "^6.0.0",
|
||||||
"chai-subset": "^1.4.0",
|
"chai-subset": "^1.4.0",
|
||||||
|
"fixme": "^0.4.3",
|
||||||
"mocha": "^3.2.0",
|
"mocha": "^3.2.0",
|
||||||
"supertest": "^2.0.1",
|
"supertest": "^2.0.1",
|
||||||
"supertest-as-promised": "^4.0.2"
|
"supertest-as-promised": "^4.0.2"
|
||||||
|
|||||||
@@ -2,19 +2,20 @@ const label = 'build';
|
|||||||
console.time(label);
|
console.time(label);
|
||||||
|
|
||||||
const clean = require('vitreum/steps/clean.js');
|
const clean = require('vitreum/steps/clean.js');
|
||||||
const jsx = require('vitreum/steps/jsx.js').partial;
|
const jsx = require('vitreum/steps/jsx.js');
|
||||||
const lib = require('vitreum/steps/libs.js').partial;
|
const lib = require('vitreum/steps/libs.js');
|
||||||
const less = require('vitreum/steps/less.js').partial;
|
const less = require('vitreum/steps/less.js');
|
||||||
const asset = require('vitreum/steps/assets.js').partial;
|
const asset = require('vitreum/steps/assets.js');
|
||||||
|
|
||||||
const Proj = require('./project.json');
|
const Proj = require('./project.json');
|
||||||
|
|
||||||
clean()
|
Promise.resolve()
|
||||||
.then(lib(Proj.libs))
|
.then(()=>clean())
|
||||||
.then(jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, ['./shared']))
|
.then(()=>lib(Proj.libs))
|
||||||
.then(less('homebrew', ['./shared']))
|
.then(()=>jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, ['./shared']))
|
||||||
.then(jsx('admin', './client/admin/admin.jsx', Proj.libs, ['./shared']))
|
.then((deps)=>less('homebrew', ['./shared'], deps))
|
||||||
.then(less('admin', ['./shared']))
|
.then(()=>jsx('admin', './client/admin/admin.jsx', Proj.libs, ['./shared']))
|
||||||
.then(asset(Proj.assets, ['./shared', './client']))
|
.then((deps)=>less('admin', ['./shared'], deps))
|
||||||
.then(console.timeEnd.bind(console, label))
|
.then(()=>asset(Proj.assets, ['./shared', './client']))
|
||||||
|
.then(()=>console.timeEnd.bind(console, label))
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
const label = 'dev';
|
const label = 'dev';
|
||||||
console.time(label);
|
console.time(label);
|
||||||
|
|
||||||
const jsx = require('vitreum/steps/jsx.watch.js').partial;
|
const jsx = require('vitreum/steps/jsx.watch.js');
|
||||||
const less = require('vitreum/steps/less.watch.js').partial;
|
const less = require('vitreum/steps/less.watch.js');
|
||||||
const assets = require('vitreum/steps/assets.watch.js').partial;
|
const assets = require('vitreum/steps/assets.watch.js');
|
||||||
const server = require('vitreum/steps/server.watch.js').partial;
|
const server = require('vitreum/steps/server.watch.js');
|
||||||
const livereload = require('vitreum/steps/livereload.js').partial;
|
const livereload = require('vitreum/steps/livereload.js');
|
||||||
|
|
||||||
const Proj = require('./project.json');
|
const Proj = require('./project.json');
|
||||||
|
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, './shared'))
|
.then(()=>jsx('homebrew', './client/homebrew/homebrew.jsx', Proj.libs, './shared'))
|
||||||
.then(less('homebrew', './shared'))
|
.then((deps)=>less('homebrew', './shared', deps))
|
||||||
.then(jsx('admin', './client/admin/admin.jsx', Proj.libs, './shared'))
|
.then(()=>jsx('admin', './client/admin/admin.jsx', Proj.libs, './shared'))
|
||||||
.then(less('admin', './shared'))
|
.then((deps)=>less('admin', './shared', deps))
|
||||||
.then(assets(Proj.assets, ['./shared', './client']))
|
.then(()=>assets(Proj.assets, ['./shared', './client']))
|
||||||
.then(livereload())
|
.then(()=>livereload())
|
||||||
.then(server('./server.js', ['server']))
|
.then(()=>server('./server.js', ['server']))
|
||||||
.then(console.timeEnd.bind(console, label))
|
.then(()=>console.timeEnd.bind(console, label))
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
8
scripts/notes.js
Normal file
@@ -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
|
||||||
|
});
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
8
scripts/snippet.test.js
Normal file
@@ -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());
|
||||||
@@ -8,10 +8,11 @@ const mw = require('./middleware.js');
|
|||||||
|
|
||||||
|
|
||||||
const statics = {
|
const statics = {
|
||||||
welcomeBrew : fs.readFileSync('./welcome.brew.md', 'utf8'),
|
welcomeBrew : fs.readFileSync('./statics/welcome.brew.md', 'utf8'),
|
||||||
changelog : fs.readFileSync('./changelog.md', 'utf8'),
|
changelog : fs.readFileSync('./statics/changelog.md', 'utf8'),
|
||||||
testBrew : fs.readFileSync('./statics/test.brew.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'),
|
oldTest : fs.readFileSync('./statics/oldTest.brew.md', 'utf8'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ router.get('/edit/:editId', mw.loadBrew, renderPage);
|
|||||||
|
|
||||||
//Print Page
|
//Print Page
|
||||||
router.get('/print/:shareId', mw.viewBrew, renderPage);
|
router.get('/print/:shareId', mw.viewBrew, renderPage);
|
||||||
|
router.get('/print', renderPage);
|
||||||
|
|
||||||
//Source page
|
//Source page
|
||||||
router.get('/source/:sharedId', mw.viewBrew, (req, res, next)=>{
|
router.get('/source/:sharedId', mw.viewBrew, (req, res, next)=>{
|
||||||
@@ -81,6 +83,17 @@ router.get('/changelog', (req, res, next) => {
|
|||||||
return next();
|
return next();
|
||||||
}, renderPage);
|
}, renderPage);
|
||||||
|
|
||||||
|
//faq Page
|
||||||
|
router.get('/faq', (req, res, next) => {
|
||||||
|
req.brew = {
|
||||||
|
text : statics.faq,
|
||||||
|
title : 'FAQ',
|
||||||
|
|
||||||
|
editId : true
|
||||||
|
};
|
||||||
|
return next();
|
||||||
|
}, renderPage);
|
||||||
|
|
||||||
//New Page
|
//New Page
|
||||||
router.get('/new', renderPage);
|
router.get('/new', renderPage);
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const getTOC = (pages) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(brew){
|
module.exports = function(brew){
|
||||||
const pages = brew.split('\\page');
|
|
||||||
const TOC = getTOC(pages);
|
const TOC = getTOC(pages);
|
||||||
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
|
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
|
||||||
r.push(`- **[${idx1 + 1} ${g1.title}](#p${g1.page})**`)
|
r.push(`- **[${idx1 + 1} ${g1.title}](#p${g1.page})**`)
|
||||||
@@ -70,8 +70,9 @@ const Actions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
localPrint : ()=>{
|
localPrint : ()=>{
|
||||||
localStorage.setItem('print', Store.getBrewText());
|
const key = 'print';
|
||||||
window.open('/print?dialog=true&local=print','_blank');
|
localStorage.setItem(key, JSON.stringify(Store.getBrew()));
|
||||||
|
window.open(`/print?dialog=true&local=${key}`,'_blank');
|
||||||
},
|
},
|
||||||
print : ()=>{
|
print : ()=>{
|
||||||
window.open(`/print/${Store.getBrew().shareId}?dialog=true`, '_blank').focus();
|
window.open(`/print/${Store.getBrew().shareId}?dialog=true`, '_blank').focus();
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ const _ = require('lodash');
|
|||||||
const cx = require('classnames');
|
const cx = require('classnames');
|
||||||
|
|
||||||
const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
||||||
const SnippetBar = require('./snippetbar/snippetbar.jsx');
|
|
||||||
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
|
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
|
||||||
|
|
||||||
const Menubar = require('./menubar/menubar.jsx');
|
const Menubar = require('./menubar/menubar.jsx');
|
||||||
|
|
||||||
const splice = function(str, index, inject){
|
const splice = function(str, index, inject){
|
||||||
@@ -32,6 +30,10 @@ const BrewEditor = React.createClass({
|
|||||||
view : 'code', //'code', 'style', 'meta'
|
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() {
|
componentDidMount: function() {
|
||||||
this.updateEditorSize();
|
this.updateEditorSize();
|
||||||
@@ -53,11 +55,16 @@ const BrewEditor = React.createClass({
|
|||||||
|
|
||||||
|
|
||||||
handleInject : function(injectText){
|
handleInject : function(injectText){
|
||||||
const lines = this.props.value.split('\n');
|
const text = (this.isCode() ? this.props.brew.text : this.props.brew.style);
|
||||||
lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText);
|
|
||||||
|
|
||||||
this.handleTextChange(lines.join('\n'));
|
const lines = text.split('\n');
|
||||||
this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length);
|
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
|
//MOve this to a util.sj file
|
||||||
highlightPageLines : function(){
|
highlightPageLines : function(){
|
||||||
if(!this.refs.codeEditor) return;
|
if(!this.refs.codeEditor) return;
|
||||||
|
if(!this.isCode()) return;
|
||||||
|
|
||||||
|
|
||||||
const codeMirror = this.refs.codeEditor.codeMirror;
|
const codeMirror = this.refs.codeEditor.codeMirror;
|
||||||
|
|
||||||
const lineNumbers = _.reduce(this.props.brew.text.split('\n'), (r, line, lineNumber)=>{
|
const lineNumbers = _.reduce(this.props.brew.text.split('\n'), (r, line, lineNumber)=>{
|
||||||
@@ -95,6 +105,11 @@ const BrewEditor = React.createClass({
|
|||||||
r.push(lineNumber);
|
r.push(lineNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(line.indexOf('\\column') === 0){
|
||||||
|
codeMirror.addLineClass(lineNumber, 'text', 'columnSplit');
|
||||||
|
r.push(lineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
if(_.startsWith(line, '{{') || _.startsWith(line, '}}')){
|
if(_.startsWith(line, '{{') || _.startsWith(line, '}}')){
|
||||||
codeMirror.addLineClass(lineNumber, 'text', 'block');
|
codeMirror.addLineClass(lineNumber, 'text', 'block');
|
||||||
}
|
}
|
||||||
@@ -116,19 +131,19 @@ const BrewEditor = React.createClass({
|
|||||||
|
|
||||||
|
|
||||||
renderEditor : function(){
|
renderEditor : function(){
|
||||||
if(this.state.view == 'meta'){
|
if(this.isMeta()){
|
||||||
return <MetadataEditor
|
return <MetadataEditor
|
||||||
metadata={this.props.brew}
|
metadata={this.props.brew}
|
||||||
onChange={this.props.onMetaChange} />
|
onChange={this.props.onMetaChange} />
|
||||||
}
|
}
|
||||||
if(this.state.view == 'style'){
|
if(this.isStyle()){
|
||||||
return <CodeEditor key='style'
|
return <CodeEditor key='style'
|
||||||
ref='codeEditor'
|
ref='codeEditor'
|
||||||
language='css'
|
language='css'
|
||||||
value={this.props.brew.style}
|
value={this.props.brew.style}
|
||||||
onChange={this.props.onStyleChange} />
|
onChange={this.props.onStyleChange} />
|
||||||
}
|
}
|
||||||
if(this.state.view == 'code'){
|
if(this.isCode()){
|
||||||
return <CodeEditor key='code'
|
return <CodeEditor key='code'
|
||||||
ref='codeEditor'
|
ref='codeEditor'
|
||||||
language='gfm'
|
language='gfm'
|
||||||
@@ -140,16 +155,10 @@ const BrewEditor = React.createClass({
|
|||||||
render : function(){
|
render : function(){
|
||||||
this.highlightPageLines();
|
this.highlightPageLines();
|
||||||
return <div className='brewEditor' ref='main'>
|
return <div className='brewEditor' ref='main'>
|
||||||
{/*
|
|
||||||
<SnippetBar
|
|
||||||
brew={this.props.value}
|
|
||||||
onInject={this.handleInject}
|
|
||||||
onToggle={this.handgleToggle}
|
|
||||||
showmeta={this.state.showMetadataEditor} />
|
|
||||||
*/}
|
|
||||||
<Menubar
|
<Menubar
|
||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
onViewChange={this.handleViewChange}
|
onViewChange={this.handleViewChange}
|
||||||
|
onSnippetInject={this.handleInject}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,13 @@
|
|||||||
border-bottom : #333 solid 1px;
|
border-bottom : #333 solid 1px;
|
||||||
}
|
}
|
||||||
.block{
|
.block{
|
||||||
color : blue;
|
color : purple;
|
||||||
//font-style: italic;
|
//font-style: italic;
|
||||||
}
|
}
|
||||||
|
.columnSplit{
|
||||||
|
font-style : italic;
|
||||||
|
color : grey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.brewJump{
|
.brewJump{
|
||||||
|
|||||||
@@ -1,19 +1,60 @@
|
|||||||
|
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const cx = require('classnames');
|
const cx = require('classnames');
|
||||||
|
|
||||||
|
const SnippetMap = require('./snippet.map.js');
|
||||||
|
const SnippetGroup = require('./snippetGroup/snippetGroup.jsx');
|
||||||
|
|
||||||
const Menubar = React.createClass({
|
const Menubar = React.createClass({
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
return {
|
return {
|
||||||
view : '',
|
view : 'code',
|
||||||
onViewChange : ()=>{},
|
onViewChange : ()=>{},
|
||||||
onSnippetInject : ()=>{},
|
onSnippetInject : ()=>{},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//TODO: remove
|
||||||
|
renderDevGroup : function(){
|
||||||
|
const Snippets = require('homebrewery/snippets/brew');
|
||||||
|
|
||||||
|
const snippets = _.map(Snippets, (gen, name)=>{
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
gen,
|
||||||
|
icon : 'fa-question'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return <SnippetGroup
|
||||||
|
name='All'
|
||||||
|
icon='fa-rocket'
|
||||||
|
snippets={snippets}
|
||||||
|
onClick={this.props.onSnippetInject}
|
||||||
|
key='dev'
|
||||||
|
/>
|
||||||
|
},
|
||||||
|
|
||||||
|
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 <SnippetGroup {...group} onClick={this.props.onSnippetInject} key={group.name} />
|
||||||
|
});
|
||||||
|
|
||||||
|
groups = groups.concat(this.renderDevGroup());
|
||||||
|
|
||||||
|
return <div className='snippets'>{groups} </div>
|
||||||
|
},
|
||||||
render: function(){
|
render: function(){
|
||||||
return <div className='menubar'>
|
return <div className='menubar'>
|
||||||
|
|
||||||
|
{this.renderSnippets()}
|
||||||
|
|
||||||
<div className='editors'>
|
<div className='editors'>
|
||||||
<div className={cx('code', {selected : this.props.view == 'code'})}
|
<div className={cx('code', {selected : this.props.view == 'code'})}
|
||||||
onClick={this.props.onViewChange.bind(null, 'code')}>
|
onClick={this.props.onViewChange.bind(null, 'code')}>
|
||||||
|
|||||||
@@ -32,4 +32,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.snippets{
|
||||||
|
display : flex;
|
||||||
|
height : 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
48
shared/homebrewery/brewEditor/menubar/snippet.map.js
Normal file
@@ -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
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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 <div className='snippet' key={snippet.name} onClick={this.handleSnippetClick.bind(this, snippet)}>
|
||||||
|
<i className={'fa fa-fw ' + snippet.icon} />
|
||||||
|
{snippet.name}
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function(){
|
||||||
|
return <div className='snippetGroup'>
|
||||||
|
<div className='text'>
|
||||||
|
<i className={'fa fa-fw ' + this.props.icon} />
|
||||||
|
<span className='groupName'>{this.props.name}</span>
|
||||||
|
</div>
|
||||||
|
<div className='dropdown'>
|
||||||
|
{this.renderSnippets()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = SnippetGroup;
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 <SnippetGroup
|
|
||||||
brew={this.props.brew}
|
|
||||||
groupName={snippetGroup.groupName}
|
|
||||||
icon={snippetGroup.icon}
|
|
||||||
snippets={snippetGroup.snippets}
|
|
||||||
key={snippetGroup.groupName}
|
|
||||||
onSnippetClick={this.handleSnippetClick}
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
render : function(){
|
|
||||||
return <div className='snippetBar'>
|
|
||||||
{this.renderSnippetGroups()}
|
|
||||||
<div className={cx('toggleMeta', {selected: this.props.showmeta})}
|
|
||||||
onClick={this.props.onToggle}>
|
|
||||||
<i className='fa fa-bars' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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 <div className='snippet' key={snippet.name} onClick={this.handleSnippetClick.bind(this, snippet)}>
|
|
||||||
<i className={'fa fa-fw ' + snippet.icon} />
|
|
||||||
{snippet.name}
|
|
||||||
</div>
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
render : function(){
|
|
||||||
return <div className='snippetGroup'>
|
|
||||||
<div className='text'>
|
|
||||||
<i className={'fa fa-fw ' + this.props.icon} />
|
|
||||||
<span className='groupName'>{this.props.groupName}</span>
|
|
||||||
</div>
|
|
||||||
<div className='dropdown'>
|
|
||||||
{this.renderSnippets()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,9 +7,9 @@ const BrewRenderer = require('../brewRenderer/brewRenderer.smart.jsx');
|
|||||||
|
|
||||||
|
|
||||||
const BrewInterface = React.createClass({
|
const BrewInterface = React.createClass({
|
||||||
|
|
||||||
handleSplitMove : function(){
|
handleSplitMove : function(){
|
||||||
console.log('split move!');
|
const BrewEditor = this.refs.editor.refs.wrappedComponent;
|
||||||
|
BrewEditor.updateEditorSize();
|
||||||
},
|
},
|
||||||
render: function(){
|
render: function(){
|
||||||
return <SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
|
return <SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
|
||||||
|
|||||||
@@ -133,6 +133,11 @@ const BrewRenderer = React.createClass({
|
|||||||
return this.lastRender;
|
return this.lastRender;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//TODO: This is pretty bad
|
||||||
|
renderStyle : function(){
|
||||||
|
return <style>{this.props.brew.style.replace(/;/g, ' !important;')}</style>
|
||||||
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
if(this.props.brew.version == 1) return <OldBrewRenderer value={this.props.brew.text} />;
|
if(this.props.brew.version == 1) return <OldBrewRenderer value={this.props.brew.text} />;
|
||||||
|
|
||||||
@@ -146,7 +151,7 @@ const BrewRenderer = React.createClass({
|
|||||||
<RenderWarnings />
|
<RenderWarnings />
|
||||||
|
|
||||||
|
|
||||||
<style>{this.props.brew.style}</style>
|
{this.renderStyle()}
|
||||||
|
|
||||||
<div className='pages' ref='pages'>
|
<div className='pages' ref='pages'>
|
||||||
{this.renderPages()}
|
{this.renderPages()}
|
||||||
|
|||||||
@@ -26,11 +26,18 @@ renderer.paragraph = function(text){
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderer.image = function(href, title, text){
|
||||||
|
return `<img src="${href}" class="${text.split(',').join(' ')}"></img>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
marked : Markdown,
|
marked : Markdown,
|
||||||
render : (rawBrewText)=>{
|
render : (rawBrewText)=>{
|
||||||
blockCount = 0;
|
blockCount = 0;
|
||||||
|
|
||||||
|
rawBrewText = rawBrewText.replace(/\\column/g, '{{columnSplit }}')
|
||||||
|
|
||||||
let html = Markdown(rawBrewText, {renderer : renderer, sanitize: true});
|
let html = Markdown(rawBrewText, {renderer : renderer, sanitize: true});
|
||||||
//Close all hanging block tags
|
//Close all hanging block tags
|
||||||
html += _.times(blockCount, ()=>{return '</div>'}).join('\n');
|
html += _.times(blockCount, ()=>{return '</div>'}).join('\n');
|
||||||
|
|||||||
BIN
shared/homebrewery/phb_style/img/footer_flip.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
shared/homebrewery/phb_style/img/monster_bg.jpg
Normal file
|
After Width: | Height: | Size: 339 KiB |
|
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 327 B |
BIN
shared/homebrewery/phb_style/img/note_border - Copy.png
Normal file
|
After Width: | Height: | Size: 530 B |
BIN
shared/homebrewery/phb_style/img/note_border.pdn
Normal file
BIN
shared/homebrewery/phb_style/img/note_border_shadow.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
shared/homebrewery/phb_style/img/shadow_border.pdn
Normal file
BIN
shared/homebrewery/phb_style/img/shadow_border.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
211
shared/homebrewery/phb_style/phb.blocks.less
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
@monsterStatBackground : #FDF1DC;
|
@monsterStatBackground : #FDF1DC;
|
||||||
|
|
||||||
|
|
||||||
@teal : blue;
|
|
||||||
|
|
||||||
|
|
||||||
.colorElements(@color){
|
.colorElements(@color){
|
||||||
table tbody{
|
table tbody{
|
||||||
@@ -17,8 +15,24 @@
|
|||||||
background-color : @color;
|
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
|
//TODO make a color mixin generator
|
||||||
.teal{ .colorElements(@teal); }
|
.teal{ .colorElements(@teal); }
|
||||||
|
.blue{ .colorElements(@blue); }
|
||||||
|
.green{ .colorElements(@green); }
|
||||||
|
.yellow{ .colorElements(@yellow); }
|
||||||
|
.gold{ .colorElements(@gold); }
|
||||||
|
.red{ .colorElements(@red); }
|
||||||
|
|||||||
172
shared/homebrewery/phb_style/phb.elements.less
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,18 +53,3 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
@footerImg : url('/assets/homebrewery/phb_style/img/footer.png');
|
@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');
|
@dividerImg : url('/assets/homebrewery/phb_style/img/divider.png');
|
||||||
|
|
||||||
@frameBorder : url('/assets/homebrewery/phb_style/img/frame_border.png');
|
@frameBorder : url('/assets/homebrewery/phb_style/img/frame_border.png');
|
||||||
@monsterBorder : url('/assets/homebrewery/phb_style/img/monster_border.png');
|
@monsterBorder : url('/assets/homebrewery/phb_style/img/monster_border.png');
|
||||||
@noteBorder : url('/assets/homebrewery/phb_style/img/note_border.png');
|
@noteBorder : url('/assets/homebrewery/phb_style/img/note_border.png');
|
||||||
@descriptiveBorder : url('/assets/homebrewery/phb_style/img/desc_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');
|
@phbBG : url('/assets/homebrewery/phb_style/img/phb_bg.jpg');
|
||||||
@darkBG : url('/assets/homebrewery/phb_style/img/phb_dark_bg.jpg');
|
@darkBG : url('/assets/homebrewery/phb_style/img/phb_dark_bg.jpg');
|
||||||
@dmgBG : url('/assets/homebrewery/phb_style/img/dmg_bg.jpg');
|
@dmgBG : url('/assets/homebrewery/phb_style/img/dmg_bg.jpg');
|
||||||
|
@monsterBG : url('/assets/homebrewery/phb_style/img/monster_bg.jpg');
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
|
||||||
|
//TODO: Remove this
|
||||||
|
/*
|
||||||
@media print {
|
@media print {
|
||||||
.phb.v2{
|
.phb.v2{
|
||||||
.descriptive, blockquote{
|
.descriptive, blockquote{
|
||||||
@@ -5,34 +8,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
.phb.v2{
|
.phb.v2{
|
||||||
|
@import './phb.mixins.less';
|
||||||
@import './phb.fonts.less';
|
@import './phb.fonts.less';
|
||||||
@import './phb.colors.less';
|
@import './phb.colors.less';
|
||||||
@import './phb.img.less';
|
@import './phb.img.less';
|
||||||
|
@import './phb.blocks.less';
|
||||||
|
@import './phb.elements.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();
|
|
||||||
counter-increment : phb-page-numbers;
|
counter-increment : phb-page-numbers;
|
||||||
position : relative;
|
position : relative;
|
||||||
z-index : 15;
|
z-index : 15;
|
||||||
@@ -42,6 +27,10 @@
|
|||||||
width : 215.9mm;
|
width : 215.9mm;
|
||||||
padding : 1.0cm 1.7cm;
|
padding : 1.0cm 1.7cm;
|
||||||
padding-bottom : 1.5cm;
|
padding-bottom : 1.5cm;
|
||||||
|
column-count : 2;
|
||||||
|
column-fill : auto;
|
||||||
|
column-gap : 1cm;
|
||||||
|
column-width : 8cm;
|
||||||
background-color : @background;
|
background-color : @background;
|
||||||
background-image : @phbBG;
|
background-image : @phbBG;
|
||||||
font-family : BookInsanity;
|
font-family : BookInsanity;
|
||||||
@@ -49,150 +38,64 @@
|
|||||||
text-rendering : optimizeLegibility;
|
text-rendering : optimizeLegibility;
|
||||||
page-break-before : always;
|
page-break-before : always;
|
||||||
page-break-after : 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
|
// * 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
|
//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 {
|
//pre+blockquote, h2+blockquote, h3+blockquote, h4+blockquote, h5+blockquote {
|
||||||
margin-top : 13px;
|
// margin-top : 13px;
|
||||||
}
|
//}
|
||||||
//*****************************
|
//*****************************
|
||||||
// * MONSTER STAT BLOCK
|
// * MONSTER STAT BLOCK
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
/*
|
||||||
hr+blockquote{
|
hr+blockquote{
|
||||||
position : relative;
|
position : relative;
|
||||||
padding-top : 15px;
|
padding-top : 15px;
|
||||||
@@ -252,107 +155,46 @@
|
|||||||
border : none;
|
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
|
// * EXTRAS
|
||||||
// *****************************/
|
// *****************************/
|
||||||
hr{
|
|
||||||
visibility : hidden;
|
|
||||||
margin : 0px;
|
|
||||||
}
|
|
||||||
//Modified unorder list, used in spells
|
//Modified unorder list, used in spells
|
||||||
hr+ul{
|
// hr+ul{
|
||||||
margin-bottom : 0.5em;
|
// margin-bottom : 0.5em;
|
||||||
padding-left : 1em;
|
// padding-left : 1em;
|
||||||
text-indent : -1em;
|
// text-indent : -1em;
|
||||||
list-style-type : none;
|
// list-style-type : none;
|
||||||
}
|
// }
|
||||||
//Column Break
|
//Column Break
|
||||||
|
/*
|
||||||
pre, code{
|
pre, code{
|
||||||
visibility : hidden;
|
visibility : hidden;
|
||||||
-webkit-column-break-after : always;
|
-webkit-column-break-after : always;
|
||||||
break-after : always;
|
break-after : always;
|
||||||
-moz-column-break-after : always;
|
-moz-column-break-after : always;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
//Avoid breaking up
|
//Avoid breaking up
|
||||||
|
/*
|
||||||
p,blockquote,table{
|
p,blockquote,table{
|
||||||
z-index : 15;
|
z-index : 15;
|
||||||
-webkit-column-break-inside : avoid;
|
-webkit-column-break-inside : avoid;
|
||||||
column-break-inside : avoid;
|
column-break-inside : avoid;
|
||||||
overflow: hidden; /* Firefox fix */
|
overflow: hidden; /* Firefox fix */
|
||||||
}
|
|
||||||
//Better spacing for spell blocks
|
//Better spacing for spell blocks
|
||||||
h4+p+hr+ul{
|
// h4+p+hr+ul{
|
||||||
margin-top : -0.5em
|
// margin-top : -0.5em
|
||||||
}
|
// }
|
||||||
//Text indent right after table
|
// //Text indent right after table
|
||||||
table+p{
|
// table+p{
|
||||||
text-indent : 1em;
|
// text-indent : 1em;
|
||||||
}
|
// }
|
||||||
// Nested lists
|
// 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
|
// * SPELL LIST
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
/*
|
||||||
.spellList{
|
.spellList{
|
||||||
.useSansSerif();
|
.useSansSerif();
|
||||||
column-count : 4;
|
column-count : 4;
|
||||||
@@ -378,42 +220,43 @@
|
|||||||
//*****************************
|
//*****************************
|
||||||
// * PRINT
|
// * PRINT
|
||||||
// *****************************/
|
// *****************************/
|
||||||
&.print{
|
// &.print{
|
||||||
blockquote{
|
// blockquote{
|
||||||
box-shadow : none;
|
// box-shadow : none;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
//*****************************
|
//*****************************
|
||||||
// * WIDE
|
// * WIDE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
/*
|
||||||
.wide{
|
.wide{
|
||||||
column-span : all;
|
column-span : all;
|
||||||
-webkit-column-span : all;
|
-webkit-column-span : all;
|
||||||
-moz-column-span : all;
|
-moz-column-span : all;
|
||||||
}
|
}*/
|
||||||
//*****************************
|
//*****************************
|
||||||
// * CLASS TABLE
|
// * CLASS TABLE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
.classTable{
|
// .classTable{
|
||||||
margin-top : 25px;
|
// margin-top : 25px;
|
||||||
margin-bottom : 40px;
|
// margin-bottom : 40px;
|
||||||
border-collapse : separate;
|
// border-collapse : separate;
|
||||||
background-color : white;
|
// background-color : white;
|
||||||
border : initial;
|
// border : initial;
|
||||||
border-style : solid;
|
// border-style : solid;
|
||||||
border-image-outset : 25px 17px;
|
// border-image-outset : 25px 17px;
|
||||||
border-image-repeat : round;
|
// border-image-repeat : round;
|
||||||
border-image-slice : 150 200 150 200;
|
// border-image-slice : 150 200 150 200;
|
||||||
border-image-source : @frameBorder;
|
// border-image-source : @frameBorder;
|
||||||
border-image-width : 47px;
|
// border-image-width : 47px;
|
||||||
h5{
|
// h5{
|
||||||
margin-bottom : 10px;
|
// margin-bottom : 10px;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
//*****************************
|
//*****************************
|
||||||
// * CLASS TABLE
|
// * CLASS TABLE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
/*
|
||||||
.descriptive{
|
.descriptive{
|
||||||
display : block-inline;
|
display : block-inline;
|
||||||
margin-bottom : 1em;
|
margin-bottom : 1em;
|
||||||
@@ -445,61 +288,36 @@
|
|||||||
pre+.descriptive{
|
pre+.descriptive{
|
||||||
margin-top : 8px;
|
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
|
// * Old Stuff
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
// //Double hr for full width elements
|
||||||
//Double hr for full width elements
|
// hr+hr+blockquote{
|
||||||
hr+hr+blockquote{
|
// column-span : all;
|
||||||
column-span : all;
|
// -webkit-column-span : all;
|
||||||
-webkit-column-span : all;
|
// -moz-column-span : all;
|
||||||
-moz-column-span : all;
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
//*****************************
|
//*****************************
|
||||||
// * CLASS TABLE
|
// * CLASS TABLE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
hr+table{
|
// hr+table{
|
||||||
margin-top : -5px;
|
// margin-top : -5px;
|
||||||
margin-bottom : 50px;
|
// margin-bottom : 50px;
|
||||||
padding-top : 10px;
|
// padding-top : 10px;
|
||||||
border-collapse : separate;
|
// border-collapse : separate;
|
||||||
background-color : white;
|
// background-color : white;
|
||||||
border : initial;
|
// border : initial;
|
||||||
border-style : solid;
|
// border-style : solid;
|
||||||
border-image-outset : 37px 17px;
|
// border-image-outset : 37px 17px;
|
||||||
border-image-repeat : round;
|
// border-image-repeat : round;
|
||||||
border-image-slice : 150 200 150 200;
|
// border-image-slice : 150 200 150 200;
|
||||||
border-image-source : @frameBorder;
|
// border-image-source : @frameBorder;
|
||||||
border-image-width : 47px;
|
// border-image-width : 47px;
|
||||||
}
|
// }
|
||||||
h5+hr+table{
|
// h5+hr+table{
|
||||||
column-span : all;
|
// column-span : all;
|
||||||
-webkit-column-span : all;
|
// -webkit-column-span : all;
|
||||||
-moz-column-span : all;
|
// -moz-column-span : all;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
48
shared/homebrewery/phb_style/phb.mixins.less
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
82
shared/homebrewery/snippets/brew/class.snippet.js
Normal file
@@ -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}
|
||||||
|
}}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
19
shared/homebrewery/snippets/brew/index.js
Normal file
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
);
|
||||||
74
shared/homebrewery/snippets/brew/monster.snippet.js
Normal file
@@ -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
|
||||||
|
|
||||||
|
}}`
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
22
shared/homebrewery/snippets/brew/note.snippet.js
Normal file
@@ -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(' ')}
|
||||||
|
}}`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
421
shared/homebrewery/snippets/brew/random.data.js
Normal file
@@ -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;
|
||||||
41
shared/homebrewery/snippets/brew/spell.snippet.js
Normal file
@@ -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}
|
||||||
|
}}`;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
62
shared/homebrewery/snippets/brew/table.snippet.js
Normal file
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
112
shared/homebrewery/snippets/brew/toc.snippet.js
Normal file
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
`;*/
|
||||||
|
}
|
||||||
|
}
|
||||||
4
shared/homebrewery/snippets/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
brew : require('./brew'),
|
||||||
|
style : require('./style')
|
||||||
|
}
|
||||||
8
shared/homebrewery/snippets/style/a4.snippet.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
a4 : ()=>{
|
||||||
|
return `.phb{
|
||||||
|
width : 210mm;
|
||||||
|
height : 296.8mm;
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
shared/homebrewery/snippets/style/bg.snippet.js
Normal file
@@ -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');
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
shared/homebrewery/snippets/style/index.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = _.merge(
|
||||||
|
require('./ink.snippet.js'),
|
||||||
|
require('./a4.snippet.js'),
|
||||||
|
require('./bg.snippet.js')
|
||||||
|
);
|
||||||
9
shared/homebrewery/snippets/style/ink.snippet.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
inkFriendly : ()=>{
|
||||||
|
return `.phb{ background : white;}
|
||||||
|
.phb img{ display : none;}
|
||||||
|
.phb hr+blockquote{background : white;}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,28 +38,29 @@ var Nav = {
|
|||||||
href : null,
|
href : null,
|
||||||
newTab : false,
|
newTab : false,
|
||||||
onClick : function(){},
|
onClick : function(){},
|
||||||
color : null
|
color : null,
|
||||||
|
collaspe : false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleClick : function(){
|
handleClick : function(){
|
||||||
this.props.onClick();
|
this.props.onClick();
|
||||||
},
|
},
|
||||||
render : function(){
|
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;
|
var icon;
|
||||||
if(this.props.icon) icon = <i className={'fa ' + this.props.icon} />;
|
if(this.props.icon) icon = <i className={'fa ' + this.props.icon} />;
|
||||||
|
|
||||||
const props = _.omit(this.props, ['newTab']);
|
const props = _.omit(this.props, ['newTab', 'collaspe']);
|
||||||
|
|
||||||
if(this.props.href){
|
if(this.props.href){
|
||||||
return <a {...props} className={classes} target={this.props.newTab ? '_blank' : '_self'} >
|
return <a {...props} className={classes} target={this.props.newTab ? '_blank' : '_self'} >
|
||||||
{this.props.children}
|
<span>{this.props.children}</span>
|
||||||
{icon}
|
{icon}
|
||||||
</a>
|
</a>
|
||||||
}else{
|
}else{
|
||||||
return <div {...props} className={classes} onClick={this.handleClick} >
|
return <div {...props} className={classes} onClick={this.handleClick} >
|
||||||
{this.props.children}
|
<span>{this.props.children}</span>
|
||||||
{icon}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
nav{
|
nav{
|
||||||
background-color : #333;
|
background-color : #333;
|
||||||
.navContent{
|
.navContent{
|
||||||
@@ -41,6 +42,7 @@ nav{
|
|||||||
}
|
}
|
||||||
.navItem{
|
.navItem{
|
||||||
.animate(background-color);
|
.animate(background-color);
|
||||||
|
display : inline-block;
|
||||||
padding : 8px 12px;
|
padding : 8px 12px;
|
||||||
cursor : pointer;
|
cursor : pointer;
|
||||||
background-color : #333;
|
background-color : #333;
|
||||||
@@ -53,6 +55,28 @@ nav{
|
|||||||
margin-left : 5px;
|
margin-left : 5px;
|
||||||
font-size : 13px;
|
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 };
|
&.tealLight:hover{ background-color : @tealLight };
|
||||||
&.teal:hover{ background-color : @teal };
|
&.teal:hover{ background-color : @teal };
|
||||||
&.greenLight:hover{ background-color : @greenLight };
|
&.greenLight:hover{ background-color : @greenLight };
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# changelog
|
# changelog
|
||||||
|
|
||||||
|
|
||||||
|
The self-discovery aspect of the snippets isn't working out.
|
||||||
|
|
||||||
|
|
||||||
## BIG NEWS
|
## 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.
|
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.
|
||||||
|
|
||||||
107
statics/faq.md
Normal file
@@ -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
|
||||||
|
|
||||||
@@ -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.
|
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.
|
> One with quotes and what not
|
||||||
> * Set the **Destination** to "Save as PDF"
|
> yeah yeah yeah
|
||||||
> * Set **Paper Size** to "Letter"
|
> {{cite -- Very cool person }}
|
||||||
> * 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
|
|
||||||
|
|
||||||
|
|
||||||
|
{{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
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
```
|
```
|
||||||
|
cool stuff
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Big things coming in v3.0.0
|
## Big things coming in v3.0.0
|
||||||
@@ -55,18 +86,15 @@ If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<img src='http://i.imgur.com/hMna6G0.png' style='position:absolute;bottom:50px;right:30px;width:280px' />
|
|
||||||
|
|
||||||
<div class='pageNumber'>1</div>
|
|
||||||
<div class='footnote'>PART 1 | FANCINESS</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
{{footnote PART 1 | FANCINESS }}
|
||||||
|
|
||||||
|
|
||||||
\page
|
\page
|
||||||
|
|
||||||
|
|
||||||
{{classTable,wide
|
{{frame,wide
|
||||||
##### The Archivist
|
##### The Archivist
|
||||||
| Level | Proficiency Bonus | Features | Statistical Occultism|
|
| Level | Proficiency Bonus | Features | Statistical Occultism|
|
||||||
|:---:|:---:|:---|:---:|
|
|:---:|:---:|:---|:---:|
|
||||||
|
|||||||