feat(marketplace): add filter options and sorting functionality to Items component

This commit is contained in:
alexsparkes
2025-10-30 23:33:06 +00:00
parent 9c477e3980
commit 3f9e3e5d59
3 changed files with 129 additions and 19 deletions

View File

@@ -517,3 +517,60 @@ p.author {
margin-bottom: 0 !important;
}
}
.filter-options-container {
display: flex;
flex-flow: row;
gap: 20px;
margin: 20px 0;
align-items: center;
justify-content: space-between;
}
.filter-chips {
display: flex;
flex-flow: row;
gap: 12px;
align-items: center;
.filter-chip {
all: unset;
padding: 8px 20px;
border-radius: 24px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
white-space: nowrap;
user-select: none;
@include themed {
background-color: t($modal-sidebarActive);
color: t($color);
}
&:hover {
@include themed {
background-color: rgba(255, 255, 255, 0.15);
}
}
&.active {
@include themed {
background-color: #fff;
color: #000;
}
&:hover {
@include themed {
background-color: #f0f0f0;
}
}
}
&:focus-visible {
outline: 2px solid rgba(255, 255, 255, 0.5);
outline-offset: 2px;
}
}
}

View File

@@ -1,18 +1,31 @@
import variables from 'config/variables';
import React, { memo } from 'react';
import React, { memo, useState } from 'react';
import { MdAutoFixHigh, MdOutlineArrowForward, MdOutlineOpenInNew } from 'react-icons/md';
import placeholderIcon from 'assets/icons/marketplace-placeholder.png';
import { Button } from 'components/Elements';
import Dropdown from '../../../../components/Form/Settings/Dropdown/Dropdown';
function filterItems(item, filter) {
function filterItems(item, filter, categoryFilter) {
const lowerCaseFilter = filter.toLowerCase();
return (
const textMatch =
item.name?.toLowerCase().includes(lowerCaseFilter) ||
filter === '' ||
item.author?.toLowerCase().includes(lowerCaseFilter) ||
item.type?.toLowerCase().includes(lowerCaseFilter)
);
item.type?.toLowerCase().includes(lowerCaseFilter);
// Apply category filter
if (categoryFilter === 'all') {
return textMatch;
}
const categoryMap = {
quotes: 'quote_packs',
photos: 'photo_packs',
presets: 'preset_settings',
};
return textMatch && item.type === categoryMap[categoryFilter];
}
function ItemCard({ item, toggleFunction, type, onCollection, isCurator }) {
@@ -71,7 +84,27 @@ function Items({
filter,
moreByCreator,
showCreateYourOwn,
filterOptions = false,
onSortChange,
}) {
const [selectedCategory, setSelectedCategory] = useState('all');
const [sortType, setSortType] = useState(localStorage.getItem('sortMarketplace') || 'a-z');
const filterCategories = [
{ id: 'all', label: 'All' },
{ id: 'quotes', label: 'Quotes' },
{ id: 'photos', label: 'Photos' },
{ id: 'presets', label: 'Presets' },
];
const handleSortChange = (value) => {
setSortType(value);
localStorage.setItem('sortMarketplace', value);
if (onSortChange) {
onSortChange(value);
}
};
const shouldShowCollection =
((collection && !onCollection && (filter === null || filter === '')) ||
(type === 'collections' && !onCollection && (filter === null || filter === ''))) &&
@@ -114,9 +147,34 @@ function Items({
)}
</div>
)}
{/* Items Filter Options */}
{filterOptions && (
<div className="filter-options-container">
<div className="filter-chips">
{filterCategories.map((category) => (
<button
key={category.id}
className={`filter-chip ${selectedCategory === category.id ? 'active' : ''}`}
onClick={() => setSelectedCategory(category.id)}
>
{category.label}
</button>
))}
</div>
<Dropdown
label={variables.getMessage('modals.main.addons.sort.title')}
name="sortMarketplace"
onChange={(value) => handleSortChange(value)}
items={[
{ value: 'a-z', text: variables.getMessage('modals.main.addons.sort.a_z') },
{ value: 'z-a', text: variables.getMessage('modals.main.addons.sort.z_a') },
]}
/>
</div>
)}
<div className={`items ${moreByCreator ? 'creatorItems' : ''}`}>
{items
?.filter((item) => filterItems(item, filter))
?.filter((item) => filterItems(item, filter, filterOptions ? selectedCategory : 'all'))
.map((item, index) => (
<ItemCard
isCurator={isCurator}

View File

@@ -12,7 +12,6 @@ import {
import ItemPage from './ItemPage';
import Items from '../components/Items/Items';
import Dropdown from '../../../components/Form/Settings/Dropdown/Dropdown';
import { Header } from 'components/Layout/Settings';
import { Button } from 'components/Elements';
@@ -355,7 +354,10 @@ class Marketplace extends PureComponent {
componentDidUpdate(prevProps) {
// Handle navigation trigger changes
if (this.props.navigationTrigger && this.props.navigationTrigger !== prevProps.navigationTrigger) {
if (
this.props.navigationTrigger &&
this.props.navigationTrigger !== prevProps.navigationTrigger
) {
const { type, data } = this.props.navigationTrigger;
if (type === 'product' && data) {
@@ -478,11 +480,11 @@ class Marketplace extends PureComponent {
</>
) : (
<>
<div className="flexTopMarketplace">
{/* <div className="flexTopMarketplace">
<span className="mainTitle">
{variables.getMessage('modals.main.navbar.marketplace')}
</span>
</div>
</div> */}
<div className="headerExtras marketplaceCondition">
{this.props.type !== 'collections' && (
<div>
@@ -499,15 +501,6 @@ class Marketplace extends PureComponent {
</form>
</div>
)}
<Dropdown
label={variables.getMessage('modals.main.addons.sort.title')}
name="sortMarketplace"
onChange={(value) => this.changeSort(value)}
items={[
{ value: 'a-z', text: variables.getMessage('modals.main.addons.sort.a_z') },
{ value: 'z-a', text: variables.getMessage('modals.main.addons.sort.z_a') },
]}
/>
</div>
</>
)}
@@ -541,6 +534,7 @@ class Marketplace extends PureComponent {
)
) : (
<Items
filterOptions={true}
type={this.props.type}
items={this.state.items}
collection={this.state.displayedCollection}
@@ -548,6 +542,7 @@ class Marketplace extends PureComponent {
toggleFunction={(input) => this.toggle('item', input)}
collectionFunction={(input) => this.toggle('collection', input)}
filter={this.state.filter}
onSortChange={(value) => this.changeSort(value)}
showCreateYourOwn={true}
/>
)}