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';
+ }
+ }
+ }
+ }
}