mirror of
https://github.com/mue/mue.git
synced 2026-07-16 05:23:49 +02:00
feat: implement pack enable/disable functionality and improve UI responsiveness
This commit is contained in:
@@ -162,12 +162,17 @@ export async function checkAndRefreshAPIPacks() {
|
||||
export function buildPhotoPool() {
|
||||
const pool = [];
|
||||
const installed = JSON.parse(localStorage.getItem('installed') || '[]');
|
||||
const enabledPacks = JSON.parse(localStorage.getItem('enabledPacks') || '{}');
|
||||
const apiPacksReady = JSON.parse(localStorage.getItem('api_packs_ready') || '[]');
|
||||
const apiPackCache = JSON.parse(localStorage.getItem('api_pack_cache') || '{}');
|
||||
|
||||
installed.forEach((pack) => {
|
||||
if (pack.type !== 'photos') return;
|
||||
|
||||
// Filter by enabled status - default to enabled if not in enabledPacks object
|
||||
const packId = pack.id || pack.name;
|
||||
if (enabledPacks[packId] === false) return;
|
||||
|
||||
if (pack.api_enabled) {
|
||||
// API pack - check if configured and ready
|
||||
if (apiPacksReady.includes(pack.id)) {
|
||||
|
||||
@@ -65,7 +65,9 @@ const SourceSection = ({
|
||||
toggleFunction={onToggle}
|
||||
showCreateYourOwn={false}
|
||||
onUninstall={onPhotoPackUninstall}
|
||||
onTogglePack={() => {}}
|
||||
viewType="grid"
|
||||
showChips={false}
|
||||
/>
|
||||
|
||||
{/* Settings for API packs */}
|
||||
|
||||
@@ -4,7 +4,10 @@ import { MdCheckCircle, MdOutlineUploadFile, MdClose } from 'react-icons/md';
|
||||
import placeholderIcon from 'assets/icons/marketplace-placeholder.png';
|
||||
|
||||
import { Tooltip } from 'components/Elements';
|
||||
import { Button } from 'components/Elements';
|
||||
import Switch from 'components/Form/Settings/Switch/Switch';
|
||||
import Dropdown from '../../../../components/Form/Settings/Dropdown/Dropdown';
|
||||
import EventBus from 'utils/eventbus';
|
||||
import { getProxiedImageUrl } from 'utils/marketplace';
|
||||
|
||||
function filterItems(item, filter, categoryFilter) {
|
||||
@@ -60,32 +63,92 @@ function ItemCard({
|
||||
isInstalled,
|
||||
isAdded,
|
||||
onUninstall,
|
||||
onTogglePack,
|
||||
showChips = true,
|
||||
}) {
|
||||
item._onCollection = onCollection;
|
||||
|
||||
const isSideloaded = item.sideload === true;
|
||||
const packId = item.id || item.name;
|
||||
|
||||
// Use React state to manage enabled status for immediate UI updates
|
||||
const [isEnabled, setIsEnabled] = useState(() => {
|
||||
const enabledPacks = JSON.parse(localStorage.getItem('enabledPacks') || '{}');
|
||||
return enabledPacks[packId] !== false; // Default to enabled if not set
|
||||
});
|
||||
|
||||
const handleTogglePack = (e) => {
|
||||
e.stopPropagation();
|
||||
const newState = !isEnabled;
|
||||
|
||||
// Update local state immediately for UI responsiveness
|
||||
setIsEnabled(newState);
|
||||
|
||||
// Update localStorage
|
||||
const enabledPacks = JSON.parse(localStorage.getItem('enabledPacks') || '{}');
|
||||
enabledPacks[packId] = newState;
|
||||
localStorage.setItem('enabledPacks', JSON.stringify(enabledPacks));
|
||||
|
||||
if (onTogglePack) {
|
||||
onTogglePack(packId, newState);
|
||||
}
|
||||
|
||||
// Emit refresh event for quotes only (background will update on next interval)
|
||||
if (item.type === 'quotes') {
|
||||
EventBus.emit('refresh', 'quote');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`item ${isSideloaded ? 'item-sideloaded' : ''}`}
|
||||
className={`item ${isSideloaded ? 'item-sideloaded' : ''} ${!isEnabled && isAdded ? 'item-disabled' : ''}`}
|
||||
onClick={isSideloaded ? undefined : () => toggleFunction(item)}
|
||||
key={item.name}
|
||||
>
|
||||
{isAdded && onUninstall && (
|
||||
<Tooltip
|
||||
title={variables.getMessage('modals.main.marketplace.product.buttons.remove')}
|
||||
{isAdded && onTogglePack && (
|
||||
<div
|
||||
className="item-toggle-switch"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{ position: 'absolute', top: '12px', right: '12px', zIndex: 3 }}
|
||||
>
|
||||
<button
|
||||
className="item-uninstall-btn"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onUninstall(item.type, item.name);
|
||||
}}
|
||||
>
|
||||
<MdClose />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<label className="switch-track" style={{ cursor: 'pointer' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isEnabled}
|
||||
onChange={handleTogglePack}
|
||||
style={{ display: 'none' }}
|
||||
/>
|
||||
<div
|
||||
className={`switch-track ${isEnabled ? 'checked' : ''}`}
|
||||
style={{
|
||||
width: '52px',
|
||||
height: '32px',
|
||||
borderRadius: '16px',
|
||||
backgroundColor: isEnabled
|
||||
? 'var(--linkColor, #5298ff)'
|
||||
: 'rgba(128, 128, 128, 0.3)',
|
||||
position: 'relative',
|
||||
transition: 'background-color 0.2s',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="switch-thumb"
|
||||
style={{
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'white',
|
||||
position: 'absolute',
|
||||
top: '4px',
|
||||
left: isEnabled ? '24px' : '4px',
|
||||
transition: 'left 0.2s',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{isSideloaded && (
|
||||
<Tooltip
|
||||
@@ -128,18 +191,33 @@ function ItemCard({
|
||||
''
|
||||
)}
|
||||
|
||||
<div className="card-chips">
|
||||
{item.type && (
|
||||
<span className="card-type">
|
||||
{variables.getMessage('modals.main.marketplace.' + getTypeTranslationKey(item.type))}
|
||||
</span>
|
||||
)}
|
||||
{item.in_collections && item.in_collections.length > 0 && !onCollection && (
|
||||
<span className="card-collection">
|
||||
{item.in_collections[0].display_name || item.in_collections[0].name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{showChips && (
|
||||
<div className="card-chips">
|
||||
{item.type && (
|
||||
<span className="card-type">
|
||||
{variables.getMessage('modals.main.marketplace.' + getTypeTranslationKey(item.type))}
|
||||
</span>
|
||||
)}
|
||||
{item.in_collections && item.in_collections.length > 0 && !onCollection && (
|
||||
<span className="card-collection">
|
||||
{item.in_collections[0].display_name || item.in_collections[0].name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isAdded && onUninstall && (
|
||||
<Button
|
||||
type="settings"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onUninstall(item.type, item.name);
|
||||
}}
|
||||
icon={<MdClose />}
|
||||
label={variables.getMessage('modals.main.marketplace.product.buttons.remove')}
|
||||
style={{ marginTop: '10px', width: '100%' }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -156,7 +234,9 @@ function Items({
|
||||
onSortChange,
|
||||
isAdded = false,
|
||||
onUninstall,
|
||||
onTogglePack,
|
||||
viewType = 'grid',
|
||||
showChips = true,
|
||||
}) {
|
||||
const [selectedCategory, setSelectedCategory] = useState('all');
|
||||
const [sortType, setSortType] = useState(localStorage.getItem('sortMarketplace') || 'a-z');
|
||||
@@ -222,6 +302,8 @@ function Items({
|
||||
isInstalled={installedNames.has(item.name)}
|
||||
isAdded={isAdded}
|
||||
onUninstall={onUninstall}
|
||||
onTogglePack={onTogglePack}
|
||||
showChips={showChips}
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -114,9 +114,7 @@ export function useQuoteLoader(updateQuote) {
|
||||
}
|
||||
|
||||
// Filter out incomplete quotes (empty quote text)
|
||||
const validQuotes = customQuote?.filter(
|
||||
(q) => q.quote && q.quote.trim() !== ''
|
||||
) || [];
|
||||
const validQuotes = customQuote?.filter((q) => q.quote && q.quote.trim() !== '') || [];
|
||||
|
||||
if (validQuotes.length === 0) {
|
||||
return { noQuote: true };
|
||||
@@ -144,8 +142,14 @@ export function useQuoteLoader(updateQuote) {
|
||||
}
|
||||
|
||||
const installed = JSON.parse(localStorage.getItem('installed') || '[]');
|
||||
const enabledPacks = JSON.parse(localStorage.getItem('enabledPacks') || '{}');
|
||||
const quotePack = installed
|
||||
.filter((item) => item.type === 'quotes')
|
||||
.filter((item) => {
|
||||
if (item.type !== 'quotes') return false;
|
||||
const packId = item.id || item.name;
|
||||
// Default to enabled if not in enabledPacks object
|
||||
return enabledPacks[packId] !== false;
|
||||
})
|
||||
.flatMap((item) =>
|
||||
item.quotes.map((quote) => ({
|
||||
...quote,
|
||||
|
||||
@@ -359,7 +359,9 @@ const QuoteOptions = ({ currentSubSection, onSubSectionChange, sectionName }) =>
|
||||
<>
|
||||
<Row final={true}>
|
||||
<Content
|
||||
title={variables.getMessage('modals.main.settings.sections.quote.installed_packs_title')}
|
||||
title={variables.getMessage(
|
||||
'modals.main.settings.sections.quote.installed_packs_title',
|
||||
)}
|
||||
subtitle={`${installedQuotePacks.length} ${installedQuotePacks.length === 1 ? 'pack' : 'packs'} • ${totalQuotes} ${totalQuotes === 1 ? 'quote' : 'quotes'}`}
|
||||
/>
|
||||
<Action>
|
||||
@@ -378,7 +380,9 @@ const QuoteOptions = ({ currentSubSection, onSubSectionChange, sectionName }) =>
|
||||
toggleFunction={handleToggle}
|
||||
showCreateYourOwn={false}
|
||||
onUninstall={handleUninstall}
|
||||
onTogglePack={() => {}}
|
||||
viewType="grid"
|
||||
showChips={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user