From e963672b651e248faa5554a1b38452d3ce359eba Mon Sep 17 00:00:00 2001 From: Charlie Humphreys Date: Fri, 24 Jun 2022 23:31:20 -0500 Subject: [PATCH] update tag setup to be based on the latest version of the stringArrayEditor.jsx --- .../editor/metadataEditor/metadataEditor.jsx | 110 ++------------- .../editor/metadataEditor/metadataEditor.less | 79 ++++++++--- .../stringArrayEditor/stringArrayEditor.jsx | 133 ++++++++++++++++++ client/homebrew/navbar/navbar.less | 2 +- client/homebrew/pages/editPage/editPage.jsx | 13 +- client/homebrew/pages/homePage/homePage.jsx | 2 +- client/homebrew/pages/newPage/newPage.jsx | 6 +- shared/naturalcrit/nav/nav.less | 2 +- shared/naturalcrit/styles/colors.less | 23 +++ 9 files changed, 243 insertions(+), 127 deletions(-) create mode 100644 client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index f3b5419e5..9f8094efd 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -5,6 +5,7 @@ const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); const request = require('superagent'); +const StringArrayEditor = require('../stringArrayEditor/stringArrayEditor.jsx'); const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder']; @@ -27,38 +28,6 @@ const MetadataEditor = createClass({ onChange : ()=>{} }; }, - getInitialState : function() { - return { - tagContext : !!this.props.metadata.tags ? this.props.metadata.tags.map((tag)=>({ - tag, - editing : false - })) : [], - temporaryTag : '', - updateTag : '' - }; - }, - - componentWillUpdate : function() { - const tags = this.props.metadata.tags; - if(!!tags) { - const contextTags = Object.values(this.state.tagContext).map((context)=>context.tag); - let updateContext = tags.length !== contextTags.length; - for (let i = 0; i < tags.length && updateContext === false; i++){ - const tag = tags[i]; - if(!contextTags.includes(tag)) - updateContext = true; - } - if(updateContext) { - this.setState((prevState)=>({ - ...prevState, - tagContext : this.props.metadata.tags.map((tag)=>({ - tag, - editing : false - })) - })); - } - } - }, getInitialState : function(){ return { @@ -78,9 +47,10 @@ const MetadataEditor = createClass({ }, handleFieldChange : function(name, e){ - this.props.onChange(_.merge({}, this.props.metadata, { + this.props.onChange({ + ...this.props.metadata, [name] : e.target.value - })); + }); }, handleSystem : function(system, e){ if(e.target.checked){ @@ -97,9 +67,10 @@ const MetadataEditor = createClass({ this.props.onChange(this.props.metadata); }, handlePublish : function(val){ - this.props.onChange(_.merge({}, this.props.metadata, { + this.props.onChange({ + ...this.props.metadata, published : val - })); + }); }, handleDelete : function(){ @@ -201,68 +172,6 @@ const MetadataEditor = createClass({ ; }, - addTag : function(tag){ - this.props.metadata.tags = _.uniq([...this.props.metadata.tags, ...(tag.split(',').map((t)=>t.trim()))]); - this.props.onChange(this.props.metadata); - }, - removeTag : function(tag){ - this.props.metadata.tags = this.props.metadata.tags.filter((t)=>t !== tag); - this.props.onChange(this.props.metadata); - }, - updateTag : function(tag, index){ - this.props.metadata.tags[index] = tag; - this.props.onChange(this.props.metadata); - }, - editTag : function(index){ - const tagContext = this.state.tagContext.map((context, i)=>{ - context.editing = index === i; - return context; - }); - this.setState({ tagContext, updateTag: this.props.metadata.tags[index] }); - }, - handleTagInputKeyDown : function(event, index){ - if(event.key === 'Enter') { - const tagPattern = /^(?:(?:group|meta|system|type):)?[A-Za-z0-9][A-Za-z0-9 /.:\-]+$/; - if(!!event.target.value.match(tagPattern)) { - if(!!index) { - this.updateTag(event.target.value, index); - const tagContext = this.state.tagContext; - tagContext[index].editing = false; - this.setState({ tagContext, updateTag: '' }); - } else { - this.addTag(event.target.value); - this.setState({ temporaryTag: '' }); - } - } else { - console.log('does not match'); - } - } - }, - - renderTags : function(){ - const tagElements = Object.values(this.state.tagContext).map((context, i)=>context.editing - ? { this.handleTagInputKeyDown(e, i); }} - onChange={(e)=>{ this.setState({ updateTag: e.target.value }); }}/> - :
{ this.editTag(i); }}>{context.tag}  - this.removeTag(context.tag)}/> -
- ); - - return
- -
- {tagElements} - { this.handleTagInputKeyDown(e); }} - onChange={(e)=>{ this.setState({ temporaryTag: e.target.value }); }}/> -
-
; - }, - render : function(){ return
@@ -289,7 +198,10 @@ const MetadataEditor = createClass({ {this.renderThumbnail()}
- {this.renderTags()} + this.handleFieldChange('tags', e)}/> {this.renderAuthors()} diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 31de998ce..d4fe62397 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -1,3 +1,4 @@ +@import 'naturalcrit/styles/colors.less'; .metadataEditor{ position : absolute; @@ -109,30 +110,74 @@ line-height : 1.5em; } - .tags.field .list { - display : flex; - flex-wrap : wrap; + .field .list { + display: flex; + flex-wrap: wrap; - >* { - flex : 0 0 auto; + > * { + flex: 0 0 auto; } - .badge { - background-color : #444; - border-radius : .5em; - color : white; - font-size : .9em; - margin : 2px; - padding : .3em; + #groupedIcon { + #backgroundColors; + display: inline-block; + border-radius: 0 0.5em 0.5em 0; + height: ~"calc(100% + 0.6em)"; + position: relative; + top: -0.3em; + right: -0.3em; + cursor: pointer; + min-width: 20px; + text-align: center; + color: white; - i.fa-times { - cursor: pointer; + i { + position: relative; + top: 50%; + transform: translateY(-50%); } } - .value { - width : 7.5vw; - min-width : 75px; + .badge { + background-color: #dddddd; + border-radius: .5em; + font-size: .9em; + margin: 2px; + padding: .3em; + + .icon { + #groupedIcon + } + } + + .input-group { + height: ~"calc(.9em + 4px + .6em)"; + + input { + border-radius: .5em 0 0 .5em; + } + + input:last-child { + border-radius: .5em; + } + + .value { + width: 7.5vw; + min-width: 75px; + height: 100%; + } + + .invalid:focus { + background-color: pink; + } + + .icon { + #groupedIcon; + height: 97%; + font-size: .8em; + right: 1px; + top: -.54em; + } } } } diff --git a/client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx b/client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx new file mode 100644 index 000000000..9c29f2e4e --- /dev/null +++ b/client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx @@ -0,0 +1,133 @@ +const React = require('react'); +const createClass = require('create-react-class'); +const _ = require('lodash'); + +const StringArrayEditor = createClass({ + displayName : 'StringArrayEditor', + getDefaultProps : function() { + return { + label : '', + values : [], + valuePatterns : null, + placeholder : '', + unique : false, + cannotEdit : [], + onChange : ()=>{} + }; + }, + + getInitialState : function() { + return { + valueContext : !!this.props.values ? this.props.values.map((value)=>({ + value, + editing : false + })) : [], + temporaryValue : '', + updateValue : '' + }; + }, + + componentDidUpdate : function(prevProps) { + if(!_.eq(this.props, prevProps)) { + this.setState({ + valueContext : !!this.props.values ? this.props.values.map((newValue)=>({ + value : newValue, + editing : this.state.valueContext.find(({ value })=>value === newValue)?.editing || false + })) : [] + }); + } + }, + + handleChange : function(value) { + this.props.onChange({ + target : { + value + } + }); + }, + + addValue : function(value){ + this.handleChange(_.uniq([...this.props.values, value])); + this.setState({ + temporaryValue : '' + }); + }, + + removeValue : function(index){ + this.handleChange(this.props.values.filter((_, i)=>i !== index)); + }, + + updateValue : function(value, index){ + const valueContext = this.state.valueContext; + valueContext[index].value = value; + valueContext[index].editing = false; + this.handleChange(valueContext.map((context)=>context.value)); + this.setState({ valueContext, updateValue: '' }); + }, + + editValue : function(index){ + if(!!this.props.cannotEdit && this.props.cannotEdit.includes(this.props.values[index])) { + return; + } + const valueContext = this.state.valueContext.map((context, i)=>{ + context.editing = index === i; + return context; + }); + this.setState({ valueContext, updateValue: this.props.values[index] }); + }, + + valueIsValid : function(value) { + const matchesPatterns = !this.props.valuePatterns || this.props.valuePatterns.some((pattern)=>!!(value || '').match(pattern)); + const uniqueIfSet = !this.props.unique || !this.props.values.includes(value); + return matchesPatterns && uniqueIfSet; + }, + + handleValueInputKeyDown : function(event, index) { + if(event.key === 'Enter') { + if(this.valueIsValid(event.target.value)) { + if(index !== undefined) { + this.updateValue(event.target.value, index); + } else { + this.addValue(event.target.value); + } + } + } else if(event.key === 'Escape') { + const valueContext = this.state.valueContext; + valueContext[index].editing = false; + this.setState({ valueContext, updateValue: '' }); + } + }, + + render : function() { + const valueElements = Object.values(this.state.valueContext).map((context, i)=>context.editing + ? +
+ this.handleValueInputKeyDown(e, i)} + onChange={(e)=>this.setState({ updateValue: e.target.value })}/> + {this.valueIsValid(this.state.updateValue) ?
{ e.stopPropagation(); this.updateValue(this.state.updateValue, i); }}/>
: null} +
+
+ :
this.editValue(i)}>{context.value} + {!!this.props.cannotEdit && this.props.cannotEdit.includes(context.value) ? null :
{ e.stopPropagation(); this.removeValue(i); }}/>
} +
+ ); + + return
+ +
+ {valueElements} +
+ this.handleValueInputKeyDown(e)} + onChange={(e)=>this.setState({ temporaryValue: e.target.value })}/> + {this.valueIsValid(this.state.temporaryValue) ?
{ e.stopPropagation(); this.addValue(this.state.temporaryValue); }}/>
: null} +
+
+
; + } +}); + +module.exports = StringArrayEditor; \ No newline at end of file diff --git a/client/homebrew/navbar/navbar.less b/client/homebrew/navbar/navbar.less index 95cc04c7a..39fbfaf5c 100644 --- a/client/homebrew/navbar/navbar.less +++ b/client/homebrew/navbar/navbar.less @@ -91,7 +91,7 @@ &:nth-of-type(2){ background-color: darken(@purple, 30%); } } .item{ - #backgroundColors; + #backgroundColorsHover; .animate(background-color); position : relative; display : block; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index f8ac70a5d..d28968df7 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -114,7 +114,7 @@ const EditPage = createClass({ if(htmlErrors.length) htmlErrors = Markdown.validate(text); this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { text: text }), + brew : { ...prevState.brew, text: text }, isPending : true, htmlErrors : htmlErrors }), ()=>this.trySave()); @@ -122,14 +122,17 @@ const EditPage = createClass({ handleStyleChange : function(style){ this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { style: style }), + brew : { ...prevState.brew, style: style }, isPending : true }), ()=>this.trySave()); }, handleMetaChange : function(metadata){ this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, metadata), + brew : { + ...prevState.brew, + ...metadata + }, isPending : true, }), ()=>this.trySave()); @@ -213,11 +216,11 @@ const EditPage = createClass({ history.replaceState(null, null, `/edit/${this.savedBrew.editId}`); this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { + brew : { ...prevState.brew, googleId : this.savedBrew.googleId ? this.savedBrew.googleId : null, editId : this.savedBrew.editId, shareId : this.savedBrew.shareId - }), + }, isPending : false, isSaving : false, })); diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 6947eb031..c70894093 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -52,7 +52,7 @@ const HomePage = createClass({ }, handleTextChange : function(text){ this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { text: text }) + brew : { ...prevState.brew, text: text } })); }, renderNavbar : function(){ diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index ae57039b5..c47e38dc2 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -112,7 +112,7 @@ const NewPage = createClass({ if(htmlErrors.length) htmlErrors = Markdown.validate(text); this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { text: text }), + brew : { ...prevState.brew, text: text }, htmlErrors : htmlErrors })); localStorage.setItem(BREWKEY, text); @@ -120,14 +120,14 @@ const NewPage = createClass({ handleStyleChange : function(style){ this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { style: style }), + brew : { ...prevState.brew, style: style }, })); localStorage.setItem(STYLEKEY, style); }, handleMetaChange : function(metadata){ this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, metadata), + brew : { ...prevState.brew, ...metadata }, })); localStorage.setItem(METAKEY, JSON.stringify({ // 'title' : this.state.brew.title, diff --git a/shared/naturalcrit/nav/nav.less b/shared/naturalcrit/nav/nav.less index f84d11733..43eaa0819 100644 --- a/shared/naturalcrit/nav/nav.less +++ b/shared/naturalcrit/nav/nav.less @@ -50,7 +50,7 @@ nav{ } } .navItem{ - #backgroundColors; + #backgroundColorsHover; .animate(background-color); padding : 8px 12px; cursor : pointer; diff --git a/shared/naturalcrit/styles/colors.less b/shared/naturalcrit/styles/colors.less index 340fb38a7..30a7610a2 100644 --- a/shared/naturalcrit/styles/colors.less +++ b/shared/naturalcrit/styles/colors.less @@ -23,6 +23,29 @@ @grey : #7F8C8D; #backgroundColors { + &.tealLight{ background-color : @tealLight }; + &.teal{ background-color : @teal }; + &.greenLight{ background-color : @greenLight }; + &.green{ background-color : @green }; + &.blueLight{ background-color : @blueLight }; + &.blue{ background-color : @blue }; + &.purpleLight{ background-color : @purpleLight }; + &.purple{ background-color : @purple }; + &.steelLight{ background-color : @steelLight }; + &.steel{ background-color : @steel }; + &.yellowLight{ background-color : @yellowLight }; + &.yellow{ background-color : @yellow }; + &.orangeLight{ background-color : @orangeLight }; + &.orange{ background-color : @orange }; + &.redLight{ background-color : @redLight }; + &.red{ background-color : @red }; + &.silverLight{ background-color : @silverLight }; + &.silver{ background-color : @silver }; + &.greyLight{ background-color : @greyLight }; + &.grey{ background-color : @grey }; +} + +#backgroundColorsHover { &.tealLight:hover{ background-color : @tealLight }; &.teal:hover{ background-color : @teal }; &.greenLight:hover{ background-color : @greenLight };