ui improvement + fix search card in deck manager that leaded to a crash when card was found
This commit is contained in:
@@ -82,7 +82,7 @@ define(['./workbox-ca84f546'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.8gqbvnk5km4"
|
"revision": "0.bbuf8ja4298"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function AppContent() {
|
|||||||
switch (currentPage) {
|
switch (currentPage) {
|
||||||
case 'home':
|
case 'home':
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-900 text-white p-3 sm:p-6 animate-fade-in">
|
<div className="relative bg-gray-900 text-white p-3 sm:p-6 animate-fade-in md:min-h-screen">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<h1 className="text-2xl md:text-3xl font-bold mb-4 md:mb-6 animate-slide-in-left">My Decks</h1>
|
<h1 className="text-2xl md:text-3xl font-bold mb-4 md:mb-6 animate-slide-in-left">My Decks</h1>
|
||||||
<DeckList
|
<DeckList
|
||||||
@@ -78,10 +78,12 @@ function AppContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-900">
|
<div className="min-h-screen bg-gray-900 flex flex-col">
|
||||||
<Navigation currentPage={currentPage} setCurrentPage={setCurrentPage} />
|
<Navigation currentPage={currentPage} setCurrentPage={setCurrentPage} />
|
||||||
<main className="pt-0 pb-20 md:pt-16 md:pb-0">
|
<main className="relative flex-1 overflow-y-auto pt-0 md:pt-16">
|
||||||
|
<div className="relative min-h-full pb-20 md:pb-0">
|
||||||
{renderPage()}
|
{renderPage()}
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<PWAInstallPrompt />
|
<PWAInstallPrompt />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ const CardSearch = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-900 text-white p-3 sm:p-6">
|
<div className="relative bg-gray-900 text-white p-3 sm:p-6 md:min-h-screen">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<h1 className="text-2xl md:text-3xl font-bold mb-4 md:mb-6">Card Search</h1>
|
<h1 className="text-2xl md:text-3xl font-bold mb-4 md:mb-6">Card Search</h1>
|
||||||
<form onSubmit={handleSearch} className="mb-8 space-y-4">
|
<form onSubmit={handleSearch} className="mb-8 space-y-4">
|
||||||
@@ -774,7 +774,7 @@ const CardSearch = () => {
|
|||||||
<div
|
<div
|
||||||
className={`fixed bottom-4 right-4 p-4 rounded-lg shadow-lg transition-all duration-300 ${
|
className={`fixed bottom-4 right-4 p-4 rounded-lg shadow-lg transition-all duration-300 ${
|
||||||
snackbar.type === 'success' ? 'bg-green-500' : 'bg-red-500'
|
snackbar.type === 'success' ? 'bg-green-500' : 'bg-red-500'
|
||||||
} text-white z-50`}
|
} text-white z-[140]`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ export default function Collection() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-900 text-white p-3 sm:p-6">
|
<div className="relative bg-gray-900 text-white p-3 sm:p-6 md:min-h-screen">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<h1 className="text-2xl md:text-3xl font-bold mb-4 md:mb-6">My Collection</h1>
|
<h1 className="text-2xl md:text-3xl font-bold mb-4 md:mb-6">My Collection</h1>
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@ export default function Collection() {
|
|||||||
const displayOracleText = currentFace?.oracle_text || hoveredCard.oracle_text;
|
const displayOracleText = currentFace?.oracle_text || hoveredCard.oracle_text;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="hidden lg:block fixed top-1/2 right-8 transform -translate-y-1/2 z-40 pointer-events-none">
|
<div className="hidden lg:block fixed top-1/2 right-8 transform -translate-y-1/2 z-30 pointer-events-none">
|
||||||
<div className="bg-gray-800 rounded-lg shadow-2xl p-4 max-w-md">
|
<div className="bg-gray-800 rounded-lg shadow-2xl p-4 max-w-md">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
@@ -344,16 +344,16 @@ export default function Collection() {
|
|||||||
<>
|
<>
|
||||||
{/* Backdrop */}
|
{/* Backdrop */}
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 bg-black bg-opacity-50 z-40 transition-opacity duration-300"
|
className="fixed inset-0 bg-black bg-opacity-50 z-[110] transition-opacity duration-300"
|
||||||
onClick={() => setSelectedCard(null)}
|
onClick={() => setSelectedCard(null)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Sliding Panel */}
|
{/* Sliding Panel */}
|
||||||
<div className="fixed top-0 right-0 h-full w-full md:w-96 bg-gray-800 shadow-2xl z-50 overflow-y-auto animate-slide-in-right">
|
<div className="fixed top-0 right-0 h-full w-full md:w-96 bg-gray-800 shadow-2xl z-[120] overflow-y-auto animate-slide-in-right">
|
||||||
{/* Close button - fixed position, stays visible when scrolling */}
|
{/* Close button - fixed position, stays visible when scrolling */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setSelectedCard(null)}
|
onClick={() => setSelectedCard(null)}
|
||||||
className="fixed top-4 right-4 bg-gray-700 hover:bg-gray-600 text-white p-2 md:p-1.5 rounded-full transition-colors z-[60] shadow-lg"
|
className="fixed top-4 right-4 bg-gray-700 hover:bg-gray-600 text-white p-2 md:p-1.5 rounded-full transition-colors z-[130] shadow-lg"
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
>
|
>
|
||||||
<X size={24} className="md:w-5 md:h-5" />
|
<X size={24} className="md:w-5 md:h-5" />
|
||||||
@@ -478,7 +478,7 @@ export default function Collection() {
|
|||||||
<div
|
<div
|
||||||
className={`fixed bottom-4 right-4 p-4 rounded-lg shadow-lg transition-all duration-300 ${
|
className={`fixed bottom-4 right-4 p-4 rounded-lg shadow-lg transition-all duration-300 ${
|
||||||
snackbar.type === 'success' ? 'bg-green-500' : 'bg-red-500'
|
snackbar.type === 'success' ? 'bg-green-500' : 'bg-red-500'
|
||||||
} text-white z-50`}
|
} text-white z-[140]`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ export default function Community() {
|
|||||||
|
|
||||||
// ============ MAIN VIEW ============
|
// ============ MAIN VIEW ============
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-900 text-white min-h-screen">
|
<div className="relative bg-gray-900 text-white md:min-h-screen">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="sticky top-0 bg-gray-900/95 backdrop-blur border-b border-gray-800 p-3 z-10">
|
<div className="sticky top-0 bg-gray-900/95 backdrop-blur border-b border-gray-800 p-3 z-10">
|
||||||
<h1 className="text-xl font-bold mb-3">Community</h1>
|
<h1 className="text-xl font-bold mb-3">Community</h1>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default function DeckBuilder({
|
|||||||
initial={{ x: "100%" }}
|
initial={{ x: "100%" }}
|
||||||
animate={{ x: isOpen ? "0%" : "100%" }}
|
animate={{ x: isOpen ? "0%" : "100%" }}
|
||||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||||
className="fixed top-0 right-0 w-4/5 h-full bg-gray-800 p-6 shadow-lg md:static md:w-full md:h-auto md:p-6 md:shadow-none z-50"
|
className="fixed top-0 right-0 w-4/5 h-full bg-gray-800 p-6 shadow-lg md:static md:w-full md:h-auto md:p-6 md:shadow-none z-[110]"
|
||||||
>
|
>
|
||||||
{/* Bouton de fermeture */}
|
{/* Bouton de fermeture */}
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export default function DeckEditor({ deckId, onClose }: DeckEditorProps) {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-900 text-white p-6 flex items-center justify-center">
|
<div className="relative md:min-h-screen bg-gray-900 text-white p-6 flex items-center justify-center">
|
||||||
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-blue-500"></div>
|
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-blue-500"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -70,7 +70,7 @@ export default function DeckEditor({ deckId, onClose }: DeckEditorProps) {
|
|||||||
|
|
||||||
if (!deck) {
|
if (!deck) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-900 text-white p-6">
|
<div className="relative md:min-h-screen bg-gray-900 text-white p-6">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<div className="bg-red-500/10 border border-red-500 rounded-lg p-4">
|
<div className="bg-red-500/10 border border-red-500 rounded-lg p-4">
|
||||||
<h2 className="text-xl font-bold text-red-500">Error</h2>
|
<h2 className="text-xl font-bold text-red-500">Error</h2>
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
const [currentDeckId, setCurrentDeckId] = useState<string | null>(initialDeck?.id || null);
|
const [currentDeckId, setCurrentDeckId] = useState<string | null>(initialDeck?.id || null);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [searchResults, setSearchResults] = useState<Card[]>([]);
|
const [searchResults, setSearchResults] = useState<Card[]>([]);
|
||||||
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
const [selectedCards, setSelectedCards] = useState<{
|
const [selectedCards, setSelectedCards] = useState<{
|
||||||
card: Card;
|
card: Card;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
@@ -296,11 +297,16 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!searchQuery.trim()) return;
|
if (!searchQuery.trim()) return;
|
||||||
|
|
||||||
|
setIsSearching(true);
|
||||||
try {
|
try {
|
||||||
const cards = await searchCards(searchQuery);
|
const cards = await searchCards(searchQuery);
|
||||||
setSearchResults(cards);
|
setSearchResults(cards || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to search cards:', error);
|
console.error('Failed to search cards:', error);
|
||||||
|
setSearchResults([]);
|
||||||
|
setSnackbar({ message: 'Failed to search cards', type: 'error' });
|
||||||
|
} finally {
|
||||||
|
setIsSearching(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -538,7 +544,7 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-900 text-white p-3 sm:p-6 pt-6 pb-20 md:pt-20 md:pb-6">
|
<div className="relative bg-gray-900 text-white p-3 sm:p-6 pt-6 pb-44 md:pt-20 md:pb-6 md:min-h-screen">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||||
{/* Card Search Section */}
|
{/* Card Search Section */}
|
||||||
@@ -575,7 +581,17 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
|
|
||||||
{/* Vertical Card List for Mobile */}
|
{/* Vertical Card List for Mobile */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{searchResults.map(card => {
|
{isSearching ? (
|
||||||
|
<div className="flex items-center justify-center py-12">
|
||||||
|
<Loader2 className="animate-spin text-blue-500" size={48} />
|
||||||
|
</div>
|
||||||
|
) : searchResults.length === 0 && searchQuery ? (
|
||||||
|
<div className="text-center py-12 text-gray-400">
|
||||||
|
<p className="text-lg mb-2">No cards found</p>
|
||||||
|
<p className="text-sm">Try a different search term</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
searchResults.map(card => {
|
||||||
const currentFaceIndex = getCurrentFaceIndex(card.id);
|
const currentFaceIndex = getCurrentFaceIndex(card.id);
|
||||||
const isMultiFaced = isDoubleFaced(card);
|
const isMultiFaced = isDoubleFaced(card);
|
||||||
const inCollection = userCollection.get(card.id) || 0;
|
const inCollection = userCollection.get(card.id) || 0;
|
||||||
@@ -702,7 +718,8 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -876,10 +893,6 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="font-bold text-xl">
|
|
||||||
Total Price: ${totalPrice.toFixed(2)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{deckSize > 0 && suggestedLandCountValue > 0 && (
|
{deckSize > 0 && suggestedLandCountValue > 0 && (
|
||||||
<div className="bg-gray-700 rounded-lg p-3">
|
<div className="bg-gray-700 rounded-lg p-3">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
@@ -906,19 +919,34 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Fixed Footer with Price and Actions - Mobile First */}
|
||||||
|
<div className="fixed bottom-16 left-0 right-0 md:left-auto md:right-4 md:bottom-4 md:w-80 z-20 bg-gray-800 border-t border-gray-700 md:border md:rounded-lg shadow-2xl">
|
||||||
|
<div className="p-3 space-y-3">
|
||||||
|
{/* Total Price */}
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="text-sm font-semibold text-gray-300">Total Price</span>
|
||||||
|
<span className="text-xl font-bold text-green-400">${totalPrice.toFixed(2)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action Buttons */}
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{!isLoadingCollection && getMissingCards().length > 0 && (
|
{!isLoadingCollection && getMissingCards().length > 0 && (
|
||||||
<button
|
<button
|
||||||
onClick={handleAddAllMissingCards}
|
onClick={handleAddAllMissingCards}
|
||||||
disabled={isAddingAll}
|
disabled={isAddingAll}
|
||||||
className="flex-1 px-4 py-2 bg-yellow-600 hover:bg-yellow-700 disabled:bg-gray-600 disabled:cursor-not-allowed rounded-lg flex items-center justify-center gap-2"
|
className="flex-1 px-3 py-2 bg-yellow-600 hover:bg-yellow-700 disabled:bg-gray-600 disabled:cursor-not-allowed rounded-lg flex items-center justify-center gap-2 text-sm font-medium transition-colors"
|
||||||
title="Add missing cards to collection"
|
title="Add missing cards to collection"
|
||||||
>
|
>
|
||||||
{isAddingAll ? (
|
{isAddingAll ? (
|
||||||
<Loader2 className="animate-spin" size={20} />
|
<Loader2 className="animate-spin" size={18} />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<PackagePlus size={20} />
|
<PackagePlus size={18} />
|
||||||
<span className="hidden sm:inline">Add Missing</span>
|
<span className="hidden sm:inline">Add Missing</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -929,25 +957,23 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
disabled={
|
disabled={
|
||||||
!deckName.trim() || selectedCards.length === 0 || isSaving
|
!deckName.trim() || selectedCards.length === 0 || isSaving
|
||||||
}
|
}
|
||||||
className="flex-1 px-4 py-2 bg-green-600 hover:bg-green-700 disabled:bg-gray-600 disabled:cursor-not-allowed rounded-lg flex items-center justify-center gap-2 relative"
|
className="flex-1 px-3 py-2 bg-green-600 hover:bg-green-700 disabled:bg-gray-600 disabled:cursor-not-allowed rounded-lg flex items-center justify-center gap-2 text-sm font-medium relative transition-colors"
|
||||||
>
|
>
|
||||||
{isSaving ? (
|
{isSaving ? (
|
||||||
<>
|
<>
|
||||||
<Loader2 className="animate-spin text-white absolute left-2 top-1/2 -translate-y-1/2" size={20} />
|
<Loader2 className="animate-spin text-white" size={18} />
|
||||||
<span className="opacity-0">Save Deck</span>
|
<span>Saving...</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Save size={20} />
|
<Save size={18} />
|
||||||
<span>{initialDeck ? 'Update Deck' : 'Save Deck'}</span>
|
<span>{initialDeck ? 'Update' : 'Save'}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Hover Card Preview - only show if no card is selected */}
|
{/* Hover Card Preview - only show if no card is selected */}
|
||||||
{hoveredCard && !selectedCard && (() => {
|
{hoveredCard && !selectedCard && (() => {
|
||||||
@@ -962,7 +988,7 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
const displayOracleText = currentFace?.oracle_text || hoveredCard.oracle_text;
|
const displayOracleText = currentFace?.oracle_text || hoveredCard.oracle_text;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="hidden lg:block fixed top-1/2 right-8 transform -translate-y-1/2 z-40 pointer-events-none">
|
<div className="hidden lg:block fixed top-1/2 right-8 transform -translate-y-1/2 z-30 pointer-events-none">
|
||||||
<div className="bg-gray-800 rounded-lg shadow-2xl p-4 max-w-md">
|
<div className="bg-gray-800 rounded-lg shadow-2xl p-4 max-w-md">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
@@ -1011,16 +1037,16 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
<>
|
<>
|
||||||
{/* Backdrop */}
|
{/* Backdrop */}
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 bg-black bg-opacity-50 z-40 transition-opacity duration-300"
|
className="fixed inset-0 bg-black bg-opacity-50 z-[110] transition-opacity duration-300"
|
||||||
onClick={() => setSelectedCard(null)}
|
onClick={() => setSelectedCard(null)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Sliding Panel */}
|
{/* Sliding Panel */}
|
||||||
<div className="fixed top-0 right-0 h-full w-full md:w-96 bg-gray-800 shadow-2xl z-50 overflow-y-auto animate-slide-in-right">
|
<div className="fixed top-0 right-0 h-full w-full md:w-96 bg-gray-800 shadow-2xl z-[120] overflow-y-auto animate-slide-in-right">
|
||||||
{/* Close button */}
|
{/* Close button */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setSelectedCard(null)}
|
onClick={() => setSelectedCard(null)}
|
||||||
className="fixed top-4 right-4 bg-gray-700 hover:bg-gray-600 text-white p-2 md:p-1.5 rounded-full transition-colors z-[60] shadow-lg"
|
className="fixed top-4 right-4 bg-gray-700 hover:bg-gray-600 text-white p-2 md:p-1.5 rounded-full transition-colors z-[130] shadow-lg"
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
>
|
>
|
||||||
<X size={24} className="md:w-5 md:h-5" />
|
<X size={24} className="md:w-5 md:h-5" />
|
||||||
@@ -1125,7 +1151,7 @@ export default function DeckManager({ initialDeck, onSave }: DeckManagerProps) {
|
|||||||
|
|
||||||
{snackbar && (
|
{snackbar && (
|
||||||
<div
|
<div
|
||||||
className={`fixed bottom-4 right-4 bg-green-500 text-white p-4 rounded-lg shadow-lg transition-all duration-300 ${
|
className={`fixed bottom-4 right-4 text-white p-4 rounded-lg shadow-lg transition-all duration-300 z-[140] ${
|
||||||
snackbar.type === 'success' ? 'bg-green-500' : 'bg-red-500'
|
snackbar.type === 'success' ? 'bg-green-500' : 'bg-red-500'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-900 text-white p-6">
|
<div className="relative md:min-h-screen bg-gray-900 text-white p-6">
|
||||||
<div className="max-w-7xl mx-auto">
|
<div className="max-w-7xl mx-auto">
|
||||||
<h1 className="text-3xl font-bold mb-6">Life Counter</h1>
|
<h1 className="text-3xl font-bold mb-6">Life Counter</h1>
|
||||||
{!setupComplete ? renderSetupForm() : renderLifeCounters()}
|
{!setupComplete ? renderSetupForm() : renderLifeCounters()}
|
||||||
|
|||||||
@@ -53,12 +53,12 @@ export default function Modal({
|
|||||||
<>
|
<>
|
||||||
{/* Backdrop */}
|
{/* Backdrop */}
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 bg-black bg-opacity-50 z-50 transition-opacity duration-300 animate-fade-in"
|
className="fixed inset-0 bg-black bg-opacity-50 z-[110] transition-opacity duration-300 animate-fade-in"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Modal */}
|
{/* Modal */}
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 pointer-events-none">
|
<div className="fixed inset-0 z-[120] flex items-center justify-center p-4 pointer-events-none">
|
||||||
<div
|
<div
|
||||||
className={`${sizeClasses[size]} w-full bg-gray-800 rounded-lg shadow-2xl pointer-events-auto animate-scale-in`}
|
className={`${sizeClasses[size]} w-full bg-gray-800 rounded-lg shadow-2xl pointer-events-auto animate-scale-in`}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default function Navigation({ currentPage, setCurrentPage }: NavigationPr
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Desktop Navigation - Top */}
|
{/* Desktop Navigation - Top */}
|
||||||
<nav className="hidden md:block fixed top-0 left-0 right-0 bg-gray-800 border-b border-gray-700 z-50 animate-slide-in-left">
|
<nav className="hidden md:block fixed top-0 left-0 right-0 bg-gray-800 border-b border-gray-700 z-[100] animate-slide-in-left">
|
||||||
<div className="max-w-7xl mx-auto px-4">
|
<div className="max-w-7xl mx-auto px-4">
|
||||||
<div className="flex items-center justify-between h-16">
|
<div className="flex items-center justify-between h-16">
|
||||||
<div className="flex items-center space-x-8">
|
<div className="flex items-center space-x-8">
|
||||||
@@ -107,7 +107,7 @@ export default function Navigation({ currentPage, setCurrentPage }: NavigationPr
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showDropdown && (
|
{showDropdown && (
|
||||||
<div className="absolute right-0 mt-2 w-48 bg-gray-800 rounded-md shadow-lg py-1 border border-gray-700 animate-scale-in glass-effect">
|
<div className="absolute right-0 mt-2 w-48 bg-gray-800 rounded-md shadow-lg py-1 border border-gray-700 animate-scale-in glass-effect z-[110]">
|
||||||
<button
|
<button
|
||||||
onClick={handleSignOut}
|
onClick={handleSignOut}
|
||||||
className="flex items-center space-x-2 w-full px-4 py-2 text-sm text-gray-300 hover:bg-gray-700 transition-smooth"
|
className="flex items-center space-x-2 w-full px-4 py-2 text-sm text-gray-300 hover:bg-gray-700 transition-smooth"
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export default function PWAInstallPrompt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-20 md:bottom-4 left-4 right-4 md:left-auto md:right-4 md:max-w-sm z-50 animate-slide-in-bottom">
|
<div className="fixed bottom-20 md:bottom-4 left-4 right-4 md:left-auto md:right-4 md:max-w-sm z-[105] animate-slide-in-bottom">
|
||||||
<div className="bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg shadow-2xl p-4 text-white">
|
<div className="bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg shadow-2xl p-4 text-white">
|
||||||
<button
|
<button
|
||||||
onClick={handleDismiss}
|
onClick={handleDismiss}
|
||||||
|
|||||||
@@ -340,14 +340,14 @@ export default function TradeCreator({
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/80 z-50 flex items-center justify-center">
|
<div className="fixed inset-0 bg-black/80 z-[110] flex items-center justify-center">
|
||||||
<Loader2 className="animate-spin text-blue-500" size={48} />
|
<Loader2 className="animate-spin text-blue-500" size={48} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/80 z-50 flex items-center justify-center p-0 md:p-4">
|
<div className="fixed inset-0 bg-black/80 z-[110] flex items-center justify-center p-0 md:p-4">
|
||||||
<div className="bg-gray-800 w-full h-full md:rounded-lg md:w-full md:max-w-6xl md:max-h-[90vh] overflow-hidden flex flex-col">
|
<div className="bg-gray-800 w-full h-full md:rounded-lg md:w-full md:max-w-6xl md:max-h-[90vh] overflow-hidden flex flex-col">
|
||||||
|
|
||||||
{/* ============ MOBILE VIEW ============ */}
|
{/* ============ MOBILE VIEW ============ */}
|
||||||
|
|||||||
Reference in New Issue
Block a user