diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx index 90f9d32f2..0369305d5 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx @@ -20,7 +20,8 @@ const BrewItem = createClass({ authors : [], stubbed : true }, - reportError : ()=>{} + updateListFilter : ()=>{}, + reportError : ()=>{} }; }, @@ -44,6 +45,10 @@ const BrewItem = createClass({ }); }, + updateFilter : function(type, term){ + this.props.updateListFilter(type, term); + }, + renderDeleteBrewLink : function(){ if(!this.props.brew.editId) return; @@ -109,6 +114,9 @@ const BrewItem = createClass({ const brew = this.props.brew; if(Array.isArray(brew.tags)) { // temporary fix until dud tags are cleaned brew.tags = brew.tags?.filter((tag)=>tag); //remove tags that are empty strings + brew.tags.sort((a, b)=>{ + return a.indexOf(':') - b.indexOf(':') != 0 ? a.indexOf(':') - b.indexOf(':') : a.toLowerCase().localeCompare(b.toLowerCase()); + }); } const dateFormatString = 'YYYY-MM-DD HH:mm:ss'; @@ -129,7 +137,7 @@ const BrewItem = createClass({ {brew.tags.map((tag, idx)=>{ const matches = tag.match(/^(?:([^:]+):)?([^:]+)$/); - return {matches[2]}; + return {this.updateFilter(tag);}}>{matches[2]}; })} : <> diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less index 5a1bb3d92..9bee4e5eb 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less @@ -63,6 +63,41 @@ white-space: nowrap; display: inline-block; font-weight: bold; + border-color: currentColor; + cursor : pointer; + &:before { + font-family: 'Font Awesome 5 Free'; + font-size: 12px; + margin-right: 3px; + } + &.type { + background-color: #0080003b; + color: #008000; + &:before{ + content: '\f0ad'; + } + } + &.group { + background-color: #5050503b; + color: #000000; + &:before{ + content: '\f500'; + } + } + &.meta { + background-color: #0000803b; + color: #000080; + &:before{ + content: '\f05a'; + } + } + &.system { + background-color: #8000003b; + color: #800000; + &:before{ + content: '\f518'; + } + } } &:hover{ .links{ diff --git a/client/homebrew/pages/basePages/listPage/listPage.jsx b/client/homebrew/pages/basePages/listPage/listPage.jsx index d0cd11ec6..2385b4490 100644 --- a/client/homebrew/pages/basePages/listPage/listPage.jsx +++ b/client/homebrew/pages/basePages/listPage/listPage.jsx @@ -36,6 +36,7 @@ const ListPage = createClass({ return { filterString : this.props.query?.filter || '', + filterTags : [], sortType : this.props.query?.sort || null, sortDir : this.props.query?.dir || null, query : this.props.query, @@ -82,7 +83,7 @@ const ListPage = createClass({ if(!brews || !brews.length) return
No Brews.
; return _.map(brews, (brew, idx)=>{ - return ; + return { this.updateUrl(this.state.filterString, this.state.sortType, this.state.sortDir, tag); }}/>; }); }, @@ -136,13 +137,33 @@ const ListPage = createClass({ return; }, - updateUrl : function(filterTerm, sortType, sortDir){ + updateUrl : function(filterTerm, sortType, sortDir, filterTag=''){ const url = new URL(window.location.href); const urlParams = new URLSearchParams(url.search); urlParams.set('sort', sortType); urlParams.set('dir', sortDir); + let filterTags = urlParams.getAll('tag'); + if(filterTag != '') { + if(filterTags.findIndex((tag)=>{return tag.toLowerCase()==filterTag.toLowerCase();}) == -1){ + filterTags.push(filterTag); + } else { + filterTags = filterTags.filter((tag)=>{ return tag.toLowerCase() != filterTag.toLowerCase(); }); + } + } + urlParams.delete('tag'); + // Add tags to URL in the order they were clicked + filterTags.forEach((tag)=>{ urlParams.append('tag', tag); }); + // Sort tags before updating state + filterTags.sort((a, b)=>{ + return a.indexOf(':') - b.indexOf(':') != 0 ? a.indexOf(':') - b.indexOf(':') : a.toLowerCase().localeCompare(b.toLowerCase()); + }); + + this.setState({ + filterTags + }); + if(!filterTerm) urlParams.delete('filter'); else @@ -166,6 +187,16 @@ const ListPage = createClass({ ; }, + renderTagsOptions : function(){ + if(this.state.filterTags?.length == 0) return; + return
+ {_.map(this.state.filterTags, (tag, idx)=>{ + const matches = tag.match(/^(?:([^:]+):)?([^:]+)$/); + return { this.updateUrl(this.state.filterString, this.state.sortType, this.state.sortDir, tag); }}>{matches[2]}; + })} +
; + }, + renderSortOptions : function(){ return
Sort by :
@@ -176,9 +207,6 @@ const ListPage = createClass({ {/* {this.renderSortOption('Latest', 'latest')} */} {this.renderFilterOption()} - - -
; }, @@ -186,14 +214,28 @@ const ListPage = createClass({ const testString = _.deburr(this.state.filterString).toLowerCase(); brews = _.filter(brews, (brew)=>{ + // Filter by user entered text const brewStrings = _.deburr([ brew.title, brew.description, brew.tags].join('\n') .toLowerCase()); - return brewStrings.includes(testString); + const filterTextTest = brewStrings.includes(testString); + + // Filter by user selected tags + let filterTagTest = true; + if(this.state.filterTags.length > 0){ + filterTagTest = Array.isArray(brew.tags) && this.state.filterTags?.every((tag)=>{ + return brew.tags.findIndex((brewTag)=>{ + return brewTag.toLowerCase() == tag.toLowerCase(); + }) >= 0; + }); + } + + return filterTextTest && filterTagTest; }); + return _.orderBy(brews, (brew)=>{ return this.sortBrewOrder(brew); }, this.state.sortDir); }, @@ -224,6 +266,7 @@ const ListPage = createClass({ {this.props.navItems} {this.renderSortOptions()} + {this.renderTagsOptions()}
diff --git a/client/homebrew/pages/basePages/listPage/listPage.less b/client/homebrew/pages/basePages/listPage/listPage.less index 00d753429..0aa4a278d 100644 --- a/client/homebrew/pages/basePages/listPage/listPage.less +++ b/client/homebrew/pages/basePages/listPage/listPage.less @@ -53,7 +53,7 @@ } } } - .sort-container{ + .sort-container { font-family : 'Open Sans', sans-serif; position : sticky; top : 0; @@ -125,4 +125,66 @@ } + .tags-container { + height : 30px; + background-color : #555; + border-top : 1px solid #666; + border-bottom : 1px solid #666; + color : white; + display : flex; + justify-content : center; + align-items : center; + column-gap : 15px; + row-gap : 5px; + flex-wrap : wrap; + span { + font-family : 'Open Sans', sans-serif; + font-size : 11px; + font-weight : bold; + border : 1px solid; + border-radius : 3px; + padding : 3px; + cursor : pointer; + color: #dfdfdf; + &:before { + font-family: 'Font Awesome 5 Free'; + font-size: 12px; + margin-right: 3px; + } + &:after { + content: '\f00d'; + font-family: 'Font Awesome 5 Free'; + font-size: 12px; + margin-left: 3px; + } + &.type { + background-color: #008000; + border-color: #00a000; + &:before{ + content: '\f0ad'; + } + } + &.group { + background-color: #505050; + border-color: #000000; + &:before{ + content: '\f500'; + } + } + &.meta { + background-color: #000080; + border-color: #0000a0; + &:before{ + content: '\f05a'; + } + } + &.system { + background-color: #800000; + border-color: #a00000; + &:before{ + content: '\f518'; + } + } + } + } }