mirror of
https://github.com/stolksdorf/homebrewery.git
synced 2025-12-13 05:25:58 +00:00
Sidebar is nearing completion
This commit is contained in:
106
client/naturalCrit/encounter/encounter.jsx
Normal file
106
client/naturalCrit/encounter/encounter.jsx
Normal file
@@ -0,0 +1,106 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var MonsterCard = require('./monsterCard/monsterCard.jsx');
|
||||
|
||||
var attrMod = function(attr){
|
||||
return Math.floor(attr/2) - 5;
|
||||
}
|
||||
|
||||
var Encounter = React.createClass({
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
name : '',
|
||||
desc : '',
|
||||
reward : '',
|
||||
enemies : [],
|
||||
index : {},
|
||||
|
||||
|
||||
monsterManual : {}
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
enemies: this.createEnemies(this.props)
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
this.setState({
|
||||
enemies : this.createEnemies(nextProps)
|
||||
})
|
||||
},
|
||||
|
||||
createEnemies : function(props){
|
||||
var self = this;
|
||||
return _.indexBy(_.map(props.enemies, function(type, index){
|
||||
return self.createEnemy(props, type, index)
|
||||
}), 'id')
|
||||
},
|
||||
|
||||
createEnemy : function(props, type, index){
|
||||
var stats = props.index[type] || props.monsterManual[type];
|
||||
return _.extend({
|
||||
id : type + index,
|
||||
name : type,
|
||||
currentHP : stats.hp,
|
||||
initiative : _.random(1,20) + attrMod(stats.attr.dex)
|
||||
}, stats);
|
||||
},
|
||||
|
||||
|
||||
updateHP : function(enemyId, newHP){
|
||||
this.state.enemies[enemyId].currentHP = newHP;
|
||||
this.setState({
|
||||
enemies : this.state.enemies
|
||||
});
|
||||
},
|
||||
removeEnemy : function(enemyId){
|
||||
delete this.state.enemies[enemyId];
|
||||
this.setState({
|
||||
enemies : this.state.enemies
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
renderEnemies : function(){
|
||||
var self = this;
|
||||
|
||||
var sortedEnemies = _.sortBy(this.state.enemies, function(e){
|
||||
return -e.initiative;
|
||||
});
|
||||
|
||||
return _.map(sortedEnemies, function(enemy){
|
||||
return <MonsterCard
|
||||
{...enemy}
|
||||
key={enemy.id}
|
||||
updateHP={self.updateHP.bind(self, enemy.id)}
|
||||
remove={self.removeEnemy.bind(self, enemy.id)} />
|
||||
})
|
||||
},
|
||||
|
||||
render : function(){
|
||||
var self = this;
|
||||
|
||||
|
||||
return(
|
||||
<div className='encounter'>
|
||||
|
||||
<div className='info'>
|
||||
{this.props.name}
|
||||
</div>
|
||||
|
||||
|
||||
<div className='cardContainer'>
|
||||
{this.renderEnemies()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Encounter;
|
||||
3
client/naturalCrit/encounter/encounter.less
Normal file
3
client/naturalCrit/encounter/encounter.less
Normal file
@@ -0,0 +1,3 @@
|
||||
.encounter{
|
||||
|
||||
}
|
||||
@@ -68,7 +68,7 @@ var AttackSlot = React.createClass({
|
||||
renderNotes : function(){
|
||||
var notes = _.omit(this.props, ['name', 'atk', 'dmg', 'uses', 'heal']);
|
||||
return _.map(notes, function(text, key){
|
||||
return <div>{key + ': ' + text}</div>
|
||||
return <div key={key}>{key + ': ' + text}</div>
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2,16 +2,50 @@ var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var MonsterCard = require('./monsterCard/monsterCard.jsx');
|
||||
|
||||
var Sidebar = require('./sidebar/sidebar.jsx');
|
||||
|
||||
var Encounter = require('./encounter/encounter.jsx');
|
||||
|
||||
|
||||
var encounter = {
|
||||
var encounters = [
|
||||
{
|
||||
name : 'The Big Bad',
|
||||
desc : 'The big fight!',
|
||||
reward : 'gems',
|
||||
enemies : ['goblin', 'goblin'],
|
||||
reserve : ['goblin'],
|
||||
},
|
||||
{
|
||||
name : 'Demon Goats',
|
||||
desc : 'Gross fight',
|
||||
reward : 'curved horn, goat sac',
|
||||
enemies : ['demon_goat', 'demon_goat', 'demon_goat'],
|
||||
index : {
|
||||
demon_goat : {
|
||||
"hp" : 140,
|
||||
"ac" : 16,
|
||||
"attr" : {
|
||||
"str" : 8,
|
||||
"con" : 8,
|
||||
"dex" : 8,
|
||||
"int" : 8,
|
||||
"wis" : 8,
|
||||
"cha" : 8
|
||||
},
|
||||
"attacks" : {
|
||||
"charge" : {
|
||||
"atk" : "1d20+5",
|
||||
"dmg" : "1d8+5",
|
||||
"type" : "bludge"
|
||||
}
|
||||
},
|
||||
"abilities" : ["charge"],
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
name : 'The Big Bad',
|
||||
enemies : ['goblin', 'goblin'],
|
||||
reserve : ['goblin'],
|
||||
|
||||
}
|
||||
];
|
||||
|
||||
var MonsterManual = {
|
||||
'goblin' : {
|
||||
@@ -65,9 +99,12 @@ var NaturalCrit = React.createClass({
|
||||
var self = this;
|
||||
|
||||
return {
|
||||
enemies: _.indexBy(_.map(encounter.enemies, function(type, index){
|
||||
return self.createEnemy(type, index)
|
||||
}), 'id')
|
||||
|
||||
selectedEncounterIndex : 0,
|
||||
|
||||
encounters : encounters,
|
||||
monsterManual : MonsterManual,
|
||||
|
||||
};
|
||||
},
|
||||
|
||||
@@ -103,53 +140,62 @@ var NaturalCrit = React.createClass({
|
||||
},
|
||||
|
||||
|
||||
updateHP : function(enemyId, newHP){
|
||||
this.state.enemies[enemyId].currentHP = newHP;
|
||||
|
||||
handleJSONChange : function(encounterIndex, json){
|
||||
|
||||
this.state.encounters[encounterIndex] = json;
|
||||
this.setState({
|
||||
enemies : this.state.enemies
|
||||
});
|
||||
encounters : this.state.encounters
|
||||
})
|
||||
|
||||
},
|
||||
removeEnemy : function(enemyId){
|
||||
delete this.state.enemies[enemyId];
|
||||
|
||||
handleEncounterChange : function(encounterIndex){
|
||||
this.setState({
|
||||
enemies : this.state.enemies
|
||||
selectedEncounterIndex : encounterIndex
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
renderSelectedEncounter : function(){
|
||||
var self = this;
|
||||
var selectedEncounter = _.find(this.state.encounters, function(encounter){
|
||||
return encounter.name == self.state.selectedEncounter;
|
||||
});
|
||||
|
||||
if(this.state.selectedEncounterIndex != null){
|
||||
var selectedEncounter = this.state.encounters[this.state.selectedEncounterIndex]
|
||||
return <Encounter
|
||||
key={selectedEncounter.name}
|
||||
{...selectedEncounter}
|
||||
monsterManual={this.state.monsterManual}
|
||||
/>
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
|
||||
render : function(){
|
||||
var self = this;
|
||||
|
||||
console.log();
|
||||
|
||||
var sortedEnemies = _.sortBy(this.state.enemies, function(e){
|
||||
return -e.initiative;
|
||||
});
|
||||
|
||||
|
||||
var cards = _.map(sortedEnemies, function(enemy){
|
||||
return <MonsterCard
|
||||
{...enemy}
|
||||
key={enemy.id}
|
||||
updateHP={self.updateHP.bind(self, enemy.id)}
|
||||
remove={self.removeEnemy.bind(self, enemy.id)} />
|
||||
})
|
||||
|
||||
|
||||
console.log(this.state.encounters);
|
||||
|
||||
return(
|
||||
<div className='naturalCrit'>
|
||||
<button className='rollInitiative' onClick={this.addRandomPC}> rollInitiative</button>
|
||||
Project Ready!
|
||||
<Sidebar
|
||||
selectedEncounter={this.state.selectedEncounterIndex}
|
||||
encounters={this.state.encounters}
|
||||
monsterManual={this.state.monsterManual}
|
||||
|
||||
onSelectEncounter={this.handleEncounterChange}
|
||||
onJSONChange={this.handleJSONChange}
|
||||
/>
|
||||
|
||||
{cards}
|
||||
<div className='encounterContainer'>
|
||||
{this.renderSelectedEncounter()}
|
||||
</div>
|
||||
|
||||
<pre>
|
||||
{JSON.stringify(MonsterManual, null, ' ')}</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,4 +16,9 @@ body{
|
||||
.naturalCrit{
|
||||
color : #333;
|
||||
background-color: #eee;
|
||||
|
||||
.encounterContainer{
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
BIN
client/naturalCrit/sidebar/CODE Bold.otf
Normal file
BIN
client/naturalCrit/sidebar/CODE Bold.otf
Normal file
Binary file not shown.
BIN
client/naturalCrit/sidebar/CODE Light.otf
Normal file
BIN
client/naturalCrit/sidebar/CODE Light.otf
Normal file
Binary file not shown.
108
client/naturalCrit/sidebar/sidebar.jsx
Normal file
108
client/naturalCrit/sidebar/sidebar.jsx
Normal file
@@ -0,0 +1,108 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
var JSONFileEditor = require('naturalCrit/jsonFileEditor/jsonFileEditor.jsx');
|
||||
|
||||
var Sidebar = React.createClass({
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
selectedEncounter : null,
|
||||
|
||||
monsterManual : {},
|
||||
encounters : [],
|
||||
|
||||
onSelectEncounter : function(){},
|
||||
|
||||
onJSONChange : function(encounterIndex, json){},
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
hide : false
|
||||
};
|
||||
},
|
||||
|
||||
handleLogoClick : function(){
|
||||
this.setState({
|
||||
hide : !this.state.hide
|
||||
})
|
||||
},
|
||||
|
||||
handleJSONChange : function(encounterIndex, json){
|
||||
|
||||
|
||||
this.props.onJSONChange(encounterIndex, json);
|
||||
|
||||
|
||||
},
|
||||
|
||||
handleSelectEncounter : function(encounterIndex){
|
||||
console.log(encounterIndex);
|
||||
this.props.onSelectEncounter(encounterIndex);
|
||||
},
|
||||
|
||||
renderEncounters : function(){
|
||||
var self = this;
|
||||
|
||||
return _.map(this.props.encounters, function(encounter, index){
|
||||
console.log(self.props.selectedEncounter, index);
|
||||
|
||||
var isSelected = self.props.selectedEncounter == index;
|
||||
return <div className={cx('encounter' , {'selected' : isSelected})} key={index}>
|
||||
|
||||
<i onClick={self.handleSelectEncounter.bind(self, index)} className={cx('fa', {
|
||||
'fa-square-o' : !isSelected,
|
||||
'fa-check-square-o' : isSelected,
|
||||
})} />
|
||||
|
||||
|
||||
<JSONFileEditor
|
||||
name={encounter.name}
|
||||
json={encounter}
|
||||
onJSONChange={self.handleJSONChange.bind(self, index)}
|
||||
/>
|
||||
</div>
|
||||
})
|
||||
},
|
||||
|
||||
render : function(){
|
||||
var self = this;
|
||||
return(
|
||||
<div className={cx('sidebar', {'hide' : this.state.hide})}>
|
||||
<div className='logo'>
|
||||
<svg onClick={this.handleLogoClick} version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100"><path d="M80.644,87.982l16.592-41.483c0.054-0.128,0.088-0.26,0.108-0.394c0.006-0.039,0.007-0.077,0.011-0.116 c0.007-0.087,0.008-0.174,0.002-0.26c-0.003-0.046-0.007-0.091-0.014-0.137c-0.014-0.089-0.036-0.176-0.063-0.262 c-0.012-0.034-0.019-0.069-0.031-0.103c-0.047-0.118-0.106-0.229-0.178-0.335c-0.004-0.006-0.006-0.012-0.01-0.018L67.999,3.358 c-0.01-0.013-0.003-0.026-0.013-0.04L68,3.315V4c0,0-0.033,0-0.037,0c-0.403-1-1.094-1.124-1.752-0.976 c0,0.004-0.004-0.012-0.007-0.012C66.201,3.016,66.194,3,66.194,3H66.19h-0.003h-0.003h-0.004h-0.003c0,0-0.004,0-0.007,0 s-0.003-0.151-0.007-0.151L20.495,15.227c-0.025,0.007-0.046-0.019-0.071-0.011c-0.087,0.028-0.172,0.041-0.253,0.083 c-0.054,0.027-0.102,0.053-0.152,0.085c-0.051,0.033-0.101,0.061-0.147,0.099c-0.044,0.036-0.084,0.073-0.124,0.113 c-0.048,0.048-0.093,0.098-0.136,0.152c-0.03,0.039-0.059,0.076-0.085,0.117c-0.046,0.07-0.084,0.145-0.12,0.223 c-0.011,0.023-0.027,0.042-0.036,0.066L2.911,57.664C2.891,57.715,3,57.768,3,57.82v0.002c0,0.186,0,0.375,0,0.562 c0,0.004,0,0.004,0,0.008c0,0,0,0,0,0.002c0,0,0,0,0,0.004v0.004v0.002c0,0.074-0.002,0.15,0.012,0.223 C3.015,58.631,3,58.631,3,58.633c0,0.004,0,0.004,0,0.008c0,0,0,0,0,0.002c0,0,0,0,0,0.004v0.004c0,0,0,0,0,0.002v0.004 c0,0.191-0.046,0.377,0.06,0.545c0-0.002-0.03,0.004-0.03,0.004c0,0.004-0.03,0.004-0.03,0.004c0,0.002,0,0.002,0,0.002 l-0.045,0.004c0.03,0.047,0.036,0.09,0.068,0.133l29.049,37.359c0.002,0.004,0,0.006,0.002,0.01c0.002,0.002,0,0.004,0.002,0.008 c0.006,0.008,0.014,0.014,0.021,0.021c0.024,0.029,0.052,0.051,0.078,0.078c0.027,0.029,0.053,0.057,0.082,0.082 c0.03,0.027,0.055,0.062,0.086,0.088c0.026,0.02,0.057,0.033,0.084,0.053c0.04,0.027,0.081,0.053,0.123,0.076 c0.005,0.004,0.01,0.008,0.016,0.01c0.087,0.051,0.176,0.09,0.269,0.123c0.042,0.014,0.082,0.031,0.125,0.043 c0.021,0.006,0.041,0.018,0.062,0.021c0.123,0.027,0.249,0.043,0.375,0.043c0.099,0,0.202-0.012,0.304-0.027l45.669-8.303 c0.057-0.01,0.108-0.021,0.163-0.037C79.547,88.992,79.562,89,79.575,89c0.004,0,0.004,0,0.004,0c0.021,0,0.039-0.027,0.06-0.035 c0.041-0.014,0.08-0.034,0.12-0.052c0.021-0.01,0.044-0.019,0.064-0.03c0.017-0.01,0.026-0.015,0.033-0.017 c0.014-0.008,0.023-0.021,0.037-0.028c0.14-0.078,0.269-0.174,0.38-0.285c0.014-0.016,0.024-0.034,0.038-0.048 c0.109-0.119,0.201-0.252,0.271-0.398c0.006-0.01,0.016-0.018,0.021-0.029c0.004-0.008,0.008-0.017,0.011-0.026 c0.002-0.004,0.003-0.006,0.005-0.01C80.627,88.021,80.635,88.002,80.644,87.982z M77.611,84.461L48.805,66.453l32.407-25.202 L77.611,84.461z M46.817,63.709L35.863,23.542l43.818,14.608L46.817,63.709z M84.668,40.542l8.926,5.952l-11.902,29.75 L84.668,40.542z M89.128,39.446L84.53,36.38l-6.129-12.257L89.128,39.446z M79.876,34.645L37.807,20.622L65.854,6.599L79.876,34.645 z M33.268,19.107l-6.485-2.162l23.781-6.487L33.268,19.107z M21.92,18.895l8.67,2.891L10.357,47.798L21.92,18.895z M32.652,24.649 l10.845,39.757L7.351,57.178L32.652,24.649z M43.472,67.857L32.969,92.363L8.462,60.855L43.472,67.857z M46.631,69.09l27.826,17.393 l-38.263,6.959L46.631,69.09z"></path></svg>
|
||||
<span className='name'>
|
||||
Natural<span className='crit'>Crit</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className='contents'>
|
||||
|
||||
<div className='monsterManualContainer'>
|
||||
<i className='fa fa-book' />
|
||||
<JSONFileEditor name="Monster Manual" />
|
||||
</div>
|
||||
<div className='encounterContainer'>
|
||||
<h3> <i className='fa fa-flag' /> encounters </h3>
|
||||
{this.renderEncounters()}
|
||||
</div>
|
||||
<div className='encounterStats'>
|
||||
|
||||
</div>
|
||||
<div className='addPC'>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Sidebar;
|
||||
69
client/naturalCrit/sidebar/sidebar.less
Normal file
69
client/naturalCrit/sidebar/sidebar.less
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
@font-face {
|
||||
font-family : CodeLight;
|
||||
src : url('/assets/naturalCrit/sidebar/CODE Light.otf');
|
||||
}
|
||||
@font-face {
|
||||
font-family : CodeBold;
|
||||
src : url('/assets/naturalCrit/sidebar/CODE Bold.otf');
|
||||
}
|
||||
.sidebar{
|
||||
.animateAll();
|
||||
display : inline-block;
|
||||
vertical-align : top;
|
||||
box-sizing : border-box;
|
||||
height : 100%;
|
||||
width : 300px;
|
||||
|
||||
&.hide{
|
||||
height : 50px;
|
||||
width : 50px;
|
||||
.logo .name{
|
||||
left : -200px;
|
||||
}
|
||||
.contents{
|
||||
opacity : 0;
|
||||
}
|
||||
}
|
||||
.logo{
|
||||
padding : 10px 10px;
|
||||
background-color : @steel;
|
||||
font-family : 'CodeLight', sans-serif;
|
||||
font-size : 1.8em;
|
||||
color : white;
|
||||
svg{
|
||||
vertical-align : middle;
|
||||
height : 1em;
|
||||
margin-right : 0.2em;
|
||||
cursor : pointer;
|
||||
fill : white;
|
||||
}
|
||||
span.name{
|
||||
.animateAll();
|
||||
position : absolute;
|
||||
top : 13px;
|
||||
left : 50px;
|
||||
span.crit{
|
||||
font-family : 'CodeBold';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contents{
|
||||
.animate(opacity);
|
||||
width : 100%;
|
||||
&>*{
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
.encounterContainer{
|
||||
.encounter{
|
||||
&.selected{
|
||||
background-color : @green;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ var gulp = vitreumTasks(gulp, {
|
||||
|
||||
projectModules: ["./shared/naturalCrit"],
|
||||
additionalRequirePaths : ['./shared'],
|
||||
assetExts: ["*.svg", "*.png", "*.jpg", "*.pdf", "*.eot", "*.ttf", "*.woff", "*.woff2", "*.ico"],
|
||||
assetExts: ["*.svg", "*.png", "*.jpg", "*.pdf", "*.eot", "*.otf", "*.woff", "*.woff2", "*.ico"],
|
||||
|
||||
serverWatchPaths: ["server"],
|
||||
serverScript: "server.js",
|
||||
@@ -22,7 +22,7 @@ var gulp = vitreumTasks(gulp, {
|
||||
"react-dom",
|
||||
"lodash",
|
||||
"classnames",
|
||||
|
||||
"jsoneditor"
|
||||
],
|
||||
clientLibs: [],
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"classnames": "^2.2.0",
|
||||
"express": "^4.13.3",
|
||||
"gulp": "^3.9.0",
|
||||
"jsoneditor": "^4.2.1",
|
||||
"lodash": "^3.10.1",
|
||||
"react": "^0.14.2",
|
||||
"react-dom": "^0.14.2",
|
||||
|
||||
BIN
shared/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png
Normal file
BIN
shared/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
103
shared/naturalCrit/jsonFileEditor/jsonFileEditor.jsx
Normal file
103
shared/naturalCrit/jsonFileEditor/jsonFileEditor.jsx
Normal file
@@ -0,0 +1,103 @@
|
||||
var React = require('react');
|
||||
var _ = require('lodash');
|
||||
var cx = require('classnames');
|
||||
|
||||
|
||||
var JSONEditor = require('jsoneditor');
|
||||
|
||||
//var editor = new JSONEditor(container);
|
||||
|
||||
var json = {
|
||||
test : 6,
|
||||
arr : [true, 1,2,3,4],
|
||||
yo : {
|
||||
yeah : true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var JsonFileEditor = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
name : "yo",
|
||||
|
||||
json : json,
|
||||
|
||||
onJSONChange : function(){}
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
showEditor: false
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
//this.editor.set(nextProps.json);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.editor = new JSONEditor(this.refs.editor, {
|
||||
change : this.handleJSONChange,
|
||||
search : false
|
||||
}, this.props.json)
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
handleJSONChange : function(){
|
||||
|
||||
this.props.onJSONChange(this.editor.get());
|
||||
|
||||
//try to store in local storage?
|
||||
|
||||
},
|
||||
|
||||
handleShowEditorClick : function(){
|
||||
this.setState({
|
||||
showEditor : !this.state.showEditor
|
||||
})
|
||||
},
|
||||
|
||||
handleDownload : function(){
|
||||
|
||||
},
|
||||
handleRemove : function(){
|
||||
|
||||
},
|
||||
|
||||
|
||||
renderEditor : function(){
|
||||
return <div className='jsonEditor' ref='editor' />
|
||||
},
|
||||
|
||||
|
||||
render : function(){
|
||||
var self = this;
|
||||
return(
|
||||
<div className={cx('jsonFileEditor', {'showEditor' : this.state.showEditor})}>
|
||||
|
||||
<span className='name'>{this.props.name}</span>
|
||||
|
||||
|
||||
<div className='controls'>
|
||||
|
||||
|
||||
<button className='showEditor' onClick={this.handleShowEditorClick}><i className='fa fa-edit' /></button>
|
||||
<button className='downloadJSON' onClick={this.handleDownload}><i className='fa fa-download' /></button>
|
||||
<div className='remove' onClick={this.handleRemove}><i className='fa fa-times' /></div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{this.renderEditor()}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = JsonFileEditor;
|
||||
30
shared/naturalCrit/jsonFileEditor/jsonFileEditor.less
Normal file
30
shared/naturalCrit/jsonFileEditor/jsonFileEditor.less
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
@import (less) "./jsoneditor.css";
|
||||
.jsonFileEditor{
|
||||
position : relative;
|
||||
width : 100%;
|
||||
&.showEditor{
|
||||
.jsonEditor{
|
||||
display : initial;
|
||||
}
|
||||
}
|
||||
|
||||
.jsonEditor{
|
||||
position : absolute;
|
||||
display : none;
|
||||
top : 100%;
|
||||
left : 0px;
|
||||
z-index : 1000;
|
||||
background-color : white;
|
||||
}
|
||||
.name{
|
||||
display : inline-block;
|
||||
font-size : 0.8em;
|
||||
font-weight : 800;
|
||||
}
|
||||
.controls{
|
||||
position : absolute;
|
||||
top : 0px;
|
||||
right : 0px;
|
||||
}
|
||||
}
|
||||
625
shared/naturalCrit/jsonFileEditor/jsoneditor.css
Normal file
625
shared/naturalCrit/jsonFileEditor/jsoneditor.css
Normal file
@@ -0,0 +1,625 @@
|
||||
.jsoneditor .field,
|
||||
.jsoneditor .value,
|
||||
.jsoneditor .readonly {
|
||||
border: 1px solid transparent;
|
||||
min-height: 16px;
|
||||
min-width: 32px;
|
||||
padding: 2px;
|
||||
margin: 1px;
|
||||
word-wrap: break-word;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* adjust margin of p elements inside editable divs, needed for Opera, IE */
|
||||
|
||||
.jsoneditor .field p,
|
||||
.jsoneditor .value p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.jsoneditor .value {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.jsoneditor .readonly {
|
||||
min-width: 16px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.jsoneditor .empty {
|
||||
border-color: lightgray;
|
||||
border-style: dashed;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.jsoneditor .field.empty {
|
||||
background-image: url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png");
|
||||
background-position: 0 -144px;
|
||||
}
|
||||
|
||||
.jsoneditor .value.empty {
|
||||
background-image: url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png");
|
||||
background-position: -48px -144px;
|
||||
}
|
||||
|
||||
.jsoneditor .value.url {
|
||||
color: green;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.jsoneditor a.value.url:hover,
|
||||
.jsoneditor a.value.url:focus {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.jsoneditor .separator {
|
||||
padding: 3px 0;
|
||||
vertical-align: top;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.jsoneditor .field[contenteditable=true]:focus,
|
||||
.jsoneditor .field[contenteditable=true]:hover,
|
||||
.jsoneditor .value[contenteditable=true]:focus,
|
||||
.jsoneditor .value[contenteditable=true]:hover,
|
||||
.jsoneditor .field.highlight,
|
||||
.jsoneditor .value.highlight {
|
||||
background-color: #FFFFAB;
|
||||
border: 1px solid yellow;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.jsoneditor .field.highlight-active,
|
||||
.jsoneditor .field.highlight-active:focus,
|
||||
.jsoneditor .field.highlight-active:hover,
|
||||
.jsoneditor .value.highlight-active,
|
||||
.jsoneditor .value.highlight-active:focus,
|
||||
.jsoneditor .value.highlight-active:hover {
|
||||
background-color: #ffee00;
|
||||
border: 1px solid #ffc700;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: transparent url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png");
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.collapsed {
|
||||
background-position: 0 -48px;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.expanded {
|
||||
background-position: 0 -72px;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.contextmenu {
|
||||
background-position: -48px -72px;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.contextmenu:hover,
|
||||
.jsoneditor div.tree button.contextmenu:focus,
|
||||
.jsoneditor div.tree button.contextmenu.selected {
|
||||
background-position: -48px -48px;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree *:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button:focus {
|
||||
/* TODO: nice outline for buttons with focus
|
||||
outline: #97B0F8 solid 2px;
|
||||
box-shadow: 0 0 8px #97B0F8;
|
||||
*/
|
||||
background-color: #f5f5f5;
|
||||
outline: #e5e5e5 solid 1px;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.invisible {
|
||||
visibility: hidden;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.jsoneditor {
|
||||
color: #1A1A1A;
|
||||
border: 1px solid #97B0F8;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree table.tree {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.jsoneditor div.outer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: -35px 0 0 0;
|
||||
padding: 35px 0 0 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.jsoneditor textarea.text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
background-color: white;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.jsoneditor tr.highlight {
|
||||
background-color: #FFFFAB;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.dragarea {
|
||||
background: url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png") -72px -72px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.jsoneditor div.tree button.dragarea:hover,
|
||||
.jsoneditor div.tree button.dragarea:focus {
|
||||
background-position: -72px -48px;
|
||||
}
|
||||
|
||||
.jsoneditor tr,
|
||||
.jsoneditor th,
|
||||
.jsoneditor td {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.jsoneditor td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.jsoneditor td.tree {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.jsoneditor .field,
|
||||
.jsoneditor .value,
|
||||
.jsoneditor td,
|
||||
.jsoneditor th,
|
||||
.jsoneditor textarea {
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
/* ContextMenu - main menu */
|
||||
|
||||
.jsoneditor-contextmenu {
|
||||
position: absolute;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 124px;
|
||||
background: white;
|
||||
border: 1px solid #d3d3d3;
|
||||
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li button {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 124px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #4d4d4d;
|
||||
background: transparent;
|
||||
line-height: 26px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Fix button padding in firefox */
|
||||
|
||||
.jsoneditor-contextmenu ul li button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li button:hover,
|
||||
.jsoneditor-contextmenu ul li button:focus {
|
||||
color: #1a1a1a;
|
||||
background-color: #f5f5f5;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li button.default {
|
||||
width: 92px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li button.expand {
|
||||
float: right;
|
||||
width: 32px;
|
||||
height: 24px;
|
||||
border-left: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu div.icon {
|
||||
float: left;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-image: url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png");
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li button div.expand {
|
||||
float: right;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png") 0 -72px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li button:hover div.expand,
|
||||
.jsoneditor-contextmenu ul li button:focus div.expand,
|
||||
.jsoneditor-contextmenu ul li.selected div.expand,
|
||||
.jsoneditor-contextmenu ul li button.expand:hover div.expand,
|
||||
.jsoneditor-contextmenu ul li button.expand:focus div.expand {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu .separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
padding-top: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.remove > .icon {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.remove:hover > .icon,
|
||||
.jsoneditor-contextmenu button.remove:focus > .icon {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.append > .icon {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.append:hover > .icon,
|
||||
.jsoneditor-contextmenu button.append:focus > .icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.insert > .icon {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.insert:hover > .icon,
|
||||
.jsoneditor-contextmenu button.insert:focus > .icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.duplicate > .icon {
|
||||
background-position: -48px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.duplicate:hover > .icon,
|
||||
.jsoneditor-contextmenu button.duplicate:focus > .icon {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.sort-asc > .icon {
|
||||
background-position: -168px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.sort-asc:hover > .icon,
|
||||
.jsoneditor-contextmenu button.sort-asc:focus > .icon {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.sort-desc > .icon {
|
||||
background-position: -192px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.sort-desc:hover > .icon,
|
||||
.jsoneditor-contextmenu button.sort-desc:focus > .icon {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
|
||||
/* ContextMenu - sub menu */
|
||||
|
||||
.jsoneditor-contextmenu ul li .selected {
|
||||
background-color: #D5DDF6;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li ul {
|
||||
display: none;
|
||||
position: relative;
|
||||
left: -10px;
|
||||
top: 0;
|
||||
border: none;
|
||||
box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5);
|
||||
padding: 0 10px;
|
||||
/* TODO: transition is not supported on IE8-9 */
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
-moz-transition: all 0.3s ease-out;
|
||||
-o-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.jsoneditor-contextmenu ul li ul li button {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu ul li ul li button:hover,
|
||||
.jsoneditor-contextmenu ul li ul li button:focus {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-string > .icon {
|
||||
background-position: -144px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-string:hover > .icon,
|
||||
.jsoneditor-contextmenu button.type-string:focus > .icon,
|
||||
.jsoneditor-contextmenu button.type-string.selected > .icon {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-auto > .icon {
|
||||
background-position: -120px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-auto:hover > .icon,
|
||||
.jsoneditor-contextmenu button.type-auto:focus > .icon,
|
||||
.jsoneditor-contextmenu button.type-auto.selected > .icon {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-object > .icon {
|
||||
background-position: -72px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-object:hover > .icon,
|
||||
.jsoneditor-contextmenu button.type-object:focus > .icon,
|
||||
.jsoneditor-contextmenu button.type-object.selected > .icon {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-array > .icon {
|
||||
background-position: -96px -24px;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-array:hover > .icon,
|
||||
.jsoneditor-contextmenu button.type-array:focus > .icon,
|
||||
.jsoneditor-contextmenu button.type-array.selected > .icon {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
|
||||
.jsoneditor-contextmenu button.type-modes > .icon {
|
||||
background-image: none;
|
||||
width: 6px;
|
||||
}
|
||||
.jsoneditor .menu {
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #1A1A1A;
|
||||
background-color: #D5DDF6;
|
||||
border-bottom: 1px solid #97B0F8;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #aec0f8;
|
||||
background: #e3eaf6 url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png");
|
||||
color: #4D4D4D;
|
||||
opacity: 0.8;
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button:hover {
|
||||
background-color: #f0f2f5;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button:focus,
|
||||
.jsoneditor .menu button:active {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button:disabled {
|
||||
background-color: #e3eaf6;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.collapse-all {
|
||||
background-position: 0 -96px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.expand-all {
|
||||
background-position: 0 -120px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.undo {
|
||||
background-position: -24px -96px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.undo:disabled {
|
||||
background-position: -24px -120px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.redo {
|
||||
background-position: -48px -96px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.redo:disabled {
|
||||
background-position: -48px -120px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.compact {
|
||||
background-position: -72px -96px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.format {
|
||||
background-position: -72px -120px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.modes {
|
||||
background-image: none;
|
||||
width: auto;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu button.separator {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.jsoneditor .menu a {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #97B0F8;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.jsoneditor .menu a:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.jsoneditor .menu a.poweredBy {
|
||||
font-size: 8pt;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* TODO: css for button:disabled is not supported by IE8 */
|
||||
.jsoneditor .search input,
|
||||
.jsoneditor .search .results {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A;
|
||||
background: transparent;
|
||||
/* For Firefox */
|
||||
}
|
||||
|
||||
.jsoneditor .search {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.jsoneditor .search .frame {
|
||||
border: 1px solid #97B0F8;
|
||||
background-color: white;
|
||||
padding: 0 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.jsoneditor .search .frame table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.jsoneditor .search input {
|
||||
width: 120px;
|
||||
border: none;
|
||||
outline: none;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.jsoneditor .search .results {
|
||||
color: #4d4d4d;
|
||||
padding-right: 5px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.jsoneditor .search button {
|
||||
width: 16px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: url("/assets/naturalCrit/jsonFileEditor/img/jsoneditor-icons.png");
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.jsoneditor .search button:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.jsoneditor .search button.refresh {
|
||||
width: 18px;
|
||||
background-position: -99px -73px;
|
||||
}
|
||||
|
||||
.jsoneditor .search button.next {
|
||||
cursor: pointer;
|
||||
background-position: -124px -73px;
|
||||
}
|
||||
|
||||
.jsoneditor .search button.next:hover {
|
||||
background-position: -124px -49px;
|
||||
}
|
||||
|
||||
.jsoneditor .search button.previous {
|
||||
cursor: pointer;
|
||||
background-position: -148px -73px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.jsoneditor .search button.previous:hover {
|
||||
background-position: -148px -49px;
|
||||
}
|
||||
Reference in New Issue
Block a user