1
0
mirror of https://github.com/stolksdorf/homebrewery.git synced 2025-12-24 03:01:31 +00:00

Polishing the sidebar so more

This commit is contained in:
Scott Tolksdorf
2015-11-16 14:22:00 -05:00
parent e6e87457da
commit 5918267c86
10 changed files with 152 additions and 154 deletions

View File

@@ -68,15 +68,16 @@ var Encounter = React.createClass({
getPlayerObjects : function(){ getPlayerObjects : function(){
return _.map(this.props.players.split('\n'), function(line){ return _.reduce(this.props.players.split('\n'), function(r, line){
var parts = line.split(' '); var parts = line.split(' ');
if(parts.length != 2) return null; if(parts.length != 2) return r;
return { r.push({
name : parts[0], name : parts[0],
initiative : parts[1] * 1, initiative : parts[1] * 1,
isPC : true isPC : true
} })
}) return r;
},[])
}, },
@@ -84,7 +85,7 @@ var Encounter = React.createClass({
var self = this; var self = this;
var sortedEnemies = _.sortBy(_.union(_.values(this.state.enemies), this.getPlayerObjects()), function(e){ var sortedEnemies = _.sortBy(_.union(_.values(this.state.enemies), this.getPlayerObjects()), function(e){
if(e.initiative) return -e.initiative; if(e && e.initiative) return -e.initiative;
return 0; return 0;
}); });

View File

@@ -131,13 +131,10 @@ var MonsterCard = React.createClass({
var self = this; var self = this;
var usedItems = this.state.usedItems.slice(0); var usedItems = this.state.usedItems.slice(0);
return _.map(this.props.items, function(item, index){ return _.map(this.props.items, function(item, index){
var used = _.contains(usedItems, item); var used = _.contains(usedItems, item);
if(used){ if(used){
usedItems.splice(usedItems.indexOf(item), 1); usedItems.splice(usedItems.indexOf(item), 1);
} }
return <span return <span
key={index} key={index}
className={cx({'used' : used})} className={cx({'used' : used})}
@@ -174,11 +171,13 @@ var MonsterCard = React.createClass({
{this.renderSpells()} {this.renderSpells()}
</div> </div>
<div className='abilitiesContainer'>
{this.props.abilities}
</div>
<div className='itemContainer'> <div className='itemContainer'>
<i className='fa fa-flask' />
{this.renderItems()} {this.renderItems()}
</div> </div>
</div> </div>
); );
} }

View File

@@ -1,4 +1,5 @@
@marginSize : 10px;
.noselect(){ .noselect(){
-webkit-touch-callout : none; -webkit-touch-callout : none;
-webkit-user-select : none; -webkit-user-select : none;
@@ -7,9 +8,6 @@
-ms-user-select : none; -ms-user-select : none;
user-select : none; user-select : none;
} }
@marginSize : 10px;
.playerCard{ .playerCard{
display : inline-block; display : inline-block;
box-sizing : border-box; box-sizing : border-box;
@@ -17,25 +15,21 @@
padding : 10px; padding : 10px;
background-color : white; background-color : white;
border : 1px solid #bbb; border : 1px solid #bbb;
.name{ .name{
margin-right: 20px; margin-right : 20px;
} }
.initiative{ .initiative{
font-size: 0.8em; font-size : 0.8em;
i{ i{
font-size: 0.8em; font-size : 0.8em;
} }
} }
&:nth-child(5n + 1){ background-color: fade(@blue, 25%); } &:nth-child(5n + 1){ background-color: fade(@blue, 25%); }
&:nth-child(5n + 2){ background-color: fade(@purple, 25%); } &:nth-child(5n + 2){ background-color: fade(@purple, 25%); }
&:nth-child(5n + 3){ background-color: fade(@steel, 25%); } &:nth-child(5n + 3){ background-color: fade(@steel, 25%); }
&:nth-child(5n + 4){ background-color: fade(@green, 25%); } &:nth-child(5n + 4){ background-color: fade(@green, 25%); }
&:nth-child(5n + 5){ background-color: fade(@orange, 25%); } &:nth-child(5n + 5){ background-color: fade(@orange, 25%); }
} }
.monsterCard{ .monsterCard{
position : relative; position : relative;
display : inline-block; display : inline-block;
@@ -50,19 +44,19 @@
position : absolute; position : absolute;
top : 0px; top : 0px;
left : 0px; left : 0px;
z-index : 50;
height : 3px; height : 3px;
max-width : 100%; max-width : 100%;
background-color : @green; background-color : @green;
z-index : 50;
} }
.overhealbar{ .overhealbar{
position : absolute; position : absolute;
top : 0px; top : 0px;
left : 0px; left : 0px;
z-index : 100;
height : 3px; height : 3px;
max-width : 100%; max-width : 100%;
background-color : @blueLight; background-color : @blueLight;
z-index : 100;
} }
&.hurt{ &.hurt{
.healthbar{ .healthbar{
@@ -70,26 +64,25 @@
} }
} }
&.last_legs{ &.last_legs{
background-color: lighten(@red, 49%); background-color : lighten(@red, 49%);
.healthbar{ .healthbar{
background-color : red; background-color : red;
} }
} }
&.dead{ &.dead{
opacity: 0.3; opacity : 0.3;
} }
&>.info{ &>.info{
margin-bottom: 10px; margin-bottom : 10px;
.name{ .name{
font-size: 1.5em; margin-right : 10px;
margin-right: 10px; font-size : 1.5em;
} }
.stat{ .stat{
font-size: 0.7em; margin-right : 5px;
margin-right: 5px; font-size : 0.7em;
i{ i{
font-size: 0.7em; font-size : 0.7em;
} }
} }
} }
@@ -118,17 +111,21 @@
font-weight : 800; font-weight : 800;
} }
} }
.abilitiesContainer{
margin-top : 5px;
}
.itemContainer{ .itemContainer{
margin-top : 5px;
i{
font-size : 0.7em;
}
span{ span{
cursor: pointer; margin-right : 5px;
font-size: 0.7em; cursor : pointer;
margin-right: 5px; font-size : 0.7em;
&.used{ &.used{
text-decoration: line-through; text-decoration : line-through;
} }
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -47,7 +47,7 @@ var encounters = [
]; ];
var MonsterManual = { var monsterManual = {
'goblin' : { 'goblin' : {
"hp" : 40, "hp" : 40,
"mov": 30, "mov": 30,
@@ -97,69 +97,48 @@ var NaturalCrit = React.createClass({
getInitialState: function() { getInitialState: function() {
var self = this; var self = this;
return { return {
selectedEncounterIndex : 0, selectedEncounterIndex : 0,
encounters : JSON.parse(localStorage.getItem('encounters')) || encounters,
monsterManual : JSON.parse(localStorage.getItem('monsterManual')) || monsterManual,
encounters : encounters, players : localStorage.getItem('players') || 'jasper 13\nzatch 19'
monsterManual : MonsterManual,
players : 'jasper 13'
}; };
}, },
createEnemy : function(type, index){
var stats = MonsterManual[type]
return _.extend({
id : type + index,
name : type,
currentHP : stats.hp,
initiative : _.random(1,20) + attrMod(stats.attr.dex)
}, stats);
},
addPC : function(name, initiative){ handleEncounterJSONChange : function(encounterIndex, json){
this.state.enemies[name] = {
name : name,
id : name,
initiative : initiative,
isPC : true
};
this.setState({
enemies : this.state.enemies
})
},
addRandomPC : function(){
this.addPC(
_.sample(['zatch', 'jasper', 'el toro', 'tulik']) + _.random(1,1000),
_.random(1,25)
)
},
handleJSONChange : function(encounterIndex, json){
this.state.encounters[encounterIndex] = json; this.state.encounters[encounterIndex] = json;
this.setState({ this.setState({
encounters : this.state.encounters encounters : this.state.encounters
}) })
localStorage.setItem("encounters", JSON.stringify(this.state.encounters));
}, },
handleEncounterChange : function(encounterIndex){ handleMonsterManualJSONChange : function(json){
this.setState({ this.setState({
selectedEncounterIndex : encounterIndex monsterManual : json
}); });
localStorage.setItem("monsterManual", JSON.stringify(this.state.monsterManual));
}, },
handlePlayerChange : function(e){ handlePlayerChange : function(e){
this.setState({ this.setState({
players : e.target.value players : e.target.value
}); });
localStorage.setItem("players", e.target.value);
},
handleSelectedEncounterChange : function(encounterIndex){
this.setState({
selectedEncounterIndex : encounterIndex
});
},
handleRemoveEncounter : function(encounterIndex){
this.state.encounters.splice(encounterIndex, 1);
this.setState({
encounters : this.state.encounters
});
localStorage.setItem("encounters", JSON.stringify(this.state.encounters));
}, },
renderSelectedEncounter : function(){ renderSelectedEncounter : function(){
var self = this; var self = this;
@@ -183,9 +162,6 @@ var NaturalCrit = React.createClass({
render : function(){ render : function(){
var self = this; var self = this;
console.log(this.state.encounters);
return( return(
<div className='naturalCrit'> <div className='naturalCrit'>
<Sidebar <Sidebar
@@ -194,13 +170,15 @@ var NaturalCrit = React.createClass({
monsterManual={this.state.monsterManual} monsterManual={this.state.monsterManual}
players={this.state.players} players={this.state.players}
onSelectEncounter={this.handleEncounterChange} onSelectEncounter={this.handleSelectedEncounterChange}
onJSONChange={this.handleJSONChange} onRemoveEncounter={this.handleRemoveEncounter}
onJSONChange={this.handleEncounterJSONChange}
onMonsterManualChange={this.handleMonsterManualJSONChange}
onPlayerChange={this.handlePlayerChange} onPlayerChange={this.handlePlayerChange}
/> />
{this.renderSelectedEncounter()} {this.renderSelectedEncounter()}
</div> </div>
); );

View File

@@ -15,8 +15,9 @@ var Sidebar = React.createClass({
onSelectEncounter : function(){}, onSelectEncounter : function(){},
onJSONChange : function(encounterIndex, json){}, onJSONChange : function(encounterIndex, json){},
onMonsterManualChange : function(json){},
onPlayerChange : function(){}, onPlayerChange : function(){},
onRemoveEncounter : function(encounterIndex){}
}; };
}, },
@@ -33,17 +34,14 @@ var Sidebar = React.createClass({
}, },
handleJSONChange : function(encounterIndex, json){ handleJSONChange : function(encounterIndex, json){
this.props.onJSONChange(encounterIndex, json); this.props.onJSONChange(encounterIndex, json);
}, },
handleSelectEncounter : function(encounterIndex){ handleSelectEncounter : function(encounterIndex){
console.log(encounterIndex);
this.props.onSelectEncounter(encounterIndex); this.props.onSelectEncounter(encounterIndex);
}, },
handleRemoveEncounter : function(encounterIndex){
this.props.onRemoveEncounter(encounterIndex);
},
renderEncounters : function(){ renderEncounters : function(){
var self = this; var self = this;
@@ -53,7 +51,7 @@ var Sidebar = React.createClass({
var isSelected = self.props.selectedEncounter == index; var isSelected = self.props.selectedEncounter == index;
return <div className={cx('encounter' , {'selected' : isSelected})} key={index}> return <div className={cx('encounter' , {'selected' : isSelected})} key={index}>
<i onClick={self.handleSelectEncounter.bind(self, index)} className={cx('fa', { <i onClick={self.handleSelectEncounter.bind(self, index)} className={cx('select', 'fa', {
'fa-square-o' : !isSelected, 'fa-square-o' : !isSelected,
'fa-check-square-o' : isSelected, 'fa-check-square-o' : isSelected,
})} /> })} />
@@ -64,6 +62,8 @@ var Sidebar = React.createClass({
json={encounter} json={encounter}
onJSONChange={self.handleJSONChange.bind(self, index)} onJSONChange={self.handleJSONChange.bind(self, index)}
/> />
<i onClick={self.handleRemoveEncounter.bind(self, index)} className='remove fa fa-times' />
</div> </div>
}) })
}, },
@@ -81,11 +81,20 @@ var Sidebar = React.createClass({
<div className='contents'> <div className='contents'>
<div className='monsterManualContainer'> <div className='monsterManualContainer'>
<i className='fa fa-book' /> <JSONFileEditor
<JSONFileEditor name="Monster Manual" /> name="Monster Manual"
json={this.props.monsterManual}
onJSONChange={this.onMonsterManualChange}
/>
</div> </div>
<div className='encounterContainer'> <div className='encounterContainer'>
<h3> <i className='fa fa-flag' /> Encounters </h3> <h3>
<i className='fa fa-flag' /> Encounters
<button onClick={} className='addEncounter'>
<i className='fa fa-plus' />
</button>
</h3>
{this.renderEncounters()} {this.renderEncounters()}
<div className='controls'> <div className='controls'>

View File

@@ -41,6 +41,7 @@
cursor : pointer; cursor : pointer;
fill : white; fill : white;
} }
span.name{ span.name{
.animateAll(); .animateAll();
position : absolute; position : absolute;
@@ -68,17 +69,51 @@
.encounterContainer{ .encounterContainer{
margin-bottom : 20px; margin-bottom : 20px;
h3{ h3{
background-color : fade(@red, 25%); background-color : @red;
color : white;
button{
outline: none;
border : none;
cursor: pointer;
background-color: transparent;
.animate(color);
float : right;
&:hover{
color : white;
}
}
} }
.encounter{ .encounter{
padding-left: 20px;
position: relative;
i.remove{
position: absolute;
top : 3px;
right : 3px;
font-size: 0.6em;
cursor: pointer;
color : #333;
&:hover{
color: @red;
}
}
i.select{
cursor: pointer;
}
.jsonFileEditor{
display: inline-block;
}
&.selected{ &.selected{
background-color : @green; background-color : fade(@green, 30%);
} }
} }
} }
.addPlayers{ .addPlayers{
h3{ h3{
background-color : fade(@purple, 25%); //background-color : fade(@purple, 25%);
color : white;
background-color: @purple;
} }
textarea{ textarea{
height : 80px; height : 80px;

View File

@@ -7,7 +7,7 @@
<link rel="icon" href="/assets/NaturalCrit/favicon.ico" type="image/x-icon" /> <link rel="icon" href="/assets/NaturalCrit/favicon.ico" type="image/x-icon" />
{{=vitreum.css}} {{=vitreum.css}}
{{=vitreum.globals}} {{=vitreum.globals}}
<title>NaturalCrit</title> <title>Natural Crit - D&D Combat Manager</title>
</head> </head>
<body> <body>
<div id="reactContainer">{{=vitreum.component}}</div> <div id="reactContainer">{{=vitreum.component}}</div>

View File

@@ -2,29 +2,16 @@ var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var JSONEditor = require('jsoneditor'); var JSONEditor = require('jsoneditor');
//var editor = new JSONEditor(container);
var json = {
test : 6,
arr : [true, 1,2,3,4],
yo : {
yeah : true
}
}
var downloadFile = function(filename, text) { var downloadFile = function(filename, text) {
var element = document.createElement('a'); var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename); element.setAttribute('download', filename);
element.style.display = 'none'; element.style.display = 'none';
document.body.appendChild(element); document.body.appendChild(element);
element.click(); element.click();
document.body.removeChild(element); document.body.removeChild(element);
} }
@@ -32,10 +19,8 @@ var downloadFile = function(filename, text) {
var JsonFileEditor = React.createClass({ var JsonFileEditor = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
name : "yo", name : "test",
json : {},
json : json,
onJSONChange : function(){} onJSONChange : function(){}
}; };
}, },
@@ -45,11 +30,11 @@ var JsonFileEditor = React.createClass({
showEditor: false showEditor: false
}; };
}, },
componentWillReceiveProps: function(nextProps) { componentWillReceiveProps: function(nextProps) {
//this.editor.set(nextProps.json); if(JSON.stringify(nextProps.json) != JSON.stringify(this.editor.get())){
this.editor.set(nextProps.json);
}
}, },
componentDidMount: function() { componentDidMount: function() {
this.editor = new JSONEditor(this.refs.editor, { this.editor = new JSONEditor(this.refs.editor, {
change : this.handleJSONChange, change : this.handleJSONChange,
@@ -57,23 +42,14 @@ var JsonFileEditor = React.createClass({
}, this.props.json) }, this.props.json)
}, },
handleJSONChange : function(){ handleJSONChange : function(){
this.props.onJSONChange(this.editor.get()); this.props.onJSONChange(this.editor.get());
//try to store in local storage?
}, },
handleShowEditorClick : function(){ handleShowEditorClick : function(){
this.setState({ this.setState({
showEditor : !this.state.showEditor showEditor : !this.state.showEditor
}) })
}, },
handleDownload : function(){ handleDownload : function(){
downloadFile(this.props.name + '.json', JSON.stringify(this.props.json, null, '\t')); downloadFile(this.props.name + '.json', JSON.stringify(this.props.json, null, '\t'));
}, },
@@ -88,12 +64,6 @@ var JsonFileEditor = React.createClass({
handleUploadClick : function(){ handleUploadClick : function(){
this.refs.uploader.click() this.refs.uploader.click()
}, },
handleRemove : function(){
},
renderEditor : function(){ renderEditor : function(){
return <div className='jsonEditor' ref='editor' /> return <div className='jsonEditor' ref='editor' />
@@ -104,23 +74,14 @@ var JsonFileEditor = React.createClass({
var self = this; var self = this;
return( return(
<div className={cx('jsonFileEditor', {'showEditor' : this.state.showEditor})}> <div className={cx('jsonFileEditor', {'showEditor' : this.state.showEditor})}>
<span className='name'>{this.props.name}</span> <span className='name'>{this.props.name}</span>
<div className='controls'> <div className='controls'>
<button className='showEditor' onClick={this.handleShowEditorClick}><i className='fa fa-edit' /></button> <button className='showEditor' onClick={this.handleShowEditorClick}><i className='fa fa-edit' /></button>
<button className='downloadJSON' onClick={this.handleDownload}><i className='fa fa-download' /></button> <button className='downloadJSON' onClick={this.handleDownload}><i className='fa fa-download' /></button>
<button className='uploadJSON' onClick={this.handleUploadClick}><i className='fa fa-cloud-upload' /></button> <button className='uploadJSON' onClick={this.handleUploadClick}><i className='fa fa-cloud-upload' /></button>
</div> </div>
{this.renderEditor()} {this.renderEditor()}
<input type="file" id="input" onChange={this.handleUpload} ref='uploader' /> <input type="file" id="input" onChange={this.handleUpload} ref='uploader' />
</div> </div>

View File

@@ -2,34 +2,52 @@
@import (less) "./jsoneditor.css"; @import (less) "./jsoneditor.css";
.jsonFileEditor{ .jsonFileEditor{
position : relative; position : relative;
width : 100%; padding : 10px;
&.showEditor{ &.showEditor{
.jsonEditor{ .jsonEditor{
display : initial; display : initial;
} }
} }
.jsonEditor{ .jsonEditor{
position : absolute; position : absolute;
display : none; display : none;
top : 100%; top : 100%;
left : 0px; left : 0px;
z-index : 1000; z-index : 1000;
min-width : 400px;
background-color : white; background-color : white;
} }
.name{ .name{
display : inline-block; display : inline-block;
font-size : 0.8em; font-size : 0.8em;
font-weight : 800; font-weight : 800;
min-width: 100px;
} }
.controls{ .controls{
position : absolute; display: inline-block;
top : 0px; float: right;
right : 0px; //position : absolute;
//top : 0px;
//right : 0px;
button{
outline: none;
border : none;
cursor: pointer;
background-color: transparent;
.animate(color);
&:hover{
&.showEditor{ color : @green; }
&.downloadJSON{ color : @blue; }
&.uploadJSON{ color : @orange; }
}
}
} }
input[type="file"]{ input[type="file"]{
display: none; display : none;
} }
} }