mirror of
https://github.com/mue/mue.git
synced 2026-07-06 08:01:27 +02:00
refactor(marketplace): Reduce lines
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import variables from 'config/variables';
|
||||
import { useState } from 'react';
|
||||
import placeholderIcon from 'assets/icons/marketplace-placeholder.png';
|
||||
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
|
||||
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
|
||||
import { MdOpenInNew } from "react-icons/md";
|
||||
|
||||
function ItemCard({ item, type, onCollection, isCurator, cardStyle }) {
|
||||
const { getItemData, selectedItem, setSelectedItem } = useMarketData();
|
||||
const { setSubTab } = useTab();
|
||||
|
||||
item._onCollection = onCollection;
|
||||
|
||||
const SelectItem = () => {
|
||||
getItemData(item.type, item.name).then((data) => {
|
||||
setSubTab(data.display_name);
|
||||
});
|
||||
};
|
||||
|
||||
const getName = (name) => {
|
||||
const nameMappings = {
|
||||
photos: 'photo_packs',
|
||||
quotes: 'quote_packs',
|
||||
settings: 'preset_settings',
|
||||
};
|
||||
return nameMappings[name] || name;
|
||||
};
|
||||
|
||||
switch (cardStyle) {
|
||||
case 'list':
|
||||
return (
|
||||
<tr key={item.name} className="py-5 hover:bg-white/5 rounded-lg cursor-pointer" onClick={SelectItem}>
|
||||
<td className="flex flex-row items-center gap-10 py-3">
|
||||
<img
|
||||
className="w-10 h-10 rounded-lg"
|
||||
alt="icon"
|
||||
draggable={false}
|
||||
src={item.icon_url}
|
||||
onError={(e) => {
|
||||
e.target.onerror = null;
|
||||
e.target.src = placeholderIcon;
|
||||
}}
|
||||
/>
|
||||
{item.display_name}
|
||||
</td>
|
||||
<td>{variables.getMessage('marketplace:' + getName(item.type)) || 'marketplace'}</td>
|
||||
<td>{item.author}</td>
|
||||
<td><MdOpenInNew /></td>
|
||||
</tr>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ y: -10 }}
|
||||
transition={{ type: 'spring', stiffness: 150, damping: 15, mass: 0.5 }}
|
||||
className="item"
|
||||
onClick={SelectItem}
|
||||
key={item.name}
|
||||
>
|
||||
<img
|
||||
className="item-back"
|
||||
alt=""
|
||||
draggable={false}
|
||||
src={item.icon_url}
|
||||
onError={(e) => {
|
||||
e.target.onerror = null;
|
||||
e.target.src = placeholderIcon;
|
||||
}}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<img
|
||||
className="item-icon"
|
||||
alt="icon"
|
||||
draggable={false}
|
||||
src={item.icon_url}
|
||||
onError={(e) => {
|
||||
e.target.onerror = null;
|
||||
e.target.src = placeholderIcon;
|
||||
}}
|
||||
/>
|
||||
<div className="card-details">
|
||||
<span className="card-title">{item.display_name || item.name}</span>
|
||||
{!isCurator ? (
|
||||
<span className="card-subtitle">
|
||||
{variables.getMessage('marketplace:by', { author: item.author })}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{type === true && !onCollection ? (
|
||||
<span className="card-type">{variables.getMessage('marketplace:' + item.type)}</span>
|
||||
) : null}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { ItemCard as default, ItemCard };
|
||||
@@ -0,0 +1 @@
|
||||
export * from './ItemCard';
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './Carousel';
|
||||
export * from './SideloadFailedModal';
|
||||
export * from './Lightbox';
|
||||
export * from './ItemCard';
|
||||
|
||||
@@ -1,106 +1,6 @@
|
||||
import variables from 'config/variables';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useState } from 'react';
|
||||
import placeholderIcon from 'assets/icons/marketplace-placeholder.png';
|
||||
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
|
||||
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
|
||||
import { MdOpenInNew } from "react-icons/md";
|
||||
|
||||
function ItemCard({ item, type, onCollection, isCurator, cardStyle }) {
|
||||
const { getItemData, selectedItem, setSelectedItem } = useMarketData();
|
||||
const { setSubTab } = useTab();
|
||||
|
||||
item._onCollection = onCollection;
|
||||
|
||||
const SelectItem = () => {
|
||||
console.log('Item selected: ', item.display_name);
|
||||
console.log('Item type: ', item.type);
|
||||
getItemData(item.type, item.name).then((data) => {
|
||||
console.log('Selected item: ', data);
|
||||
//setSelectedItem(data);
|
||||
setSubTab(data.display_name);
|
||||
});
|
||||
};
|
||||
|
||||
const getName = (name) => {
|
||||
const nameMappings = {
|
||||
photos: 'photo_packs',
|
||||
quotes: 'quote_packs',
|
||||
settings: 'preset_settings',
|
||||
};
|
||||
return nameMappings[name] || name;
|
||||
};
|
||||
|
||||
switch (cardStyle) {
|
||||
case 'list':
|
||||
return (
|
||||
<tr key={item.name} className="py-5 hover:bg-white/5 rounded-lg cursor-pointer" onClick={SelectItem}>
|
||||
<td className="flex flex-row items-center gap-10 py-3">
|
||||
<img
|
||||
className="w-10 h-10 rounded-lg"
|
||||
alt="icon"
|
||||
draggable={false}
|
||||
src={item.icon_url}
|
||||
onError={(e) => {
|
||||
e.target.onerror = null;
|
||||
e.target.src = placeholderIcon;
|
||||
}}
|
||||
/>
|
||||
{item.display_name}
|
||||
</td>
|
||||
<td>{variables.getMessage('marketplace:' + getName(item.type)) || 'marketplace'}</td>
|
||||
<td>{item.author}</td>
|
||||
<td><MdOpenInNew /></td>
|
||||
</tr>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ y: -10 }}
|
||||
transition={{ type: 'spring', stiffness: 150, damping: 15, mass: 0.5 }}
|
||||
className="item"
|
||||
onClick={SelectItem}
|
||||
key={item.name}
|
||||
>
|
||||
<img
|
||||
className="item-back"
|
||||
alt=""
|
||||
draggable={false}
|
||||
src={item.icon_url}
|
||||
onError={(e) => {
|
||||
e.target.onerror = null;
|
||||
e.target.src = placeholderIcon;
|
||||
}}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<img
|
||||
className="item-icon"
|
||||
alt="icon"
|
||||
draggable={false}
|
||||
src={item.icon_url}
|
||||
onError={(e) => {
|
||||
e.target.onerror = null;
|
||||
e.target.src = placeholderIcon;
|
||||
}}
|
||||
/>
|
||||
<div className="card-details">
|
||||
<span className="card-title">{item.display_name || item.name}</span>
|
||||
{!isCurator ? (
|
||||
<span className="card-subtitle">
|
||||
{variables.getMessage('marketplace:by', { author: item.author })}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{type === true && !onCollection ? (
|
||||
<span className="card-type">{variables.getMessage('marketplace:' + item.type)}</span>
|
||||
) : null}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
}
|
||||
import { ItemCard } from 'features/marketplace/components/Elements';
|
||||
|
||||
const NewItems = ({ items, view }) => {
|
||||
const { setSubTab } = useTab();
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
import { memo, useCallback, useEffect, useState } from 'react';
|
||||
import variables from 'config/variables';
|
||||
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
|
||||
import MarketplaceTab from '../../marketplace/views/Browse';
|
||||
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
|
||||
|
||||
|
||||
import { ItemPage } from '../../marketplace/views/ItemPage';
|
||||
import { NewItems as Items } from '../../marketplace/components/Items/Items';
|
||||
|
||||
@@ -13,91 +12,71 @@ import Collection from '../../marketplace/components/Collection/Collection';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { PiGridFourFill } from 'react-icons/pi';
|
||||
import {
|
||||
MdFormatListBulleted,
|
||||
MdFilterListAlt,
|
||||
MdOutlineArrowForward,
|
||||
MdOutlineOpenInNew,
|
||||
} from 'react-icons/md';
|
||||
import { MdFormatListBulleted } from 'react-icons/md';
|
||||
|
||||
const filterTypes = [
|
||||
{ key: 'all', label: 'marketplace:photo_packs' },
|
||||
{ key: 'photo_packs', label: 'marketplace:photo_packs' },
|
||||
{ key: 'quote_packs', label: 'marketplace:quote_packs' },
|
||||
{ key: 'preset_settings', label: 'marketplace:preset_settings' },
|
||||
];
|
||||
|
||||
const filterItems = (items, filter) => {
|
||||
if (filter === 'all') return items;
|
||||
return items.filter((item) => item.type === filter);
|
||||
};
|
||||
|
||||
function Marketplace(props) {
|
||||
const { done, items, collections, getItems, getCollections, selectedItem } = useMarketData();
|
||||
const {
|
||||
done,
|
||||
items = [],
|
||||
collections = [],
|
||||
getItems,
|
||||
getCollections,
|
||||
selectedItem,
|
||||
} = useMarketData();
|
||||
const { subTab } = useTab();
|
||||
const [itemsView, setItemsView] = useState('grid');
|
||||
const [itemsFilter, setItemsFilter] = useState('all');
|
||||
const [filteredItems, setFilteredItems] = useState([]);
|
||||
const [sortItems, setSortItems] = useState('a-z');
|
||||
|
||||
const FilterOptions = () => {
|
||||
return (
|
||||
<div className="flex flex-row gap-2 my-3">
|
||||
<div
|
||||
onClick={() => {
|
||||
setItemsFilter('all');
|
||||
}}
|
||||
className={clsx(
|
||||
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
|
||||
{
|
||||
'bg-white text-black': itemsFilter === 'all',
|
||||
'bg-[#333] hover:bg-[#222222] text-white cursor:pointer': itemsFilter !== 'all',
|
||||
},
|
||||
)}
|
||||
>
|
||||
All
|
||||
</div>
|
||||
<div
|
||||
onClick={() => {
|
||||
setItemsFilter('photo_packs');
|
||||
}}
|
||||
className={clsx(
|
||||
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
|
||||
{
|
||||
'bg-white text-black': itemsFilter === 'photo_packs',
|
||||
'bg-[#333] hover:bg-[#222222] text-white cursor:pointer':
|
||||
itemsFilter !== 'photo_packs',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{variables.getMessage('marketplace:photo_packs') || 'marketplace'}
|
||||
</div>
|
||||
<div
|
||||
onClick={() => {
|
||||
setItemsFilter('quote_packs');
|
||||
}}
|
||||
className={clsx(
|
||||
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
|
||||
{
|
||||
'bg-white text-black': itemsFilter === 'quote_packs',
|
||||
'bg-[#333] hover:bg-[#222222] text-white': itemsFilter !== 'quote_packs',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{variables.getMessage('marketplace:quote_packs') || 'marketplace'}
|
||||
</div>
|
||||
<div
|
||||
onClick={() => {
|
||||
setItemsFilter('preset_settings');
|
||||
}}
|
||||
className={clsx(
|
||||
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
|
||||
{
|
||||
'bg-white text-black': itemsFilter === 'preset_settings',
|
||||
'bg-[#333] hover:bg-[#222222] text-white': itemsFilter !== 'preset_settings',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{variables.getMessage('marketplace:preset_settings') || 'marketplace'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const fetchMarketData = async () => {
|
||||
try {
|
||||
await getItems();
|
||||
await getCollections();
|
||||
} catch (error) {
|
||||
console.error('Error fetching market data:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const ItemView = () => {
|
||||
const FilterOptions = useCallback(() => {
|
||||
return (
|
||||
<div className="flex flex-row gap-2 my-3">
|
||||
{filterTypes.map(({ key, label }) => (
|
||||
<div
|
||||
key={key}
|
||||
onClick={() => setItemsFilter(key)}
|
||||
className={clsx(
|
||||
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base',
|
||||
{
|
||||
'bg-white text-black': itemsFilter === key,
|
||||
'bg-[#333] hover:bg-[#222222] text-white': itemsFilter !== key,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{key !== 'all' ? <>{variables.getMessage(`${label}`) || 'marketplace'}</> : <>All</>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}, [itemsFilter]);
|
||||
|
||||
const ItemView = useCallback(
|
||||
() => (
|
||||
<div className="flex flex-row gap-2">
|
||||
<button
|
||||
onClick={() => setItemsView('grid')}
|
||||
className={clsx('cursor:pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
|
||||
className={clsx('cursor-pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
|
||||
'bg-[#333]': itemsView === 'grid',
|
||||
})}
|
||||
>
|
||||
@@ -105,42 +84,27 @@ function Marketplace(props) {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setItemsView('list')}
|
||||
className={clsx('cursor:pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
|
||||
className={clsx('cursor-pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
|
||||
'bg-[#333]': itemsView === 'list',
|
||||
})}
|
||||
>
|
||||
<MdFormatListBulleted />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
),
|
||||
[itemsView],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
|
||||
return;
|
||||
}
|
||||
getItems();
|
||||
getCollections();
|
||||
}, []); // Only runs once when the component mounts
|
||||
fetchMarketData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
switch (itemsFilter) {
|
||||
case 'all':
|
||||
setFilteredItems(items);
|
||||
break;
|
||||
case 'photo_packs':
|
||||
setFilteredItems(items.filter((item) => item.type === 'photo_packs'));
|
||||
break;
|
||||
case 'quote_packs':
|
||||
setFilteredItems(items.filter((item) => item.type === 'quote_packs'));
|
||||
break;
|
||||
case 'preset_settings':
|
||||
setFilteredItems(items.filter((item) => item.type === 'preset_settings'));
|
||||
break;
|
||||
default:
|
||||
setFilteredItems(items);
|
||||
}
|
||||
}, [itemsFilter, items]); // Only depends on itemsFilter and items
|
||||
setFilteredItems(filterItems(items, itemsFilter));
|
||||
}, [itemsFilter, items]);
|
||||
|
||||
return (
|
||||
<AnimatePresence mode="wait">
|
||||
@@ -156,8 +120,10 @@ function Marketplace(props) {
|
||||
<Collection collections={collections} />
|
||||
<motion.div key="items">
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
{FilterOptions()}
|
||||
<div className="flex flex-row gap-2">{ItemView()}</div>
|
||||
<FilterOptions />
|
||||
<div className="flex flex-row gap-2">
|
||||
<ItemView />
|
||||
</div>
|
||||
</div>
|
||||
<Items items={filteredItems} view={itemsView} />
|
||||
</motion.div>
|
||||
|
||||
@@ -73,7 +73,7 @@ modals:
|
||||
navbar:
|
||||
settings: Settings
|
||||
addons: Library
|
||||
marketplace: Marketplace
|
||||
marketplace: Discover
|
||||
error_boundary:
|
||||
title: Error
|
||||
message: Failed to load this component of Mue
|
||||
|
||||
Reference in New Issue
Block a user