mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-23 14:23:21 +00:00
Compare commits
6 Commits
5a486a16fa
...
tpk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22a480871b | ||
|
|
daa3b096b3 | ||
|
|
bfcf6ca7f2 | ||
|
|
15ffb138eb | ||
|
|
7321cc81ec | ||
|
|
ba6ba0e51f |
21
client/tpk/navbar/navbar.jsx
Normal file
21
client/tpk/navbar/navbar.jsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
var React = require('react');
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
var Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
|
||||||
|
var Navbar = React.createClass({
|
||||||
|
render : function(){
|
||||||
|
return <Nav.base>
|
||||||
|
<Nav.section>
|
||||||
|
<Nav.logo />
|
||||||
|
<Nav.item href='/tpk' className='tpkLogo'>
|
||||||
|
<div>Total Player Knolling</div>
|
||||||
|
</Nav.item>
|
||||||
|
<Nav.item>v0.0.0</Nav.item>
|
||||||
|
</Nav.section>
|
||||||
|
{this.props.children}
|
||||||
|
</Nav.base>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Navbar;
|
||||||
16
client/tpk/navbar/navbar.less
Normal file
16
client/tpk/navbar/navbar.less
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
.tpk nav{
|
||||||
|
.tpkLogo{
|
||||||
|
.animate(color);
|
||||||
|
font-family : CodeBold;
|
||||||
|
font-size : 12px;
|
||||||
|
color : white;
|
||||||
|
div{
|
||||||
|
margin-top : 2px;
|
||||||
|
margin-bottom : -2px;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
color : @teal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
client/tpk/sheetEditor/sheetEditor.jsx
Normal file
49
client/tpk/sheetEditor/sheetEditor.jsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
var React = require('react');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var cx = require('classnames');
|
||||||
|
|
||||||
|
var CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
||||||
|
|
||||||
|
var SheetEditor = React.createClass({
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
value : "",
|
||||||
|
onChange : function(){}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
cursorPosition : {
|
||||||
|
line : 0,
|
||||||
|
ch : 0
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
var paneHeight = this.refs.main.parentNode.clientHeight;
|
||||||
|
this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleTextChange : function(text){
|
||||||
|
this.props.onChange(text);
|
||||||
|
},
|
||||||
|
handleCursorActivty : function(curpos){
|
||||||
|
this.cursorPosition = curpos;
|
||||||
|
},
|
||||||
|
|
||||||
|
//Called when there are changes to the editor's dimensions
|
||||||
|
update : function(){
|
||||||
|
this.refs.codeEditor.updateSize();
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function(){
|
||||||
|
return <div className='sheetEditor' ref='main'>
|
||||||
|
<CodeEditor
|
||||||
|
ref='codeEditor'
|
||||||
|
wrap={true}
|
||||||
|
language='jsx'
|
||||||
|
value={this.props.value}
|
||||||
|
onChange={this.handleTextChange}
|
||||||
|
onCursorActivity={this.handleCursorActivty} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = SheetEditor;
|
||||||
3
client/tpk/sheetEditor/sheetEditor.less
Normal file
3
client/tpk/sheetEditor/sheetEditor.less
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.COM{
|
||||||
|
|
||||||
|
}
|
||||||
54
client/tpk/sheetRenderer/parts/box/box.jsx
Normal file
54
client/tpk/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/tpk/sheetRenderer/parts/box/box.less
Normal file
30
client/tpk/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/tpk/sheetRenderer/parts/index.js
Normal file
13
client/tpk/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')
|
||||||
|
}
|
||||||
25
client/tpk/sheetRenderer/parts/playerInfo/playerInfo.jsx
Normal file
25
client/tpk/sheetRenderer/parts/playerInfo/playerInfo.jsx
Normal file
@@ -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/tpk/sheetRenderer/parts/skill/skill.jsx
Normal file
62
client/tpk/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/tpk/sheetRenderer/parts/skill/skill.less
Normal file
35
client/tpk/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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
client/tpk/sheetRenderer/parts/skillList/skillList.jsx
Normal file
61
client/tpk/sheetRenderer/parts/skillList/skillList.jsx
Normal file
@@ -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;
|
||||||
3
client/tpk/sheetRenderer/parts/skillList/skillList.less
Normal file
3
client/tpk/sheetRenderer/parts/skillList/skillList.less
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.COM{
|
||||||
|
|
||||||
|
}
|
||||||
44
client/tpk/sheetRenderer/parts/textInput/textInput.jsx
Normal file
44
client/tpk/sheetRenderer/parts/textInput/textInput.jsx
Normal file
@@ -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;
|
||||||
6
client/tpk/sheetRenderer/parts/textInput/textInput.less
Normal file
6
client/tpk/sheetRenderer/parts/textInput/textInput.less
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.textInput{
|
||||||
|
label{
|
||||||
|
display: inline-block;
|
||||||
|
width : 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
client/tpk/sheetRenderer/parts/utils.js
Normal file
33
client/tpk/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/tpk/sheetRenderer/sheetRenderer.jsx
Normal file
79
client/tpk/sheetRenderer/sheetRenderer.jsx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
var React = require('react');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var cx = require('classnames');
|
||||||
|
|
||||||
|
var jsx2json = require('naturalcrit/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/tpk/sheetRenderer/sheetRenderer.less
Normal file
11
client/tpk/sheetRenderer/sheetRenderer.less
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.sheetRenderer{
|
||||||
|
|
||||||
|
padding-right : 10px;
|
||||||
|
|
||||||
|
|
||||||
|
.sheetContainer{
|
||||||
|
background-color: white;
|
||||||
|
padding : 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
78
client/tpk/tpk.jsx
Normal file
78
client/tpk/tpk.jsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
var React = require('react');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var cx = require('classnames');
|
||||||
|
|
||||||
|
var Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
var Navbar = require('./navbar/navbar.jsx');
|
||||||
|
|
||||||
|
var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
|
||||||
|
var SheetEditor = require('./sheetEditor/sheetEditor.jsx');
|
||||||
|
var SheetRenderer = require('./sheetRenderer/sheetRenderer.jsx');
|
||||||
|
|
||||||
|
|
||||||
|
const SPLATSHEET_TEMPLATE = 'splatsheet_template';
|
||||||
|
const SPLATSHEET_DATA = 'splatsheet_data';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var TPK = React.createClass({
|
||||||
|
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
sheetCode: "<Box>\n\t<TextInput label='test' />\n</Box>",
|
||||||
|
|
||||||
|
sheetData : {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
//remove later
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.setState({
|
||||||
|
sheetCode : localStorage.getItem(SPLATSHEET_TEMPLATE) || this.state.sheetCode,
|
||||||
|
sheetData : JSON.parse(localStorage.getItem(SPLATSHEET_DATA)) || this.state.sheetData
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSplitMove : function(){
|
||||||
|
this.refs.editor.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCodeChange : function(code){
|
||||||
|
this.setState({
|
||||||
|
sheetCode : code
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem(SPLATSHEET_TEMPLATE, code);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDataChange : function(data){
|
||||||
|
this.setState({
|
||||||
|
sheetData : JSON.parse(JSON.stringify(data)),
|
||||||
|
});
|
||||||
|
localStorage.setItem(SPLATSHEET_DATA, JSON.stringify(data));
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function(){
|
||||||
|
return <div className='tpk page'>
|
||||||
|
<Navbar>
|
||||||
|
<Nav.section>
|
||||||
|
<Nav.item>
|
||||||
|
yo dawg
|
||||||
|
</Nav.item>
|
||||||
|
</Nav.section>
|
||||||
|
</Navbar>
|
||||||
|
<div className='content'>
|
||||||
|
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
|
||||||
|
<SheetEditor value={this.state.sheetCode} onChange={this.handleCodeChange} ref='editor' />
|
||||||
|
<SheetRenderer
|
||||||
|
code={this.state.sheetCode}
|
||||||
|
characterData={this.state.sheetData}
|
||||||
|
onChange={this.handleDataChange} />
|
||||||
|
</SplitPane>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = TPK;
|
||||||
19
client/tpk/tpk.less
Normal file
19
client/tpk/tpk.less
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
@import 'naturalcrit/styles/core.less';
|
||||||
|
.tpk{
|
||||||
|
height : 100%;
|
||||||
|
background-color : @steel;
|
||||||
|
.page{
|
||||||
|
display : flex;
|
||||||
|
height : 100%;
|
||||||
|
flex-direction : column;
|
||||||
|
.content{
|
||||||
|
position : relative;
|
||||||
|
//height : calc(~"100% - 29px"); //Navbar height
|
||||||
|
|
||||||
|
height : 100%;
|
||||||
|
|
||||||
|
flex : auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ var gulp = vitreumTasks(gulp, {
|
|||||||
entryPoints: [
|
entryPoints: [
|
||||||
'./client/main',
|
'./client/main',
|
||||||
'./client/homebrew',
|
'./client/homebrew',
|
||||||
|
'./client/tpk',
|
||||||
'./client/admin'
|
'./client/admin'
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ var gulp = vitreumTasks(gulp, {
|
|||||||
"codemirror",
|
"codemirror",
|
||||||
"codemirror/mode/gfm/gfm.js",
|
"codemirror/mode/gfm/gfm.js",
|
||||||
'codemirror/mode/javascript/javascript.js',
|
'codemirror/mode/javascript/javascript.js',
|
||||||
|
'codemirror/mode/jsx/jsx.js',
|
||||||
|
|
||||||
"moment",
|
"moment",
|
||||||
"superagent",
|
"superagent",
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ app.get('/admin', function(req, res){
|
|||||||
app = require('./server/homebrew.api.js')(app);
|
app = require('./server/homebrew.api.js')(app);
|
||||||
app = require('./server/homebrew.server.js')(app);
|
app = require('./server/homebrew.server.js')(app);
|
||||||
|
|
||||||
|
//Populate TPK routes
|
||||||
|
app = require('./server/tpk.server.js')(app);
|
||||||
|
|
||||||
|
|
||||||
app.get('*', function (req, res) {
|
app.get('*', function (req, res) {
|
||||||
|
|||||||
22
server/tpk.server.js
Normal file
22
server/tpk.server.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
var vitreumRender = require('vitreum/render');
|
||||||
|
|
||||||
|
module.exports = function(app){
|
||||||
|
|
||||||
|
//Edit Page
|
||||||
|
app.get('/tpk*', function(req, res){
|
||||||
|
vitreumRender({
|
||||||
|
page: './build/tpk/bundle.dot',
|
||||||
|
globals:{},
|
||||||
|
prerenderWith : './client/tpk/tpk.jsx',
|
||||||
|
initialProps: {
|
||||||
|
url: req.originalUrl,
|
||||||
|
},
|
||||||
|
clearRequireCache : !process.env.PRODUCTION,
|
||||||
|
}, function (err, page) {
|
||||||
|
return res.send(page)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
};
|
||||||
@@ -10,6 +10,7 @@ if(typeof navigator !== 'undefined'){
|
|||||||
//Language Modes
|
//Language Modes
|
||||||
require('codemirror/mode/gfm/gfm.js'); //Github flavoured markdown
|
require('codemirror/mode/gfm/gfm.js'); //Github flavoured markdown
|
||||||
require('codemirror/mode/javascript/javascript.js');
|
require('codemirror/mode/javascript/javascript.js');
|
||||||
|
require('codemirror/mode/jsx/jsx.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ var CodeEditor = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps: function(nextProps){
|
componentWillReceiveProps: function(nextProps){
|
||||||
if(this.codeMirror && nextProps.value !== undefined && this.codeMirror.getValue() != nextProps.value) {
|
if(this.codeMirror && nextProps.value && this.codeMirror.getValue() != nextProps.value) {
|
||||||
this.codeMirror.setValue(nextProps.value);
|
this.codeMirror.setValue(nextProps.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
228
shared/naturalcrit/jsx-parser.js
Normal file
228
shared/naturalcrit/jsx-parser.js
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(input){
|
||||||
|
return parser(tokenizer(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
SOME TEST, remove later
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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, ' '));
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user