Spaces:
Running
Running
Update index.html
Browse files- index.html +520 -100
index.html
CHANGED
@@ -186,6 +186,99 @@
|
|
186 |
background: rgba(255, 255, 255, 0.1);
|
187 |
}
|
188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
/* Simplified autocomplete */
|
190 |
.autocomplete-dropdown {
|
191 |
position: absolute;
|
@@ -278,6 +371,8 @@
|
|
278 |
display: flex;
|
279 |
align-items: center;
|
280 |
justify-content: space-between;
|
|
|
|
|
281 |
}
|
282 |
|
283 |
.search-results-title {
|
@@ -299,6 +394,13 @@
|
|
299 |
font-size: 0.875rem;
|
300 |
}
|
301 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
302 |
/* Optimized buttons */
|
303 |
.glass-button {
|
304 |
background: var(--glass-bg);
|
@@ -329,6 +431,86 @@
|
|
329 |
cursor: not-allowed;
|
330 |
}
|
331 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
332 |
/* Card container */
|
333 |
.card-3d-container {
|
334 |
perspective: 2000px;
|
@@ -399,7 +581,7 @@
|
|
399 |
text-transform: uppercase;
|
400 |
letter-spacing: 0.05em;
|
401 |
color: var(--text-muted);
|
402 |
-
margin-bottom: 0.
|
403 |
}
|
404 |
|
405 |
.info-value {
|
@@ -471,7 +653,7 @@
|
|
471 |
color: rgb(248, 113, 113);
|
472 |
}
|
473 |
|
474 |
-
/* Gallery */
|
475 |
.gallery-grid {
|
476 |
display: grid;
|
477 |
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
@@ -483,6 +665,11 @@
|
|
483 |
grid-template-columns: repeat(2, 1fr);
|
484 |
gap: 1rem;
|
485 |
}
|
|
|
|
|
|
|
|
|
|
|
486 |
}
|
487 |
|
488 |
@media (max-width: 480px) {
|
@@ -497,7 +684,6 @@
|
|
497 |
border-radius: 12px;
|
498 |
overflow: hidden;
|
499 |
transition: var(--transition-fast);
|
500 |
-
cursor: pointer;
|
501 |
background: var(--glass-bg);
|
502 |
border: 1px solid var(--glass-border);
|
503 |
}
|
@@ -506,10 +692,11 @@
|
|
506 |
transform: translateY(-4px) scale(1.02);
|
507 |
}
|
508 |
|
|
|
509 |
.gallery-overlay {
|
510 |
position: absolute;
|
511 |
inset: 0;
|
512 |
-
background: linear-gradient(to top, rgba(0, 0, 0, 0.
|
513 |
opacity: 0;
|
514 |
transition: var(--transition-fast);
|
515 |
padding: 1rem;
|
@@ -522,41 +709,63 @@
|
|
522 |
opacity: 1;
|
523 |
}
|
524 |
|
525 |
-
|
526 |
-
|
527 |
-
position: fixed;
|
528 |
-
inset: 0;
|
529 |
-
background: rgba(0, 0, 0, 0.95);
|
530 |
-
backdrop-filter: blur(20px);
|
531 |
-
z-index: 1000;
|
532 |
-
display: none;
|
533 |
-
overflow-y: auto;
|
534 |
-
}
|
535 |
-
|
536 |
-
.details-modal.active {
|
537 |
-
display: block;
|
538 |
}
|
539 |
|
540 |
-
.
|
541 |
-
|
542 |
-
|
|
|
|
|
543 |
}
|
544 |
|
545 |
-
.
|
546 |
-
|
547 |
-
|
548 |
-
right: 20px;
|
549 |
-
width: 40px;
|
550 |
-
height: 40px;
|
551 |
border-radius: 50%;
|
552 |
-
|
553 |
-
border: 1px solid var(--glass-border);
|
554 |
-
color: white;
|
555 |
-
display: flex;
|
556 |
align-items: center;
|
557 |
justify-content: center;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
558 |
cursor: pointer;
|
559 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
}
|
561 |
|
562 |
/* Loading */
|
@@ -663,16 +872,6 @@
|
|
663 |
<!-- Toast notifications -->
|
664 |
<div id="toast" class="toast"></div>
|
665 |
|
666 |
-
<!-- Details Modal -->
|
667 |
-
<div class="details-modal" id="details-modal">
|
668 |
-
<button class="details-close-btn" onclick="closeModal()" aria-label="Close">
|
669 |
-
<i class="fas fa-times"></i>
|
670 |
-
</button>
|
671 |
-
<div class="details-modal-content">
|
672 |
-
<div id="modal-content" class="glass-card p-4"></div>
|
673 |
-
</div>
|
674 |
-
</div>
|
675 |
-
|
676 |
<div class="container mx-auto py-4 md:py-8 px-4">
|
677 |
<!-- Header -->
|
678 |
<header class="text-center mb-8 md:mb-12">
|
@@ -687,7 +886,7 @@
|
|
687 |
</div>
|
688 |
|
689 |
<!-- Search -->
|
690 |
-
<div class="search-container">
|
691 |
<i class="fas fa-search search-icon"></i>
|
692 |
<textarea
|
693 |
id="search-input"
|
@@ -702,8 +901,6 @@
|
|
702 |
</button>
|
703 |
<div class="autocomplete-dropdown" id="autocomplete"></div>
|
704 |
</div>
|
705 |
-
|
706 |
-
|
707 |
</header>
|
708 |
|
709 |
<!-- Main Card Display -->
|
@@ -729,9 +926,6 @@
|
|
729 |
<button id="random-btn" class="glass-button">
|
730 |
<i class="fas fa-shuffle mr-2"></i>Random
|
731 |
</button>
|
732 |
-
<button id="details-btn" class="glass-button">
|
733 |
-
<i class="fas fa-info-circle mr-2"></i>Details
|
734 |
-
</button>
|
735 |
</div>
|
736 |
|
737 |
<!-- Face Navigation -->
|
@@ -752,8 +946,10 @@
|
|
752 |
<h2 id="card-name" class="text-2xl font-semibold text-white mb-1">No Card Selected</h2>
|
753 |
<div id="card-type" class="text-white/60 mb-4"></div>
|
754 |
|
755 |
-
|
756 |
-
|
|
|
|
|
757 |
</div>
|
758 |
|
759 |
<!-- Legalities -->
|
@@ -783,9 +979,19 @@
|
|
783 |
</div>
|
784 |
</div>
|
785 |
|
786 |
-
<!-- Gallery Section -->
|
787 |
<div id="gallery-section" class="mt-12 hidden">
|
788 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
789 |
<div id="gallery" class="gallery-grid max-w-7xl mx-auto"></div>
|
790 |
</div>
|
791 |
|
@@ -796,7 +1002,16 @@
|
|
796 |
<i class="fas fa-search"></i>
|
797 |
<span>Search: <span class="search-query" id="search-query-text"></span></span>
|
798 |
</div>
|
799 |
-
<div class="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
800 |
</div>
|
801 |
<div id="search-results" class="gallery-grid max-w-7xl mx-auto"></div>
|
802 |
</div>
|
@@ -819,6 +1034,18 @@
|
|
819 |
let autocompleteResults = [];
|
820 |
let isSearchMode = false;
|
821 |
let lastSearchQuery = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
822 |
|
823 |
// DOM Elements
|
824 |
const $ = id => document.getElementById(id);
|
@@ -826,7 +1053,6 @@
|
|
826 |
const searchClear = $('search-clear');
|
827 |
const autocomplete = $('autocomplete');
|
828 |
const randomBtn = $('random-btn');
|
829 |
-
const detailsBtn = $('details-btn');
|
830 |
const loading = $('loading');
|
831 |
const toast = $('toast');
|
832 |
const mainCardSection = $('main-card-section');
|
@@ -836,10 +1062,91 @@
|
|
836 |
|
837 |
// Initialize
|
838 |
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
|
839 |
fetchRandomCard();
|
840 |
setupEventListeners();
|
841 |
});
|
842 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
843 |
// Event Listeners
|
844 |
function setupEventListeners() {
|
845 |
searchInput.addEventListener('input', handleSearch);
|
@@ -847,9 +1154,9 @@
|
|
847 |
searchClear.addEventListener('click', clearSearch);
|
848 |
randomBtn.addEventListener('click', () => {
|
849 |
exitSearchMode();
|
|
|
850 |
fetchRandomCard();
|
851 |
});
|
852 |
-
detailsBtn.addEventListener('click', showDetails);
|
853 |
|
854 |
// Close autocomplete on outside click
|
855 |
document.addEventListener('click', e => {
|
@@ -865,7 +1172,6 @@
|
|
865 |
searchInput.focus();
|
866 |
}
|
867 |
if (e.key === 'Escape') {
|
868 |
-
closeModal();
|
869 |
searchInput.blur();
|
870 |
hideAutocomplete();
|
871 |
}
|
@@ -936,6 +1242,7 @@
|
|
936 |
searchInput.value = '';
|
937 |
searchClear.classList.remove('visible');
|
938 |
hideAutocomplete();
|
|
|
939 |
if (isSearchMode) {
|
940 |
exitSearchMode();
|
941 |
fetchRandomCard();
|
@@ -1008,17 +1315,26 @@
|
|
1008 |
}
|
1009 |
}
|
1010 |
|
1011 |
-
// Deck Doctor Search
|
1012 |
async function performDeckDoctorSearch(query) {
|
1013 |
setLoading(true);
|
1014 |
lastSearchQuery = query;
|
1015 |
|
1016 |
try {
|
1017 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1018 |
const data = await response.json();
|
1019 |
|
1020 |
if (data && data.length > 0) {
|
1021 |
-
|
|
|
1022 |
showToast(`Found ${data.length} cards`, 'success');
|
1023 |
} else {
|
1024 |
showToast('No cards found', 'error');
|
@@ -1107,20 +1423,38 @@
|
|
1107 |
|
1108 |
// Hide search results
|
1109 |
searchResultsSection.classList.add('hidden');
|
|
|
|
|
|
|
1110 |
}
|
1111 |
|
1112 |
function displaySearchResults(results) {
|
1113 |
const searchResultsContainer = $('search-results');
|
1114 |
|
1115 |
searchResultsContainer.innerHTML = results.map(([card, score]) => `
|
1116 |
-
<div class="gallery-item"
|
1117 |
<img src="${card.image_uris?.normal || ''}" alt="${card.name}" class="w-full h-full object-cover">
|
1118 |
${card.prices?.usd ? `<div class="absolute bottom-2 left-2 price-tag text-xs">${parseFloat(card.prices.usd).toFixed(2)}</div>` : ''}
|
1119 |
<div class="gallery-overlay">
|
1120 |
-
<
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1124 |
</div>
|
1125 |
</div>
|
1126 |
`).join('');
|
@@ -1141,6 +1475,7 @@
|
|
1141 |
searchClear.classList.remove('visible');
|
1142 |
|
1143 |
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
|
1144 |
} catch (error) {
|
1145 |
showToast('Failed to load card', 'error');
|
1146 |
} finally {
|
@@ -1211,10 +1546,88 @@
|
|
1211 |
// Update card info
|
1212 |
$('card-name').textContent = face.name || card.name;
|
1213 |
$('card-type').innerHTML = `<i class="fas fa-layer-group mr-2"></i>${face.type_line || card.type_line}`;
|
1214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1215 |
}
|
1216 |
|
1217 |
function updateCardInfo(card) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1218 |
// Legalities
|
1219 |
const formats = [
|
1220 |
{ key: 'standard', name: 'Standard' },
|
@@ -1356,9 +1769,18 @@
|
|
1356 |
try {
|
1357 |
// Build the query string using the same logic as Python
|
1358 |
const query = buildCardQueryString(card);
|
|
|
1359 |
console.log('Query string:', query); // Debug logging
|
1360 |
|
1361 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1362 |
const data = await response.json();
|
1363 |
|
1364 |
if (data?.length > 0) {
|
@@ -1372,6 +1794,10 @@
|
|
1372 |
|
1373 |
displayGallery(filteredResults);
|
1374 |
$('gallery-section').classList.remove('hidden');
|
|
|
|
|
|
|
|
|
1375 |
}
|
1376 |
} catch (error) {
|
1377 |
console.error('Gallery error:', error);
|
@@ -1380,12 +1806,35 @@
|
|
1380 |
|
1381 |
function displayGallery(cards) {
|
1382 |
$('gallery').innerHTML = cards.map(([card, score]) => `
|
1383 |
-
<div class="gallery-item"
|
1384 |
<img src="${card.image_uris?.normal || ''}" alt="${card.name}" class="w-full h-full object-cover">
|
1385 |
-
${card.prices?.usd ? `<div class="absolute
|
1386 |
<div class="gallery-overlay">
|
1387 |
-
<
|
1388 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1389 |
</div>
|
1390 |
</div>
|
1391 |
`).join('');
|
@@ -1398,6 +1847,7 @@
|
|
1398 |
const card = await response.json();
|
1399 |
displayCard(card);
|
1400 |
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
|
1401 |
} catch (error) {
|
1402 |
showToast('Failed to load card', 'error');
|
1403 |
} finally {
|
@@ -1409,36 +1859,7 @@
|
|
1409 |
if (!currentCard?.card_faces) return;
|
1410 |
currentFace = (currentFace + direction + currentCard.card_faces.length) % currentCard.card_faces.length;
|
1411 |
displayCardFace(currentCard, currentFace);
|
1412 |
-
|
1413 |
-
|
1414 |
-
function showDetails() {
|
1415 |
-
if (!currentCard) return;
|
1416 |
-
$('modal-content').innerHTML = `
|
1417 |
-
<h3 class="text-2xl font-semibold text-white mb-4">${currentCard.name}</h3>
|
1418 |
-
<div class="space-y-3">
|
1419 |
-
<div class="glass p-3 rounded">
|
1420 |
-
<p class="info-label">Set</p>
|
1421 |
-
<p class="text-white">${currentCard.set_name} (${currentCard.set.toUpperCase()})</p>
|
1422 |
-
</div>
|
1423 |
-
${currentCard.flavor_text ? `
|
1424 |
-
<div class="glass p-3 rounded">
|
1425 |
-
<p class="info-label">Flavor Text</p>
|
1426 |
-
<p class="italic text-white/70">"${currentCard.flavor_text}"</p>
|
1427 |
-
</div>
|
1428 |
-
` : ''}
|
1429 |
-
<div class="glass p-3 rounded">
|
1430 |
-
<p class="info-label">Artist</p>
|
1431 |
-
<p class="text-white">${currentCard.artist}</p>
|
1432 |
-
</div>
|
1433 |
-
</div>
|
1434 |
-
`;
|
1435 |
-
$('details-modal').classList.add('active');
|
1436 |
-
document.body.style.overflow = 'hidden';
|
1437 |
-
}
|
1438 |
-
|
1439 |
-
function closeModal() {
|
1440 |
-
$('details-modal').classList.remove('active');
|
1441 |
-
document.body.style.overflow = '';
|
1442 |
}
|
1443 |
|
1444 |
// Utilities
|
@@ -1446,7 +1867,6 @@
|
|
1446 |
isLoading = state;
|
1447 |
loading.classList.toggle('hidden', !state);
|
1448 |
randomBtn.disabled = state;
|
1449 |
-
detailsBtn.disabled = state || !currentCard;
|
1450 |
}
|
1451 |
|
1452 |
function showToast(message, type = 'info') {
|
|
|
186 |
background: rgba(255, 255, 255, 0.1);
|
187 |
}
|
188 |
|
189 |
+
/* Gallery Header with Filters */
|
190 |
+
.gallery-header {
|
191 |
+
display: flex;
|
192 |
+
align-items: center;
|
193 |
+
justify-content: space-between;
|
194 |
+
margin-bottom: 24px;
|
195 |
+
flex-wrap: wrap;
|
196 |
+
gap: 16px;
|
197 |
+
}
|
198 |
+
|
199 |
+
.gallery-title {
|
200 |
+
font-size: 1.5rem;
|
201 |
+
font-weight: 600;
|
202 |
+
color: white;
|
203 |
+
display: flex;
|
204 |
+
align-items: center;
|
205 |
+
gap: 12px;
|
206 |
+
}
|
207 |
+
|
208 |
+
/* Color Filters - Redesigned for gallery section */
|
209 |
+
.color-filters-inline {
|
210 |
+
display: flex;
|
211 |
+
align-items: center;
|
212 |
+
gap: 8px;
|
213 |
+
}
|
214 |
+
|
215 |
+
.color-filter-label {
|
216 |
+
font-size: 0.875rem;
|
217 |
+
font-weight: 500;
|
218 |
+
color: var(--text-secondary);
|
219 |
+
margin-right: 4px;
|
220 |
+
}
|
221 |
+
|
222 |
+
.color-filter-btn {
|
223 |
+
width: 36px;
|
224 |
+
height: 36px;
|
225 |
+
border-radius: 50%;
|
226 |
+
border: 2px solid transparent;
|
227 |
+
cursor: pointer;
|
228 |
+
transition: var(--transition-fast);
|
229 |
+
display: flex;
|
230 |
+
align-items: center;
|
231 |
+
justify-content: center;
|
232 |
+
font-weight: bold;
|
233 |
+
font-size: 13px;
|
234 |
+
position: relative;
|
235 |
+
background: none;
|
236 |
+
outline: none;
|
237 |
+
}
|
238 |
+
|
239 |
+
.color-filter-btn:hover {
|
240 |
+
transform: scale(1.15);
|
241 |
+
box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
|
242 |
+
}
|
243 |
+
|
244 |
+
.color-filter-btn.active {
|
245 |
+
border-color: rgba(255, 255, 255, 0.9);
|
246 |
+
box-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
|
247 |
+
transform: scale(1.15);
|
248 |
+
}
|
249 |
+
|
250 |
+
.color-filter-btn::after {
|
251 |
+
content: '';
|
252 |
+
position: absolute;
|
253 |
+
inset: 2px;
|
254 |
+
border-radius: 50%;
|
255 |
+
transition: var(--transition-fast);
|
256 |
+
}
|
257 |
+
|
258 |
+
/* Clear filters button */
|
259 |
+
.clear-filters-btn {
|
260 |
+
background: rgba(239, 68, 68, 0.2);
|
261 |
+
border: 1px solid rgba(239, 68, 68, 0.4);
|
262 |
+
color: rgb(248, 113, 113);
|
263 |
+
padding: 6px 12px;
|
264 |
+
border-radius: 8px;
|
265 |
+
font-size: 0.75rem;
|
266 |
+
cursor: pointer;
|
267 |
+
transition: var(--transition-fast);
|
268 |
+
display: none;
|
269 |
+
}
|
270 |
+
|
271 |
+
.clear-filters-btn.visible {
|
272 |
+
display: inline-flex;
|
273 |
+
align-items: center;
|
274 |
+
gap: 4px;
|
275 |
+
}
|
276 |
+
|
277 |
+
.clear-filters-btn:hover {
|
278 |
+
background: rgba(239, 68, 68, 0.3);
|
279 |
+
border-color: rgba(239, 68, 68, 0.6);
|
280 |
+
}
|
281 |
+
|
282 |
/* Simplified autocomplete */
|
283 |
.autocomplete-dropdown {
|
284 |
position: absolute;
|
|
|
371 |
display: flex;
|
372 |
align-items: center;
|
373 |
justify-content: space-between;
|
374 |
+
flex-wrap: wrap;
|
375 |
+
gap: 12px;
|
376 |
}
|
377 |
|
378 |
.search-results-title {
|
|
|
394 |
font-size: 0.875rem;
|
395 |
}
|
396 |
|
397 |
+
/* Search Results Filters */
|
398 |
+
.search-results-filters {
|
399 |
+
display: flex;
|
400 |
+
align-items: center;
|
401 |
+
gap: 8px;
|
402 |
+
}
|
403 |
+
|
404 |
/* Optimized buttons */
|
405 |
.glass-button {
|
406 |
background: var(--glass-bg);
|
|
|
431 |
cursor: not-allowed;
|
432 |
}
|
433 |
|
434 |
+
.glass-button-small {
|
435 |
+
padding: 6px 12px;
|
436 |
+
font-size: 0.8rem;
|
437 |
+
min-height: 32px;
|
438 |
+
}
|
439 |
+
|
440 |
+
/* Oracle text search buttons */
|
441 |
+
.oracle-search-btn {
|
442 |
+
background: rgba(102, 126, 234, 0.2);
|
443 |
+
border: 1px solid rgba(102, 126, 234, 0.4);
|
444 |
+
color: rgba(102, 126, 234, 1);
|
445 |
+
padding: 12px 16px;
|
446 |
+
border-radius: 12px;
|
447 |
+
font-size: 0.85rem;
|
448 |
+
cursor: pointer;
|
449 |
+
transition: var(--transition-fast);
|
450 |
+
display: block;
|
451 |
+
margin: 8px 0;
|
452 |
+
text-align: left;
|
453 |
+
width: 100%;
|
454 |
+
word-wrap: break-word;
|
455 |
+
line-height: 1.5;
|
456 |
+
white-space: normal;
|
457 |
+
overflow-wrap: break-word;
|
458 |
+
word-break: break-word;
|
459 |
+
}
|
460 |
+
|
461 |
+
.oracle-search-btn:hover {
|
462 |
+
background: rgba(102, 126, 234, 0.3);
|
463 |
+
border-color: rgba(102, 126, 234, 0.6);
|
464 |
+
color: white;
|
465 |
+
transform: translateY(-1px);
|
466 |
+
}
|
467 |
+
|
468 |
+
.oracle-search-btn i {
|
469 |
+
margin-right: 8px;
|
470 |
+
flex-shrink: 0;
|
471 |
+
}
|
472 |
+
|
473 |
+
/* Mobile optimization for oracle search buttons */
|
474 |
+
@media (max-width: 768px) {
|
475 |
+
.oracle-search-btn {
|
476 |
+
font-size: 0.8rem;
|
477 |
+
padding: 10px 14px;
|
478 |
+
margin: 6px 0;
|
479 |
+
line-height: 1.4;
|
480 |
+
display: flex;
|
481 |
+
align-items: flex-start;
|
482 |
+
}
|
483 |
+
|
484 |
+
.oracle-search-btn i {
|
485 |
+
margin-right: 8px;
|
486 |
+
font-size: 0.8rem;
|
487 |
+
margin-top: 0.1em;
|
488 |
+
}
|
489 |
+
}
|
490 |
+
|
491 |
+
@media (max-width: 480px) {
|
492 |
+
.oracle-search-btn {
|
493 |
+
font-size: 0.75rem;
|
494 |
+
padding: 10px 12px;
|
495 |
+
margin: 5px 0;
|
496 |
+
line-height: 1.4;
|
497 |
+
border-radius: 10px;
|
498 |
+
}
|
499 |
+
|
500 |
+
.oracle-search-btn i {
|
501 |
+
margin-right: 6px;
|
502 |
+
font-size: 0.75rem;
|
503 |
+
}
|
504 |
+
}
|
505 |
+
|
506 |
+
@media (max-width: 360px) {
|
507 |
+
.oracle-search-btn {
|
508 |
+
font-size: 0.7rem;
|
509 |
+
padding: 8px 10px;
|
510 |
+
margin: 4px 0;
|
511 |
+
}
|
512 |
+
}
|
513 |
+
|
514 |
/* Card container */
|
515 |
.card-3d-container {
|
516 |
perspective: 2000px;
|
|
|
581 |
text-transform: uppercase;
|
582 |
letter-spacing: 0.05em;
|
583 |
color: var(--text-muted);
|
584 |
+
margin-bottom: 0.5rem;
|
585 |
}
|
586 |
|
587 |
.info-value {
|
|
|
653 |
color: rgb(248, 113, 113);
|
654 |
}
|
655 |
|
656 |
+
/* Enhanced Gallery */
|
657 |
.gallery-grid {
|
658 |
display: grid;
|
659 |
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
|
665 |
grid-template-columns: repeat(2, 1fr);
|
666 |
gap: 1rem;
|
667 |
}
|
668 |
+
|
669 |
+
.gallery-header {
|
670 |
+
flex-direction: column;
|
671 |
+
align-items: flex-start;
|
672 |
+
}
|
673 |
}
|
674 |
|
675 |
@media (max-width: 480px) {
|
|
|
684 |
border-radius: 12px;
|
685 |
overflow: hidden;
|
686 |
transition: var(--transition-fast);
|
|
|
687 |
background: var(--glass-bg);
|
688 |
border: 1px solid var(--glass-border);
|
689 |
}
|
|
|
692 |
transform: translateY(-4px) scale(1.02);
|
693 |
}
|
694 |
|
695 |
+
/* Enhanced gallery overlay */
|
696 |
.gallery-overlay {
|
697 |
position: absolute;
|
698 |
inset: 0;
|
699 |
+
background: linear-gradient(to top, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0.7) 50%, transparent 100%);
|
700 |
opacity: 0;
|
701 |
transition: var(--transition-fast);
|
702 |
padding: 1rem;
|
|
|
709 |
opacity: 1;
|
710 |
}
|
711 |
|
712 |
+
.gallery-overlay-content {
|
713 |
+
space-y: 1rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
714 |
}
|
715 |
|
716 |
+
.gallery-mana-cost {
|
717 |
+
display: flex;
|
718 |
+
align-items: center;
|
719 |
+
gap: 4px;
|
720 |
+
margin-bottom: 8px;
|
721 |
}
|
722 |
|
723 |
+
.mana-symbol {
|
724 |
+
width: 16px;
|
725 |
+
height: 16px;
|
|
|
|
|
|
|
726 |
border-radius: 50%;
|
727 |
+
display: inline-flex;
|
|
|
|
|
|
|
728 |
align-items: center;
|
729 |
justify-content: center;
|
730 |
+
font-size: 10px;
|
731 |
+
font-weight: bold;
|
732 |
+
color: white;
|
733 |
+
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
734 |
+
}
|
735 |
+
|
736 |
+
.gallery-actions {
|
737 |
+
display: flex;
|
738 |
+
gap: 8px;
|
739 |
+
margin-top: 12px;
|
740 |
+
}
|
741 |
+
|
742 |
+
.gallery-btn {
|
743 |
+
background: rgba(0, 0, 0, 0.8);
|
744 |
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
745 |
+
color: white;
|
746 |
+
padding: 6px 12px;
|
747 |
+
border-radius: 6px;
|
748 |
+
font-size: 0.75rem;
|
749 |
cursor: pointer;
|
750 |
+
transition: var(--transition-fast);
|
751 |
+
text-decoration: none;
|
752 |
+
display: inline-flex;
|
753 |
+
align-items: center;
|
754 |
+
gap: 4px;
|
755 |
+
}
|
756 |
+
|
757 |
+
.gallery-btn:hover {
|
758 |
+
background: rgba(102, 126, 234, 0.8);
|
759 |
+
border-color: rgba(102, 126, 234, 1);
|
760 |
+
}
|
761 |
+
|
762 |
+
.gallery-btn-view {
|
763 |
+
background: rgba(102, 126, 234, 0.8);
|
764 |
+
}
|
765 |
+
|
766 |
+
.gallery-btn-view:hover {
|
767 |
+
background: rgba(102, 126, 234, 1);
|
768 |
+
transform: translateY(-1px);
|
769 |
}
|
770 |
|
771 |
/* Loading */
|
|
|
872 |
<!-- Toast notifications -->
|
873 |
<div id="toast" class="toast"></div>
|
874 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
875 |
<div class="container mx-auto py-4 md:py-8 px-4">
|
876 |
<!-- Header -->
|
877 |
<header class="text-center mb-8 md:mb-12">
|
|
|
886 |
</div>
|
887 |
|
888 |
<!-- Search -->
|
889 |
+
<div class="search-container mt-8">
|
890 |
<i class="fas fa-search search-icon"></i>
|
891 |
<textarea
|
892 |
id="search-input"
|
|
|
901 |
</button>
|
902 |
<div class="autocomplete-dropdown" id="autocomplete"></div>
|
903 |
</div>
|
|
|
|
|
904 |
</header>
|
905 |
|
906 |
<!-- Main Card Display -->
|
|
|
926 |
<button id="random-btn" class="glass-button">
|
927 |
<i class="fas fa-shuffle mr-2"></i>Random
|
928 |
</button>
|
|
|
|
|
|
|
929 |
</div>
|
930 |
|
931 |
<!-- Face Navigation -->
|
|
|
946 |
<h2 id="card-name" class="text-2xl font-semibold text-white mb-1">No Card Selected</h2>
|
947 |
<div id="card-type" class="text-white/60 mb-4"></div>
|
948 |
|
949 |
+
<!-- Oracle Text Search Section -->
|
950 |
+
<div id="oracle-search-section" class="mb-4">
|
951 |
+
<h3 class="info-label">Search Card Mechanics</h3>
|
952 |
+
<div id="oracle-search-buttons" class="space-y-2"></div>
|
953 |
</div>
|
954 |
|
955 |
<!-- Legalities -->
|
|
|
979 |
</div>
|
980 |
</div>
|
981 |
|
982 |
+
<!-- Gallery Section with Filters -->
|
983 |
<div id="gallery-section" class="mt-12 hidden">
|
984 |
+
<div class="gallery-header max-w-7xl mx-auto">
|
985 |
+
<h2 id="gallery-header" class="gallery-title">Similar Cards</h2>
|
986 |
+
<div class="color-filters-inline">
|
987 |
+
<span class="color-filter-label">Filter:</span>
|
988 |
+
<div id="gallery-color-filters" class="flex gap-2"></div>
|
989 |
+
<button id="clear-gallery-filters" class="clear-filters-btn" onclick="clearGalleryFilters()">
|
990 |
+
<i class="fas fa-times"></i>
|
991 |
+
Clear
|
992 |
+
</button>
|
993 |
+
</div>
|
994 |
+
</div>
|
995 |
<div id="gallery" class="gallery-grid max-w-7xl mx-auto"></div>
|
996 |
</div>
|
997 |
|
|
|
1002 |
<i class="fas fa-search"></i>
|
1003 |
<span>Search: <span class="search-query" id="search-query-text"></span></span>
|
1004 |
</div>
|
1005 |
+
<div class="flex items-center gap-4">
|
1006 |
+
<div class="results-count" id="results-count"></div>
|
1007 |
+
<div class="search-results-filters">
|
1008 |
+
<div id="search-color-filters" class="flex gap-2"></div>
|
1009 |
+
<button id="clear-search-filters" class="clear-filters-btn" onclick="clearSearchFilters()">
|
1010 |
+
<i class="fas fa-times"></i>
|
1011 |
+
Clear
|
1012 |
+
</button>
|
1013 |
+
</div>
|
1014 |
+
</div>
|
1015 |
</div>
|
1016 |
<div id="search-results" class="gallery-grid max-w-7xl mx-auto"></div>
|
1017 |
</div>
|
|
|
1034 |
let autocompleteResults = [];
|
1035 |
let isSearchMode = false;
|
1036 |
let lastSearchQuery = '';
|
1037 |
+
let galleryColors = new Set();
|
1038 |
+
let searchColors = new Set();
|
1039 |
+
let currentGalleryQuery = '';
|
1040 |
+
|
1041 |
+
// Mana color definitions
|
1042 |
+
const manaColors = [
|
1043 |
+
{ symbol: 'W', name: 'White', color: '#FFFBD5', textColor: '#000' },
|
1044 |
+
{ symbol: 'U', name: 'Blue', color: '#0E68AB', textColor: '#fff' },
|
1045 |
+
{ symbol: 'B', name: 'Black', color: '#150B00', textColor: '#fff' },
|
1046 |
+
{ symbol: 'R', name: 'Red', color: '#D3202A', textColor: '#fff' },
|
1047 |
+
{ symbol: 'G', name: 'Green', color: '#00733E', textColor: '#fff' }
|
1048 |
+
];
|
1049 |
|
1050 |
// DOM Elements
|
1051 |
const $ = id => document.getElementById(id);
|
|
|
1053 |
const searchClear = $('search-clear');
|
1054 |
const autocomplete = $('autocomplete');
|
1055 |
const randomBtn = $('random-btn');
|
|
|
1056 |
const loading = $('loading');
|
1057 |
const toast = $('toast');
|
1058 |
const mainCardSection = $('main-card-section');
|
|
|
1062 |
|
1063 |
// Initialize
|
1064 |
document.addEventListener('DOMContentLoaded', () => {
|
1065 |
+
createColorFilterButtons('gallery-color-filters', 'gallery');
|
1066 |
+
createColorFilterButtons('search-color-filters', 'search');
|
1067 |
fetchRandomCard();
|
1068 |
setupEventListeners();
|
1069 |
});
|
1070 |
|
1071 |
+
// Create color filter buttons for different sections
|
1072 |
+
function createColorFilterButtons(containerId, filterType) {
|
1073 |
+
const container = $(containerId);
|
1074 |
+
if (!container) return;
|
1075 |
+
|
1076 |
+
container.innerHTML = manaColors.map(color => `
|
1077 |
+
<button
|
1078 |
+
class="color-filter-btn"
|
1079 |
+
data-color="${color.symbol}"
|
1080 |
+
data-filter-type="${filterType}"
|
1081 |
+
onclick="toggleColorFilter('${color.symbol}', '${filterType}')"
|
1082 |
+
style="color: ${color.textColor};"
|
1083 |
+
title="Filter by ${color.name}"
|
1084 |
+
>
|
1085 |
+
<span style="
|
1086 |
+
position: absolute;
|
1087 |
+
inset: 0;
|
1088 |
+
background: ${color.color};
|
1089 |
+
border-radius: 50%;
|
1090 |
+
z-index: -1;
|
1091 |
+
"></span>
|
1092 |
+
${color.symbol}
|
1093 |
+
</button>
|
1094 |
+
`).join('');
|
1095 |
+
}
|
1096 |
+
|
1097 |
+
// Toggle color filter for specific section
|
1098 |
+
function toggleColorFilter(colorSymbol, filterType) {
|
1099 |
+
const colorSet = filterType === 'gallery' ? galleryColors : searchColors;
|
1100 |
+
const button = document.querySelector(`[data-color="${colorSymbol}"][data-filter-type="${filterType}"]`);
|
1101 |
+
|
1102 |
+
if (colorSet.has(colorSymbol)) {
|
1103 |
+
colorSet.delete(colorSymbol);
|
1104 |
+
button.classList.remove('active');
|
1105 |
+
} else {
|
1106 |
+
colorSet.add(colorSymbol);
|
1107 |
+
button.classList.add('active');
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
// Update clear button visibility
|
1111 |
+
const clearBtn = filterType === 'gallery' ? $('clear-gallery-filters') : $('clear-search-filters');
|
1112 |
+
if (clearBtn) {
|
1113 |
+
clearBtn.classList.toggle('visible', colorSet.size > 0);
|
1114 |
+
}
|
1115 |
+
|
1116 |
+
// Apply filters based on type
|
1117 |
+
if (filterType === 'gallery' && currentCard) {
|
1118 |
+
fetchSimilarCards(currentCard);
|
1119 |
+
} else if (filterType === 'search' && isSearchMode) {
|
1120 |
+
performDeckDoctorSearch(lastSearchQuery);
|
1121 |
+
}
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
// Clear filters for gallery
|
1125 |
+
function clearGalleryFilters() {
|
1126 |
+
galleryColors.clear();
|
1127 |
+
document.querySelectorAll('[data-filter-type="gallery"]').forEach(btn => {
|
1128 |
+
btn.classList.remove('active');
|
1129 |
+
});
|
1130 |
+
$('clear-gallery-filters').classList.remove('visible');
|
1131 |
+
|
1132 |
+
if (currentCard) {
|
1133 |
+
fetchSimilarCards(currentCard);
|
1134 |
+
}
|
1135 |
+
}
|
1136 |
+
|
1137 |
+
// Clear filters for search
|
1138 |
+
function clearSearchFilters() {
|
1139 |
+
searchColors.clear();
|
1140 |
+
document.querySelectorAll('[data-filter-type="search"]').forEach(btn => {
|
1141 |
+
btn.classList.remove('active');
|
1142 |
+
});
|
1143 |
+
$('clear-search-filters').classList.remove('visible');
|
1144 |
+
|
1145 |
+
if (isSearchMode) {
|
1146 |
+
performDeckDoctorSearch(lastSearchQuery);
|
1147 |
+
}
|
1148 |
+
}
|
1149 |
+
|
1150 |
// Event Listeners
|
1151 |
function setupEventListeners() {
|
1152 |
searchInput.addEventListener('input', handleSearch);
|
|
|
1154 |
searchClear.addEventListener('click', clearSearch);
|
1155 |
randomBtn.addEventListener('click', () => {
|
1156 |
exitSearchMode();
|
1157 |
+
clearGalleryFilters();
|
1158 |
fetchRandomCard();
|
1159 |
});
|
|
|
1160 |
|
1161 |
// Close autocomplete on outside click
|
1162 |
document.addEventListener('click', e => {
|
|
|
1172 |
searchInput.focus();
|
1173 |
}
|
1174 |
if (e.key === 'Escape') {
|
|
|
1175 |
searchInput.blur();
|
1176 |
hideAutocomplete();
|
1177 |
}
|
|
|
1242 |
searchInput.value = '';
|
1243 |
searchClear.classList.remove('visible');
|
1244 |
hideAutocomplete();
|
1245 |
+
clearSearchFilters();
|
1246 |
if (isSearchMode) {
|
1247 |
exitSearchMode();
|
1248 |
fetchRandomCard();
|
|
|
1315 |
}
|
1316 |
}
|
1317 |
|
1318 |
+
// Deck Doctor Search with color filters
|
1319 |
async function performDeckDoctorSearch(query) {
|
1320 |
setLoading(true);
|
1321 |
lastSearchQuery = query;
|
1322 |
|
1323 |
try {
|
1324 |
+
// Build URL with colors if selected
|
1325 |
+
let url = `https://api.deck.doctor/v1/mtg/search?q=${encodeURIComponent(query)}&topk=20&price_threshold=0`;
|
1326 |
+
|
1327 |
+
// Add color filters for search results
|
1328 |
+
searchColors.forEach(color => {
|
1329 |
+
url += `&colors=${color}`;
|
1330 |
+
});
|
1331 |
+
|
1332 |
+
const response = await fetch(url);
|
1333 |
const data = await response.json();
|
1334 |
|
1335 |
if (data && data.length > 0) {
|
1336 |
+
const colorFilterText = searchColors.size > 0 ? ` (${Array.from(searchColors).join('')})` : '';
|
1337 |
+
enterSearchMode(query + colorFilterText, data);
|
1338 |
showToast(`Found ${data.length} cards`, 'success');
|
1339 |
} else {
|
1340 |
showToast('No cards found', 'error');
|
|
|
1423 |
|
1424 |
// Hide search results
|
1425 |
searchResultsSection.classList.add('hidden');
|
1426 |
+
|
1427 |
+
// Clear search filters when exiting search mode
|
1428 |
+
clearSearchFilters();
|
1429 |
}
|
1430 |
|
1431 |
function displaySearchResults(results) {
|
1432 |
const searchResultsContainer = $('search-results');
|
1433 |
|
1434 |
searchResultsContainer.innerHTML = results.map(([card, score]) => `
|
1435 |
+
<div class="gallery-item">
|
1436 |
<img src="${card.image_uris?.normal || ''}" alt="${card.name}" class="w-full h-full object-cover">
|
1437 |
${card.prices?.usd ? `<div class="absolute bottom-2 left-2 price-tag text-xs">${parseFloat(card.prices.usd).toFixed(2)}</div>` : ''}
|
1438 |
<div class="gallery-overlay">
|
1439 |
+
<div class="gallery-overlay-content">
|
1440 |
+
<h4 class="font-semibold text-white line-clamp-2">${card.name}</h4>
|
1441 |
+
<p class="text-xs text-white/60 mt-1">${card.type_line}</p>
|
1442 |
+
${score < 1.0 ? `<p class="text-xs text-white/40 mt-1">${Math.round(score * 100)}% match</p>` :
|
1443 |
+
score === 1.0 ? `<p class="text-xs text-white/40 mt-1">From decklist</p>` : ''}
|
1444 |
+
|
1445 |
+
<div class="gallery-actions">
|
1446 |
+
<button onclick="loadCardFromSearch('${card.id}')" class="gallery-btn gallery-btn-view">
|
1447 |
+
<i class="fas fa-eye"></i>
|
1448 |
+
View Card
|
1449 |
+
</button>
|
1450 |
+
${card.purchase_uris?.tcgplayer ? `
|
1451 |
+
<a href="${card.purchase_uris.tcgplayer}" target="_blank" class="gallery-btn">
|
1452 |
+
<i class="fas fa-shopping-cart"></i>
|
1453 |
+
Buy
|
1454 |
+
</a>
|
1455 |
+
` : ''}
|
1456 |
+
</div>
|
1457 |
+
</div>
|
1458 |
</div>
|
1459 |
</div>
|
1460 |
`).join('');
|
|
|
1475 |
searchClear.classList.remove('visible');
|
1476 |
|
1477 |
window.scrollTo({ top: 0, behavior: 'smooth' });
|
1478 |
+
showToast('Card loaded successfully', 'success');
|
1479 |
} catch (error) {
|
1480 |
showToast('Failed to load card', 'error');
|
1481 |
} finally {
|
|
|
1546 |
// Update card info
|
1547 |
$('card-name').textContent = face.name || card.name;
|
1548 |
$('card-type').innerHTML = `<i class="fas fa-layer-group mr-2"></i>${face.type_line || card.type_line}`;
|
1549 |
+
}
|
1550 |
+
|
1551 |
+
// Oracle text search functionality
|
1552 |
+
function createOracleSearchButtons(oracleText) {
|
1553 |
+
if (!oracleText) return '';
|
1554 |
+
|
1555 |
+
const cardName = currentCard.name;
|
1556 |
+
const shortName = cardName.includes(',') ? cardName.split(',')[0].trim() : cardName;
|
1557 |
+
|
1558 |
+
// Split oracle text into meaningful lines
|
1559 |
+
const lines = oracleText.split('\n').filter(line => line.trim().length > 0);
|
1560 |
+
const buttons = [];
|
1561 |
+
|
1562 |
+
lines.forEach((line) => {
|
1563 |
+
let cleanedLine = line.trim();
|
1564 |
+
if (cleanedLine.length > 10) {
|
1565 |
+
// Replace card names with "this card" (case insensitive)
|
1566 |
+
cleanedLine = cleanedLine.replace(new RegExp(cardName, 'gi'), 'this card');
|
1567 |
+
if (shortName !== cardName) {
|
1568 |
+
cleanedLine = cleanedLine.replace(new RegExp(shortName, 'gi'), 'this card');
|
1569 |
+
}
|
1570 |
+
|
1571 |
+
// Show full text in buttons now
|
1572 |
+
buttons.push(`
|
1573 |
+
<button class="oracle-search-btn" onclick="searchOracleText('${cleanedLine.replace(/'/g, "\\'")}')">
|
1574 |
+
<i class="fas fa-search mr-2"></i>
|
1575 |
+
${cleanedLine}
|
1576 |
+
</button>
|
1577 |
+
`);
|
1578 |
+
}
|
1579 |
+
});
|
1580 |
+
|
1581 |
+
return buttons.join('');
|
1582 |
+
}
|
1583 |
+
|
1584 |
+
async function searchOracleText(searchTerm) {
|
1585 |
+
searchInput.value = searchTerm;
|
1586 |
+
searchClear.classList.add('visible');
|
1587 |
+
await performDeckDoctorSearch(searchTerm);
|
1588 |
+
}
|
1589 |
+
|
1590 |
+
// Mana cost display helper
|
1591 |
+
function formatManaCost(manaCost) {
|
1592 |
+
if (!manaCost) return '';
|
1593 |
+
|
1594 |
+
const symbols = manaCost.match(/\{[^}]+\}/g) || [];
|
1595 |
+
return symbols.map(symbol => {
|
1596 |
+
const clean = symbol.replace(/[{}]/g, '');
|
1597 |
+
let color = '';
|
1598 |
+
let bgColor = '';
|
1599 |
+
|
1600 |
+
switch(clean) {
|
1601 |
+
case 'W': color = 'white'; bgColor = '#FFFBD5'; break;
|
1602 |
+
case 'U': color = 'blue'; bgColor = '#0E68AB'; break;
|
1603 |
+
case 'B': color = 'black'; bgColor = '#150B00'; break;
|
1604 |
+
case 'R': color = 'red'; bgColor = '#D3202A'; break;
|
1605 |
+
case 'G': color = 'green'; bgColor = '#00733E'; break;
|
1606 |
+
case 'C': color = 'colorless'; bgColor = '#A89B9A'; break;
|
1607 |
+
default: color = 'generic'; bgColor = '#CAC5C0'; break;
|
1608 |
+
}
|
1609 |
+
|
1610 |
+
return `<span class="mana-symbol" style="background-color: ${bgColor}">${clean}</span>`;
|
1611 |
+
}).join('');
|
1612 |
}
|
1613 |
|
1614 |
function updateCardInfo(card) {
|
1615 |
+
// Oracle text search buttons
|
1616 |
+
const hasFaces = card.card_faces?.length > 1;
|
1617 |
+
const face = hasFaces ? card.card_faces[currentFace] : card;
|
1618 |
+
const oracleText = face.oracle_text || card.oracle_text || '';
|
1619 |
+
|
1620 |
+
const oracleSection = $('oracle-search-section');
|
1621 |
+
if (oracleText) {
|
1622 |
+
$('oracle-search-buttons').innerHTML = createOracleSearchButtons(oracleText);
|
1623 |
+
oracleSection.style.display = 'block';
|
1624 |
+
|
1625 |
+
// Add container class for better mobile layout
|
1626 |
+
$('oracle-search-buttons').classList.add('space-y-2');
|
1627 |
+
} else {
|
1628 |
+
oracleSection.style.display = 'none';
|
1629 |
+
}
|
1630 |
+
|
1631 |
// Legalities
|
1632 |
const formats = [
|
1633 |
{ key: 'standard', name: 'Standard' },
|
|
|
1769 |
try {
|
1770 |
// Build the query string using the same logic as Python
|
1771 |
const query = buildCardQueryString(card);
|
1772 |
+
currentGalleryQuery = query;
|
1773 |
console.log('Query string:', query); // Debug logging
|
1774 |
|
1775 |
+
// Build URL with gallery color filters
|
1776 |
+
let url = `https://api.deck.doctor/v1/mtg/search?q=${encodeURIComponent(query)}&topk=12&price_threshold=0`;
|
1777 |
+
|
1778 |
+
// Add color filters for gallery
|
1779 |
+
galleryColors.forEach(color => {
|
1780 |
+
url += `&colors=${color}`;
|
1781 |
+
});
|
1782 |
+
|
1783 |
+
const response = await fetch(url);
|
1784 |
const data = await response.json();
|
1785 |
|
1786 |
if (data?.length > 0) {
|
|
|
1794 |
|
1795 |
displayGallery(filteredResults);
|
1796 |
$('gallery-section').classList.remove('hidden');
|
1797 |
+
|
1798 |
+
// Update header if filters are active
|
1799 |
+
const colorFilterText = galleryColors.size > 0 ? ` (${Array.from(galleryColors).join('')})` : '';
|
1800 |
+
$('gallery-header').textContent = `Similar Cards${colorFilterText}`;
|
1801 |
}
|
1802 |
} catch (error) {
|
1803 |
console.error('Gallery error:', error);
|
|
|
1806 |
|
1807 |
function displayGallery(cards) {
|
1808 |
$('gallery').innerHTML = cards.map(([card, score]) => `
|
1809 |
+
<div class="gallery-item">
|
1810 |
<img src="${card.image_uris?.normal || ''}" alt="${card.name}" class="w-full h-full object-cover">
|
1811 |
+
${card.prices?.usd ? `<div class="absolute top-2 left-2 price-tag text-xs">$${parseFloat(card.prices.usd).toFixed(2)}</div>` : ''}
|
1812 |
<div class="gallery-overlay">
|
1813 |
+
<div class="gallery-overlay-content">
|
1814 |
+
<h4 class="font-semibold text-white line-clamp-2 mb-2">${card.name}</h4>
|
1815 |
+
${card.mana_cost ? `<div class="gallery-mana-cost mb-2">${formatManaCost(card.mana_cost)}</div>` : ''}
|
1816 |
+
<p class="text-xs text-white/60 line-clamp-2 mb-2">${card.type_line}</p>
|
1817 |
+
${card.oracle_text ? `<p class="text-xs text-white/50 line-clamp-3 mb-3">${card.oracle_text}</p>` : ''}
|
1818 |
+
<p class="text-xs text-white/40 mb-3">${Math.round(score * 100)}% similar</p>
|
1819 |
+
|
1820 |
+
<div class="gallery-actions">
|
1821 |
+
<button onclick="loadCard('${card.id}')" class="gallery-btn gallery-btn-view">
|
1822 |
+
<i class="fas fa-eye"></i>
|
1823 |
+
View Card
|
1824 |
+
</button>
|
1825 |
+
${card.purchase_uris?.tcgplayer ? `
|
1826 |
+
<a href="${card.purchase_uris.tcgplayer}" target="_blank" class="gallery-btn">
|
1827 |
+
<i class="fas fa-shopping-cart"></i>
|
1828 |
+
TCG
|
1829 |
+
</a>
|
1830 |
+
` : card.purchase_uris?.cardmarket ? `
|
1831 |
+
<a href="${card.purchase_uris.cardmarket}" target="_blank" class="gallery-btn">
|
1832 |
+
<i class="fas fa-shopping-cart"></i>
|
1833 |
+
CM
|
1834 |
+
</a>
|
1835 |
+
` : ''}
|
1836 |
+
</div>
|
1837 |
+
</div>
|
1838 |
</div>
|
1839 |
</div>
|
1840 |
`).join('');
|
|
|
1847 |
const card = await response.json();
|
1848 |
displayCard(card);
|
1849 |
window.scrollTo({ top: 0, behavior: 'smooth' });
|
1850 |
+
showToast('Card loaded successfully', 'success');
|
1851 |
} catch (error) {
|
1852 |
showToast('Failed to load card', 'error');
|
1853 |
} finally {
|
|
|
1859 |
if (!currentCard?.card_faces) return;
|
1860 |
currentFace = (currentFace + direction + currentCard.card_faces.length) % currentCard.card_faces.length;
|
1861 |
displayCardFace(currentCard, currentFace);
|
1862 |
+
updateCardInfo(currentCard); // Refresh oracle text buttons for the new face
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1863 |
}
|
1864 |
|
1865 |
// Utilities
|
|
|
1867 |
isLoading = state;
|
1868 |
loading.classList.toggle('hidden', !state);
|
1869 |
randomBtn.disabled = state;
|
|
|
1870 |
}
|
1871 |
|
1872 |
function showToast(message, type = 'info') {
|