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

Homebrew first pass is done

This commit is contained in:
Scott Tolksdorf
2015-12-17 22:15:03 -05:00
parent f968421b5b
commit 1c920e66c0
12 changed files with 589 additions and 241 deletions

View File

@@ -1,91 +0,0 @@
{
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\homebrew\\homebrew.jsx": [
"react",
"lodash",
"classnames",
"marked"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\shared\\naturalCrit\\defaultMonsterManual.js": [],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\shared\\naturalCrit\\combat.actions.js": [
"pico-flux"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\shared\\naturalCrit\\rollDice.js": [
"lodash"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\sidebar\\dmDice\\dmDice.jsx": [
"react",
"lodash",
"classnames",
"naturalCrit/rollDice"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\shared\\naturalCrit\\jsonFileEditor\\jsonFileEditor.jsx": [
"react",
"lodash",
"classnames",
"jsoneditor"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\encounter\\monsterCard\\attackSlot\\attackSlot.jsx": [
"react",
"lodash",
"classnames",
"naturalCrit/rollDice"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\encounter\\monsterCard\\monsterCard.jsx": [
"react",
"lodash",
"classnames",
"./attackSlot/attackSlot.jsx"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\encounter\\encounter.jsx": [
"react",
"lodash",
"classnames",
"naturalCrit/combat.store.js",
"./monsterCard/monsterCard.jsx"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\sidebar\\encounters\\encounters.jsx": [
"react",
"lodash",
"classnames",
"naturalCrit/combat.store.js",
"naturalCrit/combat.actions.js",
"naturalCrit/jsonFileEditor/jsonFileEditor.jsx"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\sidebar\\sidebar.jsx": [
"react",
"lodash",
"classnames",
"naturalCrit/combat.store.js",
"naturalCrit/combat.actions.js",
"./dmDice/dmDice.jsx",
"naturalCrit/jsonFileEditor/jsonFileEditor.jsx",
"./encounters/encounters.jsx"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\shared\\naturalCrit\\randomEncounter.js": [
"lodash"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\shared\\naturalCrit\\combat.store.js": [
"pico-flux",
"lodash",
"naturalCrit/defaultMonsterManual.js",
"naturalCrit/randomEncounter.js"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\combatManager\\combatManager.jsx": [
"react",
"lodash",
"classnames",
"naturalCrit/defaultMonsterManual.js",
"naturalCrit/combat.actions",
"./encounter/encounter.jsx",
"./sidebar/sidebar.jsx",
"naturalCrit/combat.store"
],
"C:\\Dropbox\\root\\Programming\\Javascript\\NaturalCrit\\client\\naturalCrit\\naturalCrit.jsx": [
"react",
"lodash",
"classnames",
"pico-router",
"./homebrew/homebrew.jsx",
"./combatManager/combatManager.jsx"
]
}

Binary file not shown.

View File

@@ -0,0 +1,89 @@
var React = require('react');
var _ = require('lodash');
var cx = require('classnames');
var Snippets = require('./snippets.js');
var Icons = [
{
icon : 'fa-book',
snippet : Snippets.intro,
tooltip : 'Intro'
},
{
icon : 'fa-magic',
snippet : Snippets.spell,
tooltip : 'Spell'
},
{
icon : 'fa-bookmark',
snippet : Snippets.classFeatures,
tooltip : 'Class Intro'
},
{
icon : 'fa-trophy',
snippet : Snippets.destroyUndead,
tooltip : 'Class Feature'
},
{
icon : 'fa-sticky-note',
snippet : Snippets.note,
tooltip : 'Note'
},
{
icon : 'fa-bug',
snippet : Snippets.statBlock,
tooltip : 'Monster Stat Block'
},
]
var Editor = React.createClass({
getDefaultProps: function() {
return {
text : "",
onChange : function(){}
};
},
handleTextChange : function(e){
this.props.onChange(e.target.value);
},
iconClick : function(snippet){
var curPos = this.refs.textarea.selectionStart;
this.props.onChange(this.props.text.slice(0, curPos) +
snippet +
this.props.text.slice(curPos + 1));
},
renderTemplateIcons : function(){
return _.map(Icons, (t) => {
return <div className='icon' key={t.icon}
onClick={this.iconClick.bind(this, t.snippet)}
data-tooltip={t.tooltip}>
<i className={'fa ' + t.icon} />
</div>;
})
},
render : function(){
var self = this;
return(
<div className='editor'>
<div className='textIcons'>
{this.renderTemplateIcons()}
</div>
<textarea
ref='textarea'
value={this.props.text}
onChange={this.handleTextChange} />
</div>
);
}
});
module.exports = Editor;

View File

@@ -0,0 +1,29 @@
.editor{
position : fixed;
height : 100%;
.textIcons{
display: inline-block;
vertical-align: top;
.icon{
cursor: pointer;
width : 30px;
height : 30px;
text-align: center;
line-height: 30px;
font-size: 1.5em;
&:nth-child(1){ background-color: @blue; }
&:nth-child(2){ background-color: @orange; }
&:nth-child(3){ background-color: @red; }
&:nth-child(4){ background-color: @yellow; }
&:nth-child(5){ background-color: @purple; }
&:nth-child(6){ background-color: @green; }
}
}
textarea{
display: inline-block;
height : 100%;
overflow-y: scroll;
width : 300px;
}
}

View File

@@ -0,0 +1,91 @@
module.exports = {
intro : [
'# Welcome to HomeBrew',
'This tool you to effortless make and edit in real time D&D style ideas',
'\nIt uses **markdown-syntax** anda well-designed style sheet to create stuff.',
'As you edit text on the left it will live update on the right.',
"Any changes you make will auto-saved to your browser as well.",
"",
"There's a few premade templates for common things in the PHB.",
"Just hit the icons to inject the template wherever your cursor was in the text box. \n***Have fun.***"
].join('\n'),
classFeatures : [
"## Class Features",
"As a paladin, you gain the following class features.",
"",
"#### Hit Points",
"**Hit Dice:** 1d10 per paladin level <br>",
"**Hit Points at 1st Level:** 10 + your Constitution modifier <br>",
"**Hit Points at Higher Levels:** 1d10 (or 6) + your Constituion modifier per paladin level after 1st",
"",
"#### Proficiencies",
"**Armor:** All armor, Shields <br>",
"**Weapons:** Simple Weapons, martial weapons <br>",
"**Tools:** None <br><br>",
"**Saving Throws:** Wisdom, Charisma <br>",
"**Skills:** Choose two from Athletics, Insight, Intimidation, Medicine, Persuasion, and Religion",
"",
"#### Equipment",
"You start with the following equipment, in addition to the equipment granted by your background:",
"",
"- *(a)* a martial weapon and a shield or *(b)* two martial weapons",
"- *(a)* five javelins or *(b)* any simple melee weapon",
"- Chain mail and a holy symbol",
].join('\n'),
spell : [
"#### Continual Flame",
"*2nd-level evocation* <br>",
"**Casting Time:** 1 action <br>",
"**Range:** Touch <br>",
"**Components:** V, S, M (ruby dust worth 50gp, which the spell consumes) <br>",
"**Duration:** Until dispelled <br><br>",
"A flame, equivalent in brightness to a torch, springs from from an object that you touch. ",
"The effect look like a regular flame, but it creates no heat and doesn't use oxygen. ",
"A *continual flame* can be covered or hidden but not smothered or quenched."
].join('\n'),
destroyUndead : [
"### Destroy Undead",
"Starting at 5th level, when an undead fails its saving throw against your Turn Undead feature,",
"the creature is instantly destroyed if its challange rating is at or below a certain threshold,",
"as shown in the Destroy Undead table.",
"",
"##### Destroy Undead",
"| Cleric Level | Destroys Undead of CR... |",
"|:----:|:-------------|",
"| 5th | 1/2 or lower |",
"| 8th | 1 or lower |",
"| 11th | 2 or lower |",
"| 14th | 3 or lower |",
"| 17th | 4 or lower |\n\n",
].join('\n'),
note : [
"> ##### Variant: Playing on a Grid",
"> If you play out a combat using a square grid and miniatures or other tokens, follow these rules",
">",
"> ***Squares.*** Each square on the grid represents 5 feet.",
">",
"> ***Speed.*** Rather than moving foot by foot, move square by square on the grid. This means you use your speed in 5-foot segments.",
].join('\n'),
statBlock :[
"## Warhorse",
"*Large beast, unaligned*",
"",
"---",
"|STR|DEX|CON|INT|WIS|CHA|",
"|:---:|:---:|:---:|:---:|:---:|:---:|:---:|",
"|18 (+4)|18 (+4)|18 (+4)|18 (+4)|18 (+4)|18 (+4)|",
"---",
"***Trampling Charge*** Does a thing yo",
].join('\n')
}

View File

@@ -2,36 +2,49 @@ var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var PHB = require('./phb/phb.jsx');
var Editor = require('./editor/editor.jsx');
var Snippets = require('./editor/snippets');
var KEY = 'naturalCrit-homebrew';
var Markdown = require('marked');
var Homebrew = React.createClass({ var Homebrew = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
text : "# test \nneato" text : Snippets.intro
}; };
}, },
handleTextChange : function(e){ componentDidMount: function() {
var storage = localStorage.getItem(KEY);
if(storage){
this.setState({
text : storage
})
}
},
console.log(e.value); handleTextChange : function(text){
this.setState({ this.setState({
text : e.target.value text : text
}) });
localStorage.setItem(KEY, text);
}, },
render : function(){ render : function(){
var self = this; var self = this;
console.log(this.state.text);
return( return(
<div className='homebrew'> <div className='homebrew'>
<textarea value={this.state.text} onChange={this.handleTextChange} /> <Editor text={this.state.text} onChange={this.handleTextChange} />
<PHB text={this.state.text} />
<div className='phb' dangerouslySetInnerHTML={{__html:Markdown(this.state.text)}} />
</div> </div>
); );
} }

View File

@@ -1,141 +1,6 @@
@font-face {
font-family : BookInsanity;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity.otf');
}
@font-face {
font-family : BookInsanityBold;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity Bold.otf');
}
@font-face {
font-family : BookInsanityItalic;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity Italic.otf');
}
@font-face {
font-family : BookInsanityBoldItalic;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity Bold Italic.otf');
}
@font-face {
font-family : ScalaSans;
src : url('/assets/naturalCrit/homebrew/assets/Scaly Sans.otf');
}
@font-face {
font-family : Solbera;
src : url('/assets/naturalCrit/homebrew/assets/Solbera Imitation.otf');
}
@font-face {
font-family : MrEaves;
src : url('/assets/naturalCrit/homebrew/assets/MrsEavesSmallCaps_Regular.ttf') format('truetype'),
url('/assets/naturalCrit/homebrew/assets/Mr Eaves Small Caps.otf') format('otf');
}
.homebrew{ .homebrew{
.phb{ background-color: @steel;
height : 100%;
@background : #f2ece4;
@green : #e0e5c1;
@headerUnderline : #c9ad6a;
@horizontalRule : #9c2b1b;
@header : #58180D;
background-image : url('/assets/naturalCrit/homebrew/assets/PHB-background.png');
padding : 30px;
-webkit-column-count: 2; /* Chrome, Safari, Opera */
-moz-column-count: 2; /* Firefox */
column-count: 2;
-webkit-column-width: 200px;
-moz-column-width: 200px;
column-width: 200px;
column-fill : auto;
height : 500px;
text-rendering : optimizeLegibility;
p {
line-height: 1.2em;
font-family : BookInsanity;
font-size : 9pt;
-webkit-column-break-inside:avoid;
-moz-column-break-inside:avoid;
-o-column-break-inside:avoid;
-ms-column-break-inside:avoid;
column-break-inside:avoid;
padding-bottom: 1em;
strong{
font-family : BookInsanityBold;
em{
font-family : BookInsanityBoldItalic;
}
}
em{
font-family : BookInsanityItalic;
}
}
p + p{
text-indent: 1em;
margin-top: -1em;
}
table{
font-family: ScalaSans;
font-size: 10pt;
width : 100%;
thead{
font-weight: 800;
}
tr:nth-child(even){
background: @green;
}
}
blockquote{
background-color: @green;
font-family: ScalaSans;
column-span: all;
-webkit-column-span: all;
}
h1,h2,h3,h4{
font-family : MrEaves;
color : #58180D;
margin: 0.2em 0em;
}
h1{
font-size : 24pt;
column-span: all;
-webkit-column-span: all;
&+p{
&::first-letter{
font-family: Solbera;
float :left;
font-size: 5em;
margin-top: 20px;
margin-bottom: 10px;
}
}
}
h2{
font-size : 20pt;
}
h3{
font-size : 15pt;
border-bottom : 3px solid #D8A866;
}
h4{
font-size : 12pt;
}
h5{
font-family: ScalaSans;
font-weight: 800;
font-size: 12pt;
}
}
} }

View File

@@ -0,0 +1,28 @@
var React = require('react');
var _ = require('lodash');
var cx = require('classnames');
var Markdown = require('marked');
var Phb = React.createClass({
getDefaultProps: function() {
return {
text : ""
};
},
renderPages : function(){
return _.map(this.props.text.split('\page'), (pageText, index) => {
return <div className='phb' dangerouslySetInnerHTML={{__html:Markdown(this.props.text)}} key={index} />
})
},
render : function(){
var self = this;
return <div className="pbhPages">
{this.renderPages()}
</div>;
}
});
module.exports = Phb;

View File

@@ -0,0 +1,190 @@
.pbhPages{
&>.phb{
margin-bottom : 40px;
margin-left : 400px;
}
}
@font-face {
font-family : BookInsanity;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity.otf');
}
@font-face {
font-family : BookInsanityBold;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity Bold.otf');
}
@font-face {
font-family : BookInsanityItalic;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity Italic.otf');
}
@font-face {
font-family : BookInsanityBoldItalic;
src : url('/assets/naturalCrit/homebrew/assets/Bookinsanity Bold Italic.otf');
}
@font-face {
font-family : ScalaSans;
src : url('/assets/naturalCrit/homebrew/assets/Scaly Sans.otf');
}
@font-face {
font-family : ScalaSansBold;
src : url('/assets/naturalCrit/homebrew/assets/Scala Sans Bold.ttf');
}
@font-face {
font-family : ScalaSansSmallCaps;
src : url('/assets/naturalCrit/homebrew/assets/Scala Sans SmallCaps.ttf');
}
@font-face {
font-family : Solbera;
src : url('/assets/naturalCrit/homebrew/assets/Solbera Imitation.otf');
}
@font-face {
font-family : MrEaves;
src : url('/assets/naturalCrit/homebrew/assets/MrsEavesSmallCaps_Regular.ttf') format('truetype'),
url('/assets/naturalCrit/homebrew/assets/Mr Eaves Small Caps.otf') format('otf');
}
.phb{
@background : #f2ece4;
@green : #e0e5c1;
@headerUnderline : #c9ad6a;
@horizontalRule : #9c2b1b;
@header : #58180D;
box-sizing : border-box;
height : 27.5cm;
width : 21cm;
padding : 1.0cm 1.7cm;
column-count : 2;
column-fill : auto;
column-width : 8cm;
background-image : url('/assets/naturalCrit/homebrew/assets/PHB-background.png');
-webkit-column-count : 2;
-moz-column-count : 2;
-webkit-column-width : 8cm;
-moz-column-width : 8cm;
column-gap : 1cm;
-webkit-column-gap : 1cm;
text-rendering : optimizeLegibility;
p,ul{
-webkit-column-break-inside : avoid;
-moz-column-break-inside : avoid;
-o-column-break-inside : avoid;
-ms-column-break-inside : avoid;
column-break-inside : avoid;
strong{
font-family : BookInsanityBold;
em{
font-family : BookInsanityBoldItalic;
}
}
em{
font-family : BookInsanityItalic;
}
}
p {
padding-bottom : 1em;
font-family : BookInsanity;
font-size : 9pt;
line-height : 1.3em;
&+p{
margin-top : -1em;
text-indent : 1em;
}
}
ul{
margin-bottom : 1em;
font-family : BookInsanity;
font-size : 9pt;
line-height : 1.3em;
list-style-position : inside;
list-style-type : disc;
}
table{
width : 100%;
margin-bottom : 1em;
font-family : ScalaSans;
font-size : 10pt;
thead{
font-weight : 800;
th{
padding-bottom : 0.3em;
}
}
tr{
td{
padding : 0.2em 0em;
}
&:nth-child(even){
background : @green;
}
}
}
blockquote{
background-color : @green;
font-family : ScalaSans;
box-sizing: border-box;
padding : 5px 10px;
border-top : 2px black solid;
border-bottom : 2px black solid;
box-shadow: 1px 4px 14px #888;
margin-bottom: 1em;
p{
font-family : ScalaSans;
font-size: 10pt;
line-height: 1.1em;
em{
font-family : ScalaSans;
font-style: italic;
}
strong{
font-weight: 800;
em{
font-weight: 800;
font-style: italic;
}
}
}
}
pre{
}
h1,h2,h3,h4{
margin-top : 0.2em;
margin-bottom : 0.2em;
font-family : MrEaves;
font-weight : 800;
color : @header;
}
h1{
column-span : all;
font-size : 28pt;
-webkit-column-span : all;
&+p{
&::first-letter{
float : left;
margin-top : 20px;
margin-bottom : 10px;
font-family : Solbera;
font-size : 5em;
}
}
}
h2{
font-size : 20pt;
}
h3{
font-size : 15pt;
border-bottom : 2px solid @headerUnderline;
}
h4{
font-size : 12pt;
margin-bottom: 0.00em;
}
h5{
margin-bottom : 0.2em;
font-family : ScalaSansSmallCaps;
font-size : 13pt;
font-weight : 900;
}
}

View File

@@ -2,7 +2,11 @@
//@import 'naturalCrit/styles/elements.less'; //@import 'naturalCrit/styles/elements.less';
@import 'naturalCrit/styles/animations.less'; @import 'naturalCrit/styles/animations.less';
@import 'naturalCrit/styles/colors.less'; @import 'naturalCrit/styles/colors.less';
@import 'naturalCrit/styles/tooltip.less';
html,body, #reactContainer, .naturalCrit{
min-height : 100%;
}
@sidebarWidth : 250px; @sidebarWidth : 250px;
@@ -14,6 +18,7 @@ body{
text-rendering : optimizeLegibility; text-rendering : optimizeLegibility;
margin : 0; margin : 0;
padding : 0; padding : 0;
height : 100%;
} }
.naturalCrit{ .naturalCrit{

View File

@@ -0,0 +1,129 @@
@tooltipColor : #383838;
@arrowSize : 6px;
@arrowPosition : 18px;
[data-tooltip]{
.tooltip(attr(data-tooltip));
}
[data-tooltip-top]{
.tooltipTop(attr(data-tooltip-top));
}
[data-tooltip-bottom]{
.tooltipBottom(attr(data-tooltip-bottom));
}
[data-tooltip-left]{
.tooltipLeft(attr(data-tooltip-left));
}
[data-tooltip-right]{
.tooltipRight(attr(data-tooltip-right));
}
.tooltip(@content){
.tooltipBottom(@content);
}
.tooltipTop(@content){
.tooltipBase(@content);
&:before {
margin-bottom: -@arrowSize * 2;
border-top-color: @tooltipColor;
}
&:after{ margin-left: -18px; }
&:before, &:after {
bottom: 100%;
left: 50%; }
&:hover:after, &:hover:before, &:focus:after, &:focus:before {
.transform(translateY(-(@arrowSize + 2)));
}
}
.tooltipBottom(@content){
.tooltipBase(@content);
&:before {
margin-top: -@arrowSize * 2;
border-bottom-color: @tooltipColor;
}
&:after{ margin-left: -18px; }
&:before, &:after {
top: 100%;
left: 50%; }
&:hover:after, &:hover:before, &:focus:after, &:focus:before {
.transform(translateY(@arrowSize + 2));
}
}
.tooltipLeft(@content){
.tooltipBase(@content);
&:before {
margin-right: -@arrowSize * 2;
margin-bottom: -@arrowSize;
border-left-color: @tooltipColor;
}
&:after{ margin-bottom: -14px;}
&:before, &:after {
right: 100%;
bottom: 50%; }
&:hover:after, &:hover:before, &:focus:after, &:focus:before {
.transform(translateX(-(@arrowSize + 2)));
}
}
.tooltipRight(@content){
.tooltipBase(@content);
&:before {
margin-left: -@arrowSize * 2;
margin-bottom: -@arrowSize;
border-right-color: @tooltipColor;
}
&:after{ margin-bottom: -14px;}
&:before, &:after {
left: 100%;
bottom: 50%; }
&:hover:after, &:hover:before, &:focus:after, &:focus:before {
.transform(translateX(@arrowSize + 2));
}
}
.tooltipShow(){
}
.tooltipBase(@content){
position: relative;
&:before, &:after{
.animateAll();
position: absolute;
opacity: 0;
z-index: 1000000;
pointer-events: none;
}
//Arrow
&:before{
content: '';
background: transparent;
border: @arrowSize solid transparent;
z-index: 1000001;
}
//Box
&:after{
content: @content;
color: white;
background: @tooltipColor;
padding: 8px 10px;
font-size: 12px;
line-height: 12px;
white-space: nowrap;
visibility: hidden;
}
&:hover:before, &:hover:after {
visibility: visible;
opacity: 1;
}
}