mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-23 16:33:05 +00:00
Compare commits
6 Commits
add-remove
...
splat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62b9400df1 | ||
|
|
cb5b63429e | ||
|
|
263257bfb8 | ||
|
|
e61e1a698d | ||
|
|
536a768133 | ||
|
|
312167d96b |
@@ -1,18 +1,16 @@
|
||||
|
||||
@import 'naturalCrit/styles/reset.less';
|
||||
//@import 'naturalCrit/styles/elements.less';
|
||||
@import 'naturalCrit/styles/animations.less';
|
||||
@import 'naturalCrit/styles/colors.less';
|
||||
@import 'naturalCrit/styles/tooltip.less';
|
||||
|
||||
html,body, #reactContainer{
|
||||
min-height: 100%;
|
||||
font-family : 'Open Sans', sans-serif;
|
||||
min-height : 100%;
|
||||
font-family : 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
.homebrew{
|
||||
background-color: @steel;
|
||||
height : 100%;
|
||||
|
||||
height : 100%;
|
||||
background-color : @steel;
|
||||
.paneSplit{
|
||||
width : 100%;
|
||||
height: 100vh;
|
||||
@@ -29,7 +27,6 @@ html,body, #reactContainer{
|
||||
min-height: 100%;
|
||||
//margin-top: 25px;
|
||||
}
|
||||
|
||||
.leftPane{
|
||||
width : 40%;
|
||||
}
|
||||
@@ -40,6 +37,5 @@ html,body, #reactContainer{
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
25
client/splatsheet/sheetEditor/sheetEditor.jsx
Normal file
25
client/splatsheet/sheetEditor/sheetEditor.jsx
Normal file
@@ -0,0 +1,25 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var SheetEditor = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
code : '',
|
||||
onChange : function(){}
|
||||
};
|
||||
},
|
||||
|
||||
handleCodeChange : function(e){
|
||||
this.props.onChange(e.target.value);
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <div className='sheetEditor'>
|
||||
<h2>Sheet Template</h2>
|
||||
<textarea value={this.props.code} onChange={this.handleCodeChange} />
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SheetEditor;
|
||||
8
client/splatsheet/sheetEditor/sheetEditor.less
Normal file
8
client/splatsheet/sheetEditor/sheetEditor.less
Normal file
@@ -0,0 +1,8 @@
|
||||
.sheetEditor{
|
||||
|
||||
textarea{
|
||||
height : 300px;
|
||||
width : 80%;
|
||||
}
|
||||
|
||||
}
|
||||
54
client/splatsheet/sheetRenderer/parts/box/box.jsx
Normal file
54
client/splatsheet/sheetRenderer/parts/box/box.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var utils = require('../utils');
|
||||
|
||||
var Box = React.createClass({
|
||||
mixins : [utils],
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
//name : 'box',
|
||||
defaultData : {},
|
||||
|
||||
id : '',
|
||||
title : '',
|
||||
label : '',
|
||||
shadow : false,
|
||||
border : false
|
||||
};
|
||||
},
|
||||
|
||||
handleChange : function(newData){
|
||||
this.updateData(newData);
|
||||
},
|
||||
|
||||
renderChildren : function(){
|
||||
return React.Children.map(this.props.children, (child)=>{
|
||||
if(!React.isValidElement(child)) return null;
|
||||
return React.cloneElement(child, {
|
||||
onChange : this.handleChange,
|
||||
data : this.data()
|
||||
})
|
||||
})
|
||||
},
|
||||
renderTitle : function(){
|
||||
if(this.props.title) return <h5 className='title'>{this.props.title}</h5>
|
||||
},
|
||||
renderLabel : function(){
|
||||
if(this.props.label) return <h5 className='label'>{this.props.label}</h5>
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <div className={cx('box', this.props.className, {
|
||||
shadow : this.props.shadow,
|
||||
border : this.props.border
|
||||
})}>
|
||||
{this.renderTitle()}
|
||||
{this.renderChildren()}
|
||||
{this.renderLabel()}
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Box;
|
||||
30
client/splatsheet/sheetRenderer/parts/box/box.less
Normal file
30
client/splatsheet/sheetRenderer/parts/box/box.less
Normal file
@@ -0,0 +1,30 @@
|
||||
.box{
|
||||
position : relative;
|
||||
padding : 10px;
|
||||
margin: 10px;
|
||||
|
||||
&.border{
|
||||
border: 1px solid black;
|
||||
}
|
||||
&.shadow{
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
h5{
|
||||
text-transform: uppercase;
|
||||
font-size : 0.6em;
|
||||
text-align: center;
|
||||
width : 100%;
|
||||
font-weight: 800;
|
||||
|
||||
&.title{
|
||||
margin-top: -5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
&.label{
|
||||
margin-bottom: -5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
client/splatsheet/sheetRenderer/parts/index.js
Normal file
13
client/splatsheet/sheetRenderer/parts/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
TextInput : require('./textInput/textInput.jsx'),
|
||||
PlayerInfo : require('./playerInfo/playerInfo.jsx'),
|
||||
|
||||
SkillList : require('./skillList/skillList.jsx'),
|
||||
Skill : require('./skill/skill.jsx'),
|
||||
|
||||
//ShadowBox : require('./shadowBox/shadowBox.jsx'),
|
||||
//BorderBox : require('./borderBox/borderBox.jsx'),
|
||||
|
||||
|
||||
Box : require('./box/box.jsx')
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var TextInput = require('../textInput/textInput.jsx');
|
||||
var Box = require('../box/box.jsx');
|
||||
|
||||
var PlayerInfo = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "player info",
|
||||
border : true
|
||||
};
|
||||
},
|
||||
render : function(){
|
||||
return <Box className='playerInfo' {...this.props} >
|
||||
<TextInput label="Name" placeholder="name" />
|
||||
<TextInput label="Class" />
|
||||
<TextInput label="Race" />
|
||||
{this.props.children}
|
||||
</Box>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = PlayerInfo;
|
||||
@@ -0,0 +1,3 @@
|
||||
.playerInfo{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
62
client/splatsheet/sheetRenderer/parts/skill/skill.jsx
Normal file
62
client/splatsheet/sheetRenderer/parts/skill/skill.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var utils = require('../utils');
|
||||
|
||||
var Skill = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
name : 'skill',
|
||||
defaultData : {
|
||||
prof : false,
|
||||
expert : false,
|
||||
val : ''
|
||||
},
|
||||
|
||||
id : '',
|
||||
label : '',
|
||||
sublabel : '',
|
||||
showExpert : false
|
||||
};
|
||||
},
|
||||
|
||||
id : utils.id,
|
||||
data : utils.data,
|
||||
updateData : utils.updateData,
|
||||
|
||||
handleToggleProf : function(){
|
||||
this.updateData({
|
||||
prof : !this.data().prof
|
||||
})
|
||||
},
|
||||
handleToggleExpert : function(){
|
||||
this.updateData({
|
||||
expert : !this.data().expert
|
||||
})
|
||||
},
|
||||
handleValChange : function(e){
|
||||
console.log('yo');
|
||||
this.updateData({
|
||||
val : e.target.value
|
||||
})
|
||||
},
|
||||
renderExpert : function(){
|
||||
if(this.props.showExpert){
|
||||
return <input type="radio" className='expertToggle' onChange={this.handleToggleExpert} checked={this.data().expert} />
|
||||
}
|
||||
},
|
||||
render : function(){
|
||||
return <div className='skill'>
|
||||
{this.renderExpert()}
|
||||
<input type="radio" className='skillToggle' onChange={this.handleToggleProf} checked={this.data().prof} />
|
||||
<input type='text' onChange={this.handleValChange} value={this.data().val} />
|
||||
<label>
|
||||
{this.props.label}
|
||||
<small>{this.props.sublabel}</small>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Skill;
|
||||
35
client/splatsheet/sheetRenderer/parts/skill/skill.less
Normal file
35
client/splatsheet/sheetRenderer/parts/skill/skill.less
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
.skill{
|
||||
position : relative;
|
||||
padding-left : 15px;
|
||||
input[type="radio"]{
|
||||
margin : 0px;
|
||||
}
|
||||
.expertToggle{
|
||||
position : absolute;
|
||||
top : 1px;
|
||||
left : 0px;
|
||||
}
|
||||
input[type="text"]{
|
||||
width : 25px;
|
||||
margin-left : 10px;
|
||||
background-color : transparent;
|
||||
text-align : center;
|
||||
border : none;
|
||||
border-bottom : 1px solid black;
|
||||
outline : none;
|
||||
&:focus{
|
||||
background-color : #ddd;
|
||||
}
|
||||
}
|
||||
label{
|
||||
margin-left : 10px;
|
||||
font-size : 0.8em;
|
||||
small{
|
||||
margin-left : 5px;
|
||||
font-size : 0.8em;
|
||||
color : #999;
|
||||
text-transform : uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var Skill = require('../skill/skill.jsx');
|
||||
var Box = require('../box/box.jsx');
|
||||
|
||||
|
||||
var skill_list = [
|
||||
{name : 'Acrobatics', stat : 'Dex'},
|
||||
{name : 'Animal Handling', stat : 'Wis'},
|
||||
{name : 'Arcana', stat : 'Int'},
|
||||
{name : 'Athletics', stat : 'Str'},
|
||||
{name : 'Deception', stat : 'Cha'},
|
||||
{name : 'History', stat : 'Int'},
|
||||
{name : 'Insight', stat : 'Wis'},
|
||||
{name : 'Intimidation', stat : 'Cha'},
|
||||
{name : 'Investigation', stat : 'Int'},
|
||||
{name : 'Medicine', stat : 'Wis'},
|
||||
{name : 'Nature', stat : 'Int'},
|
||||
{name : 'Perception', stat : 'Wis'},
|
||||
{name : 'Performance', stat : 'Cha'},
|
||||
{name : 'Persuasion', stat : 'Cha'},
|
||||
{name : 'Religion', stat : 'Int'},
|
||||
{name : 'Sleight of Hand', stat : 'Dex'},
|
||||
{name : 'Stealth', stat : 'Dex'},
|
||||
{name : 'Survival', stat : 'Wis'}
|
||||
]
|
||||
|
||||
|
||||
var SkillList = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
name : 'skills',
|
||||
|
||||
//title : 'Skills',
|
||||
shadow : true,
|
||||
border : false,
|
||||
showExpert : false
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
renderSkills : function(){
|
||||
return _.map(skill_list, (skill)=>{
|
||||
return <Skill
|
||||
label={skill.name}
|
||||
sublabel={'(' + skill.stat + ')'}
|
||||
showExpert={this.props.showExpert} />
|
||||
})
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <Box className='skillList' {...this.props}>
|
||||
{this.renderSkills()}
|
||||
{this.props.children}
|
||||
</Box>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SkillList;
|
||||
@@ -0,0 +1,3 @@
|
||||
.COM{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var utils = require('../utils');
|
||||
|
||||
var TextInput = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
name : 'text',
|
||||
defaultData : '',
|
||||
|
||||
id : '',
|
||||
label : '',
|
||||
};
|
||||
},
|
||||
|
||||
id : utils.id,
|
||||
data : utils.data,
|
||||
updateData : utils.updateData,
|
||||
|
||||
handleChange : function(e){
|
||||
this.updateData(e.target.value);
|
||||
},
|
||||
|
||||
renderLabel : function(){
|
||||
if(this.props.label) return <label htmlFor={this.id()}>{this.props.label}</label>
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <div className='textInput'>
|
||||
{this.renderLabel()}
|
||||
<input
|
||||
id={this.id()}
|
||||
type='text'
|
||||
onChange={this.handleChange}
|
||||
value={this.data()}
|
||||
placeholder={this.props.placeholder}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = TextInput;
|
||||
@@ -0,0 +1,6 @@
|
||||
.textInput{
|
||||
label{
|
||||
display: inline-block;
|
||||
width : 50px;
|
||||
}
|
||||
}
|
||||
33
client/splatsheet/sheetRenderer/parts/utils.js
Normal file
33
client/splatsheet/sheetRenderer/parts/utils.js
Normal file
@@ -0,0 +1,33 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
|
||||
module.exports = {
|
||||
id : function(){
|
||||
if(this.props.id) return this.props.id;
|
||||
if(this.props.label) return _.snakeCase(this.props.label);
|
||||
if(this.props.title) return _.snakeCase(this.props.title);
|
||||
return this.props.name;
|
||||
},
|
||||
data : function(){
|
||||
if(!this.id()) return this.props.data || this.props.defaultData;
|
||||
if(this.props.data && this.props.data[this.id()]) return this.props.data[this.id()];
|
||||
return this.props.defaultData;
|
||||
},
|
||||
updateData : function(val){
|
||||
if(typeof this.props.onChange !== 'function') throw "No onChange handler set";
|
||||
|
||||
var newVal = val;
|
||||
|
||||
//Clone the data if it's an object to avoid mutation bugs
|
||||
if(_.isObject(val)) newVal = _.extend({}, this.data(), val);
|
||||
|
||||
if(this.id()){
|
||||
this.props.onChange({
|
||||
[this.id()] : newVal
|
||||
});
|
||||
}else{
|
||||
//If the box has no id, don't add it to the chain
|
||||
this.props.onChange(newVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
79
client/splatsheet/sheetRenderer/sheetRenderer.jsx
Normal file
79
client/splatsheet/sheetRenderer/sheetRenderer.jsx
Normal file
@@ -0,0 +1,79 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var jsx2json = require('jsx-parser');
|
||||
|
||||
var Parts = require('./parts');
|
||||
|
||||
|
||||
var SheetRenderer = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
code : '',
|
||||
characterData : {},
|
||||
onChange : function(){},
|
||||
};
|
||||
},
|
||||
|
||||
renderElement : function(node, key){
|
||||
if(!node.tag) return null;
|
||||
|
||||
if(!Parts[node.tag]) throw 'Could Not Find Element: ' + node.tag
|
||||
|
||||
return React.createElement(
|
||||
Parts[node.tag],
|
||||
{key : key, ...node.props},
|
||||
...this.renderChildren(node.children))
|
||||
},
|
||||
renderChildren : function(nodes){
|
||||
return _.map(nodes, (node, index)=>{
|
||||
if(_.isString(node)) return node;
|
||||
return this.renderElement(node, index);
|
||||
})
|
||||
},
|
||||
renderSheet : function(){
|
||||
try{
|
||||
var nodes = jsx2json(this.props.code);
|
||||
nodes = _.map(nodes, (node)=>{
|
||||
node.props.data = this.props.characterData;
|
||||
node.props.onChange = (newData)=>{
|
||||
this.props.onChange(_.extend(this.props.characterData, newData));
|
||||
}
|
||||
return node
|
||||
})
|
||||
return this.renderChildren(nodes);
|
||||
}catch(e){
|
||||
return <div>Error bruh {e.toString()}</div>
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
render : function(){
|
||||
return <div className='sheetRenderer'>
|
||||
|
||||
<h2>Character Sheet</h2>
|
||||
|
||||
<div className='sheetContainer' ref='sheetContainer'>
|
||||
{this.renderSheet()}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = SheetRenderer;
|
||||
|
||||
|
||||
/*
|
||||
|
||||
<Temp text="cool">yo test <a href="google.com">link</a> </Temp>
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
11
client/splatsheet/sheetRenderer/sheetRenderer.less
Normal file
11
client/splatsheet/sheetRenderer/sheetRenderer.less
Normal file
@@ -0,0 +1,11 @@
|
||||
.sheetRenderer{
|
||||
|
||||
padding-right : 10px;
|
||||
|
||||
|
||||
.sheetContainer{
|
||||
background-color: white;
|
||||
padding : 20px;
|
||||
}
|
||||
|
||||
}
|
||||
73
client/splatsheet/splatsheet.jsx
Normal file
73
client/splatsheet/splatsheet.jsx
Normal file
@@ -0,0 +1,73 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var StatusBar = require('./statusBar/statusBar.jsx');
|
||||
var SheetEditor = require('./sheetEditor/sheetEditor.jsx');
|
||||
var SheetRenderer = require('./sheetRenderer/sheetRenderer.jsx');
|
||||
|
||||
|
||||
const SPLATSHEET_TEMPLATE = 'splatsheet_template';
|
||||
const SPLATSHEET_CHARACTER = 'splatsheet_character';
|
||||
|
||||
|
||||
var SplatSheet = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
sheetCode: '',
|
||||
characterData : {}
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.setState({
|
||||
sheetCode : localStorage.getItem(SPLATSHEET_TEMPLATE),
|
||||
characterData : JSON.parse(localStorage.getItem(SPLATSHEET_CHARACTER)) || this.state.characterData
|
||||
})
|
||||
},
|
||||
|
||||
handleCodeChange : function(text){
|
||||
this.setState({
|
||||
sheetCode : text,
|
||||
});
|
||||
localStorage.setItem(SPLATSHEET_TEMPLATE, text);
|
||||
},
|
||||
|
||||
handeCharacterChange : function(data){
|
||||
this.setState({
|
||||
characterData : JSON.parse(JSON.stringify(data)),
|
||||
});
|
||||
localStorage.setItem(SPLATSHEET_CHARACTER, JSON.stringify(data));
|
||||
},
|
||||
|
||||
clearCharacterData : function(){
|
||||
this.handeCharacterChange({});
|
||||
},
|
||||
|
||||
|
||||
render : function(){
|
||||
return <div className='splatsheet'>
|
||||
<StatusBar />
|
||||
|
||||
<div className='paneSplit'>
|
||||
<div className='leftPane'>
|
||||
<SheetEditor code={this.state.sheetCode} onChange={this.handleCodeChange} />
|
||||
<h2>
|
||||
Character Data
|
||||
<i className='fa fa-times' style={{color : 'red'}} onClick={this.clearCharacterData} />
|
||||
</h2>
|
||||
<pre><code>{JSON.stringify(this.state.characterData, null, ' ')}</code></pre>
|
||||
</div>
|
||||
<div className='rightPane'>
|
||||
<SheetRenderer
|
||||
code={this.state.sheetCode}
|
||||
characterData={this.state.characterData}
|
||||
onChange={this.handeCharacterChange} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SplatSheet;
|
||||
58
client/splatsheet/splatsheet.less
Normal file
58
client/splatsheet/splatsheet.less
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
@import 'naturalCrit/styles/reset.less';
|
||||
//@import 'naturalCrit/styles/elements.less';
|
||||
@import 'naturalCrit/styles/animations.less';
|
||||
@import 'naturalCrit/styles/colors.less';
|
||||
@import 'naturalCrit/styles/tooltip.less';
|
||||
html,body, #reactContainer{
|
||||
min-height : 100%;
|
||||
font-family : 'Open Sans', sans-serif;
|
||||
}
|
||||
.splatsheet{
|
||||
height : 100%;
|
||||
background-color : @steel;
|
||||
.paneSplit{
|
||||
position : relative;
|
||||
box-sizing : border-box;
|
||||
height : 100vh;
|
||||
width : 100%;
|
||||
padding-top : 25px;
|
||||
.leftPane, .rightPane{
|
||||
position : relative;
|
||||
display : inline-block;
|
||||
vertical-align : top;
|
||||
height : 100%;
|
||||
min-height : 100%;
|
||||
}
|
||||
.leftPane{
|
||||
width : 50%;
|
||||
}
|
||||
.rightPane{
|
||||
overflow-y : scroll;
|
||||
height : 100%;
|
||||
width : 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
h2{
|
||||
color : white;
|
||||
margin-top: 20px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
pre{
|
||||
background-color: black;
|
||||
padding : 10px;
|
||||
display: inline-block;
|
||||
min-width: 200px;
|
||||
code{
|
||||
font-size: 0.8em;
|
||||
font-family: monospace;
|
||||
color : @teal;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
30
client/splatsheet/statusbar/statusbar.jsx
Normal file
30
client/splatsheet/statusbar/statusbar.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var Logo = require('naturalCrit/logo/logo.jsx');
|
||||
|
||||
var Statusbar = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return <div className='statusbar'>
|
||||
<Logo
|
||||
hoverSlide={true}
|
||||
/>
|
||||
<div className='left'>
|
||||
<a href='/splatsheet' className='toolName'>
|
||||
The SplatSheet
|
||||
</a>
|
||||
</div>
|
||||
<div className='controls right'>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Statusbar;
|
||||
135
client/splatsheet/statusbar/statusbar.less
Normal file
135
client/splatsheet/statusbar/statusbar.less
Normal file
@@ -0,0 +1,135 @@
|
||||
|
||||
.statusbar{
|
||||
position : fixed;
|
||||
z-index : 1000;
|
||||
height : 25px;
|
||||
width : 100%;
|
||||
background-color : black;
|
||||
font-size : 24px;
|
||||
color : white;
|
||||
line-height : 1.0em;
|
||||
border-bottom : 1px solid @grey;
|
||||
.logo{
|
||||
display : inline-block;
|
||||
vertical-align : middle;
|
||||
margin-top : -5px;
|
||||
margin-right : 20px;
|
||||
svg{
|
||||
margin-top : -6px;
|
||||
}
|
||||
}
|
||||
.left{
|
||||
display : inline-block;
|
||||
vertical-align : top;
|
||||
}
|
||||
.right{
|
||||
float : right;
|
||||
}
|
||||
.toolName{
|
||||
display : block;
|
||||
vertical-align : middle;
|
||||
font-family : CodeBold;
|
||||
font-size : 16px;
|
||||
color : white;
|
||||
line-height : 30px;
|
||||
text-decoration : none;
|
||||
small{
|
||||
font-family : CodeBold;
|
||||
}
|
||||
}
|
||||
.controls{
|
||||
font-size : 12px;
|
||||
>*{
|
||||
display : inline-block;
|
||||
height : 100%;
|
||||
padding : 0px 10px;
|
||||
border-left : 1px solid @grey;
|
||||
}
|
||||
.savingStatus{
|
||||
width : 56px;
|
||||
color : @grey;
|
||||
text-align : center;
|
||||
}
|
||||
.newButton{
|
||||
.animate(background-color);
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
&:hover{
|
||||
background-color : fade(@green, 70%);
|
||||
}
|
||||
}
|
||||
.chromeField{
|
||||
background-color: @orange;
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
i{
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.changelogButton{
|
||||
.animate(background-color);
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
&:hover{
|
||||
background-color : fade(@purple, 70%);
|
||||
}
|
||||
}
|
||||
.deleteButton{
|
||||
.animate(background-color);
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
background-color : fade(@red, 70%);
|
||||
}
|
||||
}
|
||||
.shareField{
|
||||
.animate(background-color);
|
||||
cursor : pointer;
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
&:hover{
|
||||
background-color : fade(@teal, 70%);
|
||||
}
|
||||
span{
|
||||
margin-right : 5px;
|
||||
}
|
||||
input{
|
||||
width : 100px;
|
||||
font-size : 12px;
|
||||
}
|
||||
}
|
||||
.printField{
|
||||
.animate(background-color);
|
||||
cursor : pointer;
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
&:hover{
|
||||
background-color : fade(@orange, 70%);
|
||||
}
|
||||
span{
|
||||
margin-right : 5px;
|
||||
}
|
||||
input{
|
||||
width : 100px;
|
||||
font-size : 12px;
|
||||
}
|
||||
}
|
||||
.sourceField{
|
||||
.animate(background-color);
|
||||
cursor : pointer;
|
||||
color : white;
|
||||
text-decoration : none;
|
||||
&:hover{
|
||||
background-color : fade(@teal, 70%);
|
||||
}
|
||||
span{
|
||||
margin-right : 5px;
|
||||
}
|
||||
input{
|
||||
width : 100px;
|
||||
font-size : 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
gulpfile.js
12
gulpfile.js
@@ -5,7 +5,14 @@ var gulp = require("gulp");
|
||||
|
||||
|
||||
var gulp = vitreumTasks(gulp, {
|
||||
entryPoints: ["./client/naturalCrit", "./client/homebrew", "./client/admin"],
|
||||
entryPoints: [
|
||||
"./client/naturalCrit",
|
||||
|
||||
"./client/splatsheet",
|
||||
"./client/homebrew",
|
||||
|
||||
"./client/admin"
|
||||
],
|
||||
|
||||
DEV: true,
|
||||
|
||||
@@ -48,3 +55,6 @@ gulp.task('phb', function(){
|
||||
.pipe(gulp.dest('./'));
|
||||
})
|
||||
|
||||
|
||||
|
||||
//Maybe remove later?
|
||||
|
||||
39
jsx.test.js
Normal file
39
jsx.test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
require('app-module-path').addPath('./shared');
|
||||
|
||||
|
||||
var jsx = require('xml2js').parseString;
|
||||
|
||||
var parser = require('xml2json');
|
||||
var XMLMapping = require('xml-mapping');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var xml = `
|
||||
<NewBlock woh="6" cant_be="neato">
|
||||
<Weird href="cooool things" />
|
||||
<span> hey! </span>
|
||||
<span> me too! </span>
|
||||
</NewBlock>
|
||||
`
|
||||
|
||||
var json = XMLMapping.load(xml);
|
||||
|
||||
return console.log(JSON.stringify(json, null, ' '));
|
||||
|
||||
|
||||
/*
|
||||
return console.log(parser.toJson(xml, {
|
||||
|
||||
arrayNotation: true,reversible: true,
|
||||
|
||||
}));
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
jsx(xml, {trim: true}, function (err, result) {
|
||||
console.log(JSON.stringify(result, null, ' '));
|
||||
});
|
||||
@@ -64,9 +64,11 @@ app.get('/admin', function(req, res){
|
||||
|
||||
|
||||
app = require('./server/homebrew.api.js')(app);
|
||||
app = require('./server/splatsheet.api.js')(app);
|
||||
|
||||
|
||||
|
||||
//Render the homepage
|
||||
app.get('*', function (req, res) {
|
||||
vitreumRender({
|
||||
page: './build/naturalCrit/bundle.dot',
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
var pdf = require('html-pdf');
|
||||
var Markdown = require('marked');
|
||||
|
||||
var PHBStyle = '<style>' + require('fs').readFileSync('../phb.standalone.css', 'utf8') + '</style>'
|
||||
|
||||
|
||||
var content = Markdown('# oh hey \n welcome! isnt this neat \n \\page ##### test');
|
||||
|
||||
|
||||
var html = "<html><head>" + PHBStyle + "</head><body><div class='phb'>"+ content +"</div></body></html>"
|
||||
|
||||
//var h = 279.4 - 20*2.8;
|
||||
var h = 279.4 - 56;
|
||||
|
||||
|
||||
|
||||
//var w = 215.9 - 56*1.7
|
||||
|
||||
var w = 215.9 - 43;
|
||||
|
||||
|
||||
var config = {
|
||||
"height": (279.4 - 56) + "mm",
|
||||
"width": (215.9 - 43) + "mm",
|
||||
"border": "0",
|
||||
}
|
||||
|
||||
pdf.create(html, config).toFile('./temp.pdf', function(err, res){
|
||||
console.log(err);
|
||||
console.log(res.filename);
|
||||
});
|
||||
Binary file not shown.
27
server/splatsheet.api.js
Normal file
27
server/splatsheet.api.js
Normal file
@@ -0,0 +1,27 @@
|
||||
var _ = require('lodash');
|
||||
var Moment = require('moment');
|
||||
var vitreumRender = require('vitreum/render');
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = function(app){
|
||||
|
||||
app.get('/splatsheet', function(req, res){
|
||||
vitreumRender({
|
||||
page: './build/splatsheet/bundle.dot',
|
||||
globals:{},
|
||||
prerenderWith : './client/splatsheet/splatsheet.jsx',
|
||||
initialProps: {
|
||||
url: req.originalUrl,
|
||||
},
|
||||
clearRequireCache : true,
|
||||
}, function (err, page) {
|
||||
return res.send(page)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
return app;
|
||||
}
|
||||
BIN
server/temp.pdf
BIN
server/temp.pdf
Binary file not shown.
229
shared/jsx-parser.js
Normal file
229
shared/jsx-parser.js
Normal file
@@ -0,0 +1,229 @@
|
||||
var WHITESPACE = /(\s|\t|\n|\r)/g;
|
||||
var NUMBERS = /[0-9]/;
|
||||
var LETTERS = /[a-zA-Z_]/;
|
||||
|
||||
var tokenizer = function(input){
|
||||
var tokens = [];
|
||||
var current = 0;
|
||||
var inTag = false;
|
||||
|
||||
while(current < input.length){
|
||||
var char = input[current];
|
||||
|
||||
var getToken = function(regex){
|
||||
var value = '';
|
||||
while(regex.test(char) && current < input.length){
|
||||
value += char;
|
||||
char = input[++current];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
if(inTag){
|
||||
if(char == '>'){
|
||||
inTag = false;
|
||||
tokens.push({
|
||||
type : 'closeTag'
|
||||
})
|
||||
}
|
||||
else if(char == '/' && input[current+1] == '>'){
|
||||
inTag = false;
|
||||
tokens.push({
|
||||
type : 'endTag'
|
||||
})
|
||||
current++;
|
||||
}
|
||||
else if(char == '='){
|
||||
tokens.push({
|
||||
type : 'equals'
|
||||
});
|
||||
}
|
||||
else if(WHITESPACE.test(char)){
|
||||
|
||||
}
|
||||
else if(NUMBERS.test(char)){
|
||||
tokens.push({
|
||||
type : 'number',
|
||||
value : getToken(NUMBERS)*1
|
||||
});
|
||||
current--;
|
||||
}
|
||||
else if(LETTERS.test(char)){
|
||||
var word = getToken(LETTERS);
|
||||
if(word == 'true' || word == 'false'){
|
||||
tokens.push({
|
||||
type : 'boolean',
|
||||
value : word == 'true'
|
||||
});
|
||||
}else{
|
||||
tokens.push({
|
||||
type : 'word',
|
||||
value : word
|
||||
});
|
||||
}
|
||||
current--;
|
||||
}
|
||||
else if(char == "'"){
|
||||
char = input[++current]
|
||||
tokens.push({
|
||||
type : 'text',
|
||||
value : getToken(/[^\']/)
|
||||
});
|
||||
}
|
||||
else if(char == '"'){
|
||||
char = input[++current]
|
||||
tokens.push({
|
||||
type : 'text',
|
||||
value : getToken(/[^\"]/)
|
||||
});
|
||||
}
|
||||
}
|
||||
//Not tokenizing a tag definition
|
||||
else{
|
||||
//End tag
|
||||
if(char == '<' && input[current+1] == '/'){
|
||||
char = input[++current]
|
||||
char = input[++current]
|
||||
tokens.push({
|
||||
type : 'endTag',
|
||||
value : getToken(LETTERS)
|
||||
})
|
||||
}
|
||||
else if(char == '<'){
|
||||
inTag = true;
|
||||
char = input[++current];
|
||||
tokens.push({
|
||||
type : 'openTag',
|
||||
value : getToken(LETTERS)
|
||||
})
|
||||
current--;
|
||||
}
|
||||
else{
|
||||
//Handle slush text
|
||||
var value = '';
|
||||
while(char != '<' && current < input.length){
|
||||
value += char;
|
||||
char = input[++current];
|
||||
}
|
||||
value = value.trim()
|
||||
if(value){
|
||||
tokens.push({
|
||||
type : 'text',
|
||||
value : value
|
||||
});
|
||||
}
|
||||
current--;
|
||||
}
|
||||
}
|
||||
current++;
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
var parser = function(tokens){
|
||||
var nodes = [];
|
||||
var current = 0;
|
||||
var token = tokens[current];
|
||||
|
||||
var parseProps = function(){
|
||||
var props = {};
|
||||
var key = null;
|
||||
var last = null;
|
||||
|
||||
while(current < tokens.length && token.type != 'endTag' && token.type != 'closeTag'){
|
||||
if(last && token.type == 'word'){
|
||||
props[last] = true;
|
||||
last = token.value;
|
||||
}else if(!key && token.type == 'word'){
|
||||
last = token.value;
|
||||
}else if(last && token.type == 'equals'){
|
||||
key = last;
|
||||
last = null;
|
||||
}else if(key && (token.type == 'number' || token.type == 'text' || token.type == 'boolean')){
|
||||
props[key] = token.value;
|
||||
key = null;
|
||||
last = null;
|
||||
}else{
|
||||
throw "Invalid property value: " + key + '=' + token.value;
|
||||
}
|
||||
token = tokens[++current];
|
||||
}
|
||||
if(last) props[last] = true;
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
var genNode = function(tagType){
|
||||
token = tokens[++current];
|
||||
var node = {
|
||||
tag : tagType,
|
||||
props : parseProps(),
|
||||
children : getChildren(tagType)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
var getChildren = function(tagType){
|
||||
var children = [];
|
||||
while(current < tokens.length){
|
||||
if(token.type == 'endTag'){
|
||||
if(token.value && token.value != tagType){
|
||||
throw "Invalid closing tag: " + token.value + ". Expected closing tag of type: " + tagType
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(token.type == 'openTag'){
|
||||
children.push(genNode(token.value));
|
||||
}else if(token.type == 'text'){
|
||||
children.push(token.value);
|
||||
}
|
||||
token = tokens[++current];
|
||||
}
|
||||
return children;
|
||||
}
|
||||
return getChildren();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var test1 = `
|
||||
<div test="hey there champ" more_cool=false size=0>
|
||||
<span>
|
||||
Hey there!
|
||||
<a>so fucking cool </a>
|
||||
</span>
|
||||
let's go party
|
||||
<a href='neato' />
|
||||
</div>
|
||||
`
|
||||
|
||||
var test2 = "<div cool=0 same>Hey there!</div>"
|
||||
|
||||
|
||||
var tokens = tokenizer(test1);
|
||||
|
||||
console.log(test1, '\n---\n', tokens, '---\n', JSON.stringify(parser(tokens), null, ' '));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = function(input){
|
||||
return parser(tokenizer(input));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user