1
0
mirror of https://github.com/stolksdorf/homebrewery.git synced 2025-12-15 22:35:59 +00:00

Editor pane looks finished, injecting snippet text is workign and snippet group structure done

This commit is contained in:
Scott Tolksdorf
2016-05-06 13:59:41 -04:00
parent c418ea5b42
commit ad02f99ebe
7 changed files with 192 additions and 115 deletions

View File

@@ -6,6 +6,16 @@ var CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
var Snippets = require('./snippets/snippets.js');
var splice = function(str, index, inject){
return str.slice(0, index) + inject + str.slice(index);
};
var execute = function(val){
if(_.isFunction(val)) return val();
return val;
}
var Editor = React.createClass({
getDefaultProps: function() {
return {
@@ -14,28 +24,35 @@ var Editor = React.createClass({
};
},
cursorPosition : null,
componentDidMount: function() {
var paneHeight = this.refs.main.parentNode.clientHeight;
paneHeight -= this.refs.snippetBar.clientHeight + 1;
this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
},
handleTextChange : function(text){
this.props.onChange(text);
},
iconClick : function(snippetFn){
var curPos = this.refs.textarea.selectionStart;
this.props.onChange(this.props.text.slice(0, curPos) +
snippetFn() +
this.props.text.slice(curPos + 1));
handleCursorActivty : function(curpos){
this.cursorPosition = curpos;
},
renderTemplateIcons : function(){
return _.map(Snippets, (t) => {
return <div className='icon' key={t.icon}
onClick={this.iconClick.bind(this, t.snippet)}
data-tooltip={t.tooltip}>
<i className={'fa ' + t.icon} />
</div>;
})
handleSnippetClick : function(injectText){
if(!this.cursorPosition) return;
var lines = this.props.value.split('\n');
lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText);
this.handleTextChange(lines.join('\n'));
this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length);
},
//Called when there are changes to the editor's dimensions
update : function(){
this.refs.codeEditor.updateSize();
},
renderSnippetGroups : function(){
return _.map(Snippets, (snippetGroup)=>{
@@ -43,19 +60,25 @@ var Editor = React.createClass({
groupName={snippetGroup.groupName}
icon={snippetGroup.icon}
snippets={snippetGroup.snippets}
key={snippetGroup.groupName}
onSnippetClick={this.handleSnippetClick}
/>
})
},
render : function(){
return(
<div className='editor'>
{this.renderTemplateIcons()}
<div className='snippetBar'>
<div className='editor' ref='main'>
<div className='snippetBar' ref='snippetBar'>
{this.renderSnippetGroups()}
</div>
<CodeEditor wrap={true} language='gfm' value={this.props.value} onChange={this.handleTextChange} />
<CodeEditor
ref='codeEditor'
wrap={true}
language='gfm'
value={this.props.value}
onChange={this.handleTextChange}
onCursorActivity={this.handleCursorActivty} />
</div>
);
}
@@ -65,6 +88,12 @@ module.exports = Editor;
var SnippetGroup = React.createClass({
getDefaultProps: function() {
return {
@@ -74,19 +103,27 @@ var SnippetGroup = React.createClass({
onSnippetClick : function(){},
};
},
getInitialState: function() {
return {
};
handleSnippetClick : function(snippet){
this.props.onSnippetClick(execute(snippet.gen));
},
handleSnippetClick : function(){
renderSnippets : function(){
return _.map(this.props.snippets, (snippet)=>{
return <div className='snippet' key={snippet.name} onClick={this.handleSnippetClick.bind(this, snippet)}>
<i className={'fa fa-fw ' + snippet.icon} />
{snippet.name}
</div>
})
},
render : function(){
return <div className='snippetGroup'>
<div className='text'>
<i className={'fa fa-fw ' + this.props.icon} />
<span className='groupName'>{this.props.groupName}</span>
</div>
<div className='dropdown'>
{this.renderSnippets()}
</div>
</div>
},

View File

@@ -1,45 +1,10 @@
.editor{
position : relative;
height : 100%;
min-height : 100%;
width : 100%;
//display: flex;
//flex-direction: column;
/*
.textIcons{
display : inline-block;
vertical-align : top;
.icon{
display : inline-block;
height : 30px;
width : 30px;
cursor : pointer;
font-size : 1.5em;
line-height : 30px;
text-align : center;
&:nth-child(8n + 1){ background-color: @blue; }
&:nth-child(8n + 2){ background-color: @orange; }
&:nth-child(8n + 3){ background-color: @teal; }
&:nth-child(8n + 4){ background-color: @red; }
&:nth-child(8n + 5){ background-color: @purple; }
&:nth-child(8n + 6){ background-color: @silver; }
&:nth-child(8n + 7){ background-color: @yellow; }
&:nth-child(8n + 8){ background-color: @green; }
}
}
textarea{
box-sizing : border-box;
resize : none;
overflow-y : scroll;
height : 100%;
width : 100%;
padding : 10px;
border : none;
outline: none;
}
*/
width : 100%;
height : 500px;
.snippetBar{
padding : 5px;
@@ -48,7 +13,6 @@
display: flex;
align-items: center;
//justify-content: center;
.snippetGroup{
@@ -59,11 +23,56 @@
background-color: #999;
}
padding : 5px;
font-size: 20px;
font-size: 15px;
margin: 0px 10px;
.text{
line-height: 20px;
.groupName{
margin-left: 6px;
font-size: 12px;
}
}
//cursor : pointer;
&:hover{
.dropdown{
visibility: visible;
}
}
.dropdown{
position: absolute;
z-index : 1000;
background-color: #ddd;
padding : 5px;
visibility: hidden;
.snippet{
font-size: 13px;
padding : 10px;
.animate(background-color);
cursor : pointer;
&:hover{
background-color: #999;
}
}
}
}
}
.codeEditor{
height : 100%;
}
}

View File

@@ -163,7 +163,12 @@ module.exports = [
{
name : 'Spell',
icon : 'fa-magic',
snippet : SpellGen
gen : SpellGen
},
{
name : 'Test',
icon : 'fa-rocket',
gen : function(){ return "TEST"}
}
]
},
@@ -174,7 +179,7 @@ module.exports = [
{
name : 'Spell',
icon : 'fa-magic',
snippet : SpellGen
gen : SpellGen
}
]
},
@@ -185,7 +190,7 @@ module.exports = [
{
name : 'Spell',
icon : 'fa-magic',
snippet : SpellGen
gen : SpellGen
}
]
},

View File

@@ -56,9 +56,9 @@ module.exports = function(){
var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"];
var components = _.sample(["V", "S", "M"], _.random(1,3)).join(', ');
var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', ');
if(components.indexOf("M") !== -1){
components += " (" + _.sample(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
}
return [

View File

@@ -51,6 +51,10 @@ var HomePage = React.createClass({
*/
},
handleSplitMove : function(){
this.refs.editor.update();
},
handleTextChange : function(text){
this.setState({
text : text
@@ -59,16 +63,12 @@ var HomePage = React.createClass({
//localStorage.setItem(KEY, text);
},
render : function(){
return(
<div className='homePage page'>
<Navbar>
renderNavbar : function(){
return <Navbar>
<Nav.section>
<Nav.item>Bad Ass Brew</Nav.item>
</Nav.section>
<Nav.section>
<RedditShare brew={{text : this.state.text}}/>
<Nav.item
@@ -92,10 +92,16 @@ var HomePage = React.createClass({
</Nav.item>
</Nav.section>
</Navbar>
},
render : function(){
return(
<div className='homePage page'>
{this.renderNavbar()}
<div className='content'>
<SplitPane>
<Editor value={this.state.text} onChange={this.handleTextChange} />
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/>
<div>{this.state.text}</div>
</SplitPane>

View File

@@ -3,6 +3,11 @@ var _ = require('lodash');
var cx = require('classnames');
var SplitPane = React.createClass({
getDefaultProps: function() {
return {
onDragFinish : function(){} //fires when dragging
};
},
getInitialState: function() {
return {
storageKey : 'naturalcrit-pane-split',
@@ -20,20 +25,23 @@ var SplitPane = React.createClass({
},
handleUp : function(){
if(this.state.isDragging){
this.props.onDragFinish(this.state.size);
window.localStorage.setItem(this.props.storageKey, this.state.size);
}
this.setState({ isDragging : false });
},
handleDown : function(){
this.setState({ isDragging : true });
this.unFocus()
//this.unFocus()
},
handleMove : function(e){
if(!this.state.isDragging) return;
this.setState({
size : e.pageX
});
window.localStorage.setItem(this.props.storageKey, e.pageX);
},
/*
unFocus : function() {
if(document.selection){
document.selection.empty();
@@ -41,12 +49,9 @@ var SplitPane = React.createClass({
window.getSelection().removeAllRanges();
}
},
*/
renderDivider : function(){
return <div
className='divider'
onMouseDown={this.handleDown}
/>
return <div className='divider' onMouseDown={this.handleDown} />
},
render : function(){

View File

@@ -34,20 +34,35 @@ var CodeEditor = React.createClass({
this.codeMirror.on('change', this.handleChange);
this.codeMirror.on('cursorActivity', this.handleCursorActivity);
this.updateSize();
},
componentWillReceiveProps: _.debounce(function(nextProps){
componentWillReceiveProps: function(nextProps){
if(this.codeMirror && nextProps.value !== undefined && this.codeMirror.getValue() != nextProps.value) {
this.codeMirror.setValue(nextProps.value);
}
}, 0),
},
shouldComponentUpdate: function(nextProps, nextState) {
return false;
},
setCursorPosition : function(line, char){
setTimeout(()=>{
this.codeMirror.focus();
this.codeMirror.doc.setCursor(line, char);
}, 10);
},
updateSize : function(){
this.codeMirror.refresh();
},
handleChange : function(editor){
this.props.onChange(editor.getValue());
},
handleCursorActivity : function(){
this.props.onCursorActivity(this.codeMirror.getCursor());
this.props.onCursorActivity(this.codeMirror.doc.getCursor());
},
render : function(){