1
0
mirror of https://github.com/stolksdorf/homebrewery.git synced 2025-12-16 08:15:55 +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 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({ var Editor = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { 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){ handleTextChange : function(text){
this.props.onChange(text); this.props.onChange(text);
}, },
handleCursorActivty : function(curpos){
iconClick : function(snippetFn){ this.cursorPosition = curpos;
var curPos = this.refs.textarea.selectionStart;
this.props.onChange(this.props.text.slice(0, curPos) +
snippetFn() +
this.props.text.slice(curPos + 1));
}, },
renderTemplateIcons : function(){ handleSnippetClick : function(injectText){
return _.map(Snippets, (t) => { if(!this.cursorPosition) return;
return <div className='icon' key={t.icon} var lines = this.props.value.split('\n');
onClick={this.iconClick.bind(this, t.snippet)} lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText);
data-tooltip={t.tooltip}>
<i className={'fa ' + t.icon} /> this.handleTextChange(lines.join('\n'));
</div>; 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(){ renderSnippetGroups : function(){
return _.map(Snippets, (snippetGroup)=>{ return _.map(Snippets, (snippetGroup)=>{
@@ -43,19 +60,25 @@ var Editor = React.createClass({
groupName={snippetGroup.groupName} groupName={snippetGroup.groupName}
icon={snippetGroup.icon} icon={snippetGroup.icon}
snippets={snippetGroup.snippets} snippets={snippetGroup.snippets}
key={snippetGroup.groupName}
onSnippetClick={this.handleSnippetClick}
/> />
}) })
}, },
render : function(){ render : function(){
return( return(
<div className='editor'> <div className='editor' ref='main'>
{this.renderTemplateIcons()} <div className='snippetBar' ref='snippetBar'>
<div className='snippetBar'>
{this.renderSnippetGroups()} {this.renderSnippetGroups()}
</div> </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> </div>
); );
} }
@@ -65,6 +88,12 @@ module.exports = Editor;
var SnippetGroup = React.createClass({ var SnippetGroup = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
@@ -74,19 +103,27 @@ var SnippetGroup = React.createClass({
onSnippetClick : function(){}, onSnippetClick : function(){},
}; };
}, },
getInitialState: function() { handleSnippetClick : function(snippet){
return { this.props.onSnippetClick(execute(snippet.gen));
};
}, },
renderSnippets : function(){
return _.map(this.props.snippets, (snippet)=>{
handleSnippetClick : function(){ 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(){ render : function(){
return <div className='snippetGroup'> return <div className='snippetGroup'>
<div className='text'>
<i className={'fa fa-fw ' + this.props.icon} /> <i className={'fa fa-fw ' + this.props.icon} />
<span className='groupName'>{this.props.groupName}</span>
</div>
<div className='dropdown'>
{this.renderSnippets()}
</div>
</div> </div>
}, },

View File

@@ -1,45 +1,10 @@
.editor{ .editor{
position : relative; 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{ .snippetBar{
padding : 5px; padding : 5px;
@@ -48,7 +13,6 @@
display: flex; display: flex;
align-items: center; align-items: center;
//justify-content: center;
.snippetGroup{ .snippetGroup{
@@ -59,11 +23,56 @@
background-color: #999; background-color: #999;
} }
padding : 5px; padding : 5px;
font-size: 20px; font-size: 15px;
margin: 0px 10px; margin: 0px 10px;
.text{
line-height: 20px;
.groupName{
margin-left: 6px;
font-size: 12px;
}
}
//cursor : pointer; //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', name : 'Spell',
icon : 'fa-magic', icon : 'fa-magic',
snippet : SpellGen gen : SpellGen
},
{
name : 'Test',
icon : 'fa-rocket',
gen : function(){ return "TEST"}
} }
] ]
}, },
@@ -174,7 +179,7 @@ module.exports = [
{ {
name : 'Spell', name : 'Spell',
icon : 'fa-magic', icon : 'fa-magic',
snippet : SpellGen gen : SpellGen
} }
] ]
}, },
@@ -185,7 +190,7 @@ module.exports = [
{ {
name : 'Spell', name : 'Spell',
icon : 'fa-magic', 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 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){ 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 [ return [

View File

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

View File

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

View File

@@ -34,20 +34,35 @@ var CodeEditor = React.createClass({
this.codeMirror.on('change', this.handleChange); this.codeMirror.on('change', this.handleChange);
this.codeMirror.on('cursorActivity', this.handleCursorActivity); 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) { if(this.codeMirror && nextProps.value !== undefined && this.codeMirror.getValue() != nextProps.value) {
this.codeMirror.setValue(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){ handleChange : function(editor){
this.props.onChange(editor.getValue()); this.props.onChange(editor.getValue());
}, },
handleCursorActivity : function(){ handleCursorActivity : function(){
this.props.onCursorActivity(this.codeMirror.getCursor()); this.props.onCursorActivity(this.codeMirror.doc.getCursor());
}, },
render : function(){ render : function(){