(function(window, document) { 'use strict'; // Prevent multiple initializations if (window.EnigmaticCollectiblesWidget) { console.warn('EnigmaticCollectiblesWidget already initialized'); return; } // Default configuration const DEFAULT_CONFIG = { mount: '#enigmatic-collectibles-widget', theme: 'enigmatic-dark', // Custom Enigmatic1 theme defaultCategory: 'all', defaultSearchQuery: '', apiBaseUrl: null, height: '600px', width: '100%', showHeader: true, showFooter: true, onSelect: null, onSearch: null, cssPrefix: 'enigma-' }; // Widget state let config = { ...DEFAULT_CONFIG }; let widgetContainer = null; let widgetRoot = null; let isInitialized = false; let isReactLoaded = false; let isReactDOMLoaded = false; let isWidgetReady = false; let messageQueue = []; let readyPromise = null; let readyResolver = null; let React = null; let ReactDOM = null; let collectiblesApp = null; // Enigmatic1 branding colors const ENIGMATIC_COLORS = { primary: '#1a1a2e', // Deep blue/black secondary: '#9a0680', // Enigmatic purple accent: '#4e00c2', // Bright purple background: '#0f0f1b', // Dark background cardBackground: '#16213e',// Slightly lighter card background textPrimary: '#e6e6e6', // Light text textSecondary: '#b3b3b3', // Slightly darker text border: '#272740', // Border color shadow: 'rgba(0, 0, 0, 0.5)', // Shadow color success: '#00b894', // Success color error: '#d63031', // Error color highlight: '#f39c12' // Highlight color }; // Create a promise that resolves when the widget is ready readyPromise = new Promise(resolve => { readyResolver = resolve; }); /** * Load React and ReactDOM from CDN * @returns {Promise} - Resolves when React and ReactDOM are loaded */ function loadReact() { return new Promise((resolve, reject) => { // Load React const reactScript = document.createElement('script'); reactScript.src = 'https://unpkg.com/react@18/umd/react.production.min.js'; reactScript.crossOrigin = 'anonymous'; reactScript.onload = function() { isReactLoaded = true; React = window.React; // Load ReactDOM after React is loaded const reactDOMScript = document.createElement('script'); reactDOMScript.src = 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js'; reactDOMScript.crossOrigin = 'anonymous'; reactDOMScript.onload = function() { isReactDOMLoaded = true; ReactDOM = window.ReactDOM; resolve(); }; reactDOMScript.onerror = function() { reject(new Error('Failed to load ReactDOM')); }; document.head.appendChild(reactDOMScript); }; reactScript.onerror = function() { reject(new Error('Failed to load React')); }; document.head.appendChild(reactScript); }); } /** * Initialize the widget with configuration options * @param {Object} userConfig - Configuration options * @returns {Promise} - Resolves when widget is ready */ function init(userConfig = {}) { if (isInitialized) { console.warn('EnigmaticCollectiblesWidget already initialized'); return readyPromise; } // Merge user config with defaults config = { ...DEFAULT_CONFIG, ...userConfig }; // Find or create container element const mountSelector = config.mount; widgetContainer = typeof mountSelector === 'string' ? document.querySelector(mountSelector) : mountSelector; if (!widgetContainer) { console.error(`EnigmaticCollectiblesWidget: Container element "${config.mount}" not found`); return Promise.reject(new Error(`Container element "${config.mount}" not found`)); } // Add widget class to container widgetContainer.classList.add(`${config.cssPrefix}container`); // Set container styles widgetContainer.style.width = config.width; widgetContainer.style.height = config.height; widgetContainer.style.overflow = 'hidden'; widgetContainer.style.position = 'relative'; widgetContainer.style.boxSizing = 'border-box'; widgetContainer.style.fontFamily = "'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif"; // Create and inject styles injectStyles(); // Show loading indicator showLoading(); // Create widget root element widgetRoot = document.createElement('div'); widgetRoot.className = `${config.cssPrefix}root`; widgetRoot.style.width = '100%'; widgetRoot.style.height = '100%'; widgetContainer.appendChild(widgetRoot); // Load React and then initialize the app loadReact() .then(() => { // Create the React app createReactApp(); // Mark as initialized isInitialized = true; }) .catch(error => { console.error('Failed to load React:', error); showError('Failed to initialize the collectibles widget. Please try again later.'); }); // Return promise that resolves when widget is ready return readyPromise; } /** * Inject required CSS styles for the widget container */ function injectStyles() { const styleId = `${config.cssPrefix}styles`; // Don't add styles twice if (document.getElementById(styleId)) { return; } const styleElement = document.createElement('style'); styleElement.id = styleId; styleElement.textContent = ` /* Enigmatic1.com Widget Styles */ .${config.cssPrefix}container { font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif; border-radius: 8px; box-shadow: 0 2px 20px ${ENIGMATIC_COLORS.shadow}; background-color: ${ENIGMATIC_COLORS.background}; color: ${ENIGMATIC_COLORS.textPrimary}; } .${config.cssPrefix}root { border-radius: 8px; } .${config.cssPrefix}loading { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background-color: ${ENIGMATIC_COLORS.background}; z-index: 1; border-radius: 8px; flex-direction: column; } .${config.cssPrefix}spinner { width: 50px; height: 50px; border: 4px solid rgba(78, 0, 194, 0.3); border-top: 4px solid ${ENIGMATIC_COLORS.secondary}; border-radius: 50%; animation: ${config.cssPrefix}spin 1s linear infinite; } .${config.cssPrefix}loading-text { margin-top: 20px; color: ${ENIGMATIC_COLORS.textPrimary}; font-size: 16px; font-weight: 500; } @keyframes ${config.cssPrefix}spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .${config.cssPrefix}error { color: ${ENIGMATIC_COLORS.error}; text-align: center; padding: 20px; background-color: rgba(214, 48, 49, 0.1); border-radius: 8px; margin: 20px; border-left: 4px solid ${ENIGMATIC_COLORS.error}; } /* Enigmatic Collectibles App Styles */ .enigmatic-collectibles-app { display: flex; flex-direction: column; height: 100%; background-color: ${ENIGMATIC_COLORS.background}; color: ${ENIGMATIC_COLORS.textPrimary}; border-radius: 8px; overflow: hidden; } .enigmatic-app-header { background-color: ${ENIGMATIC_COLORS.primary}; color: ${ENIGMATIC_COLORS.textPrimary}; padding: 16px 20px; text-align: center; border-bottom: 4px solid ${ENIGMATIC_COLORS.secondary}; } .enigmatic-app-header h1 { font-size: 1.8rem; margin: 0; background: linear-gradient(45deg, ${ENIGMATIC_COLORS.secondary}, ${ENIGMATIC_COLORS.accent}); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; text-fill-color: transparent; } .enigmatic-app-header p { margin: 5px 0 0; font-size: 0.95rem; opacity: 0.8; } .enigmatic-search-container { padding: 16px; background-color: ${ENIGMATIC_COLORS.primary}; } .enigmatic-search-form { display: flex; gap: 10px; } .enigmatic-search-input { flex: 1; padding: 12px 16px; border-radius: 6px; border: 1px solid ${ENIGMATIC_COLORS.border}; background-color: rgba(255, 255, 255, 0.1); color: ${ENIGMATIC_COLORS.textPrimary}; font-size: 16px; transition: all 0.3s ease; } .enigmatic-search-input:focus { outline: none; border-color: ${ENIGMATIC_COLORS.secondary}; box-shadow: 0 0 0 2px rgba(154, 6, 128, 0.3); } .enigmatic-search-button { background: linear-gradient(45deg, ${ENIGMATIC_COLORS.secondary}, ${ENIGMATIC_COLORS.accent}); color: white; border: none; padding: 0 20px; border-radius: 6px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; } .enigmatic-search-button:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(154, 6, 128, 0.5); } .enigmatic-main-content { display: flex; flex: 1; overflow: hidden; } .enigmatic-filters { width: 260px; background-color: ${ENIGMATIC_COLORS.cardBackground}; border-right: 1px solid ${ENIGMATIC_COLORS.border}; padding: 16px; overflow-y: auto; } .enigmatic-results { flex: 1; padding: 16px; overflow-y: auto; background-color: ${ENIGMATIC_COLORS.background}; } .enigmatic-filter-section { margin-bottom: 20px; } .enigmatic-filter-title { font-size: 16px; font-weight: 600; margin-bottom: 12px; color: ${ENIGMATIC_COLORS.textPrimary}; display: flex; justify-content: space-between; align-items: center; cursor: pointer; } .enigmatic-filter-content { margin-top: 8px; } .enigmatic-filter-option { display: flex; align-items: center; margin-bottom: 8px; } .enigmatic-filter-option input[type="checkbox"], .enigmatic-filter-option input[type="radio"] { margin-right: 8px; accent-color: ${ENIGMATIC_COLORS.secondary}; } .enigmatic-filter-option label { font-size: 14px; color: ${ENIGMATIC_COLORS.textSecondary}; } .enigmatic-price-inputs { display: flex; gap: 8px; } .enigmatic-price-input { flex: 1; } .enigmatic-price-input input { width: 100%; padding: 8px; border-radius: 4px; border: 1px solid ${ENIGMATIC_COLORS.border}; background-color: rgba(255, 255, 255, 0.1); color: ${ENIGMATIC_COLORS.textPrimary}; } .enigmatic-collectibles-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; } .enigmatic-collectible-card { background-color: ${ENIGMATIC_COLORS.cardBackground}; border-radius: 8px; overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; cursor: pointer; } .enigmatic-collectible-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3); } .enigmatic-collectible-image { width: 100%; height: 180px; object-fit: cover; } .enigmatic-collectible-info { padding: 12px; } .enigmatic-collectible-title { font-size: 16px; font-weight: 600; margin: 0 0 8px; color: ${ENIGMATIC_COLORS.textPrimary}; } .enigmatic-collectible-category { font-size: 12px; color: ${ENIGMATIC_COLORS.textSecondary}; margin-bottom: 4px; } .enigmatic-collectible-price { font-size: 18px; font-weight: 700; color: ${ENIGMATIC_COLORS.secondary}; } .enigmatic-collectible-rarity { display: inline-block; padding: 3px 8px; border-radius: 12px; font-size: 11px; font-weight: 600; margin-top: 8px; background-color: rgba(154, 6, 128, 0.2); color: ${ENIGMATIC_COLORS.secondary}; } .enigmatic-app-footer { background-color: ${ENIGMATIC_COLORS.primary}; color: ${ENIGMATIC_COLORS.textSecondary}; text-align: center; padding: 12px; font-size: 12px; border-top: 1px solid ${ENIGMATIC_COLORS.border}; } .enigmatic-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.8); display: flex; align-items: center; justify-content: center; z-index: 1000; } .enigmatic-modal { background-color: ${ENIGMATIC_COLORS.cardBackground}; border-radius: 12px; width: 90%; max-width: 800px; max-height: 90vh; overflow-y: auto; position: relative; } .enigmatic-modal-close { position: absolute; top: 16px; right: 16px; background: none; border: none; color: ${ENIGMATIC_COLORS.textPrimary}; font-size: 24px; cursor: pointer; z-index: 10; } .enigmatic-modal-content { padding: 24px; } .enigmatic-detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; } .enigmatic-detail-image { width: 100%; border-radius: 8px; } .enigmatic-detail-info h2 { color: ${ENIGMATIC_COLORS.textPrimary}; margin: 0 0 16px; } .enigmatic-detail-price { font-size: 24px; font-weight: 700; color: ${ENIGMATIC_COLORS.secondary}; margin: 16px 0; } .enigmatic-detail-meta { margin: 16px 0; padding: 16px; background-color: rgba(0, 0, 0, 0.2); border-radius: 8px; } .enigmatic-detail-meta-item { display: flex; justify-content: space-between; margin-bottom: 8px; } .enigmatic-detail-meta-label { color: ${ENIGMATIC_COLORS.textSecondary}; } .enigmatic-detail-meta-value { color: ${ENIGMATIC_COLORS.textPrimary}; font-weight: 500; } .enigmatic-detail-description { margin-top: 16px; color: ${ENIGMATIC_COLORS.textSecondary}; line-height: 1.6; } .enigmatic-detail-buttons { margin-top: 24px; display: flex; gap: 12px; } .enigmatic-button-primary { background: linear-gradient(45deg, ${ENIGMATIC_COLORS.secondary}, ${ENIGMATIC_COLORS.accent}); color: white; border: none; padding: 10px 20px; border-radius: 6px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; } .enigmatic-button-secondary { background-color: transparent; color: ${ENIGMATIC_COLORS.textPrimary}; border: 1px solid ${ENIGMATIC_COLORS.border}; padding: 10px 20px; border-radius: 6px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; } .enigmatic-pagination { display: flex; justify-content: center; margin-top: 24px; gap: 8px; } .enigmatic-page-button { min-width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 4px; background-color: ${ENIGMATIC_COLORS.cardBackground}; color: ${ENIGMATIC_COLORS.textPrimary}; border: 1px solid ${ENIGMATIC_COLORS.border}; cursor: pointer; transition: all 0.2s ease; } .enigmatic-page-button.active { background-color: ${ENIGMATIC_COLORS.secondary}; color: white; border-color: ${ENIGMATIC_COLORS.secondary}; } /* Responsive styles */ @media (max-width: 768px) { .enigmatic-main-content { flex-direction: column; } .enigmatic-filters { width: 100%; border-right: none; border-bottom: 1px solid ${ENIGMATIC_COLORS.border}; } .enigmatic-detail-grid { grid-template-columns: 1fr; } } `; document.head.appendChild(styleElement); } /** * Show loading indicator */ function showLoading() { const loadingElement = document.createElement('div'); loadingElement.className = `${config.cssPrefix}loading`; loadingElement.innerHTML = `
Loading Enigmatic Collectibles...
`; widgetContainer.appendChild(loadingElement); } /** * Hide loading indicator */ function hideLoading() { const loadingElement = widgetContainer.querySelector(`.${config.cssPrefix}loading`); if (loadingElement) { loadingElement.parentNode.removeChild(loadingElement); } } /** * Show error message * @param {string} message - Error message to display */ function showError(message) { hideLoading(); const errorElement = document.createElement('div'); errorElement.className = `${config.cssPrefix}error`; errorElement.textContent = message; widgetContainer.appendChild(errorElement); } /** * Create the React application */ function createReactApp() { // Mock data for collectibles const mockCollectibles = generateMockCollectibles(); // Create the React component const EnigmaticCollectiblesApp = () => { const [searchQuery, setSearchQuery] = React.useState(''); const [filters, setFilters] = React.useState({ category: 'all', minPrice: '', maxPrice: '', rarity: 'all', condition: 'all' }); const [collectibles, setCollectibles] = React.useState([]); const [loading, setLoading] = React.useState(false); const [selectedCollectible, setSelectedCollectible] = React.useState(null); const [currentPage, setCurrentPage] = React.useState(1); const [totalPages, setTotalPages] = React.useState(1); // Categories for filtering const categories = [ { id: 'all', name: 'All Categories' }, { id: 'comics', name: 'Comics' }, { id: 'coins', name: 'Coins' }, { id: 'art', name: 'Art' }, { id: 'toys', name: 'Toys' }, { id: 'sports', name: 'Sports Memorabilia' }, { id: 'movies', name: 'Movie Props & Replicas' }, { id: 'cards', name: 'Trading Cards' } ]; // Format price with commas and dollar sign const formatPrice = (price) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(price); }; // Search for collectibles const handleSearch = (e) => { if (e) e.preventDefault(); setLoading(true); // Simulate API call with setTimeout setTimeout(() => { const results = searchCollectibles(searchQuery, filters); setCollectibles(results.items); setTotalPages(results.totalPages); setLoading(false); // Notify parent of search if (config.onSearch) { config.onSearch({ query: searchQuery, filters: filters, results: results.totalResults }); } }, 500); }; // Search collectibles function const searchCollectibles = (query, filters) => { const itemsPerPage = 12; // Convert query to lowercase for case-insensitive search const searchQuery = query.toLowerCase(); // Filter items based on search query and filters let filteredItems = mockCollectibles.filter(item => { // Search query matching const matchesQuery = !searchQuery || item.title.toLowerCase().includes(searchQuery) || item.description.toLowerCase().includes(searchQuery) || item.category.toLowerCase().includes(searchQuery); if (!matchesQuery) return false; // Category filter if (filters.category !== 'all' && item.category.toLowerCase() !== filters.category.toLowerCase()) { return false; } // Price range filter if (filters.minPrice && item.price < parseFloat(filters.minPrice)) { return false; } if (filters.maxPrice && item.price > parseFloat(filters.maxPrice)) { return false; } // Rarity filter if (filters.rarity !== 'all' && item.rarity.toLowerCase().replace(' ', '') !== filters.rarity.toLowerCase()) { return false; } // Condition filter if (filters.condition !== 'all' && item.condition.toLowerCase().replace(' ', '') !== filters.condition.toLowerCase()) { return false; } return true; }); // Calculate pagination const totalPages = Math.ceil(filteredItems.length / itemsPerPage); const startIndex = (currentPage - 1) * itemsPerPage; const paginatedItems = filteredItems.slice(startIndex, startIndex + itemsPerPage); // Return results object return { items: paginatedItems, totalPages: totalPages, totalResults: filteredItems.length }; }; // Handle filter changes const handleFilterChange = (name, value) => { setFilters(prev => ({ ...prev, [name]: value })); setCurrentPage(1); // Reset to first page when filters change }; // Handle page change const handlePageChange = (page) => { setCurrentPage(page); }; // Handle collectible selection const handleCollectibleSelect = (collectible) => { setSelectedCollectible(collectible); // Notify parent of selection if (config.onSelect) { config.onSelect(collectible); } }; // Close detail modal const handleCloseDetail = () => { setSelectedCollectible(null); }; // Effect to search when filters or page changes React.useEffect(() => { if (searchQuery) { handleSearch(); } }, [filters, currentPage]); // Effect to notify parent when widget is ready React.useEffect(() => { // Hide loading indicator hideLoading(); // Set widget ready state isWidgetReady = true; // Resolve ready promise if (readyResolver) { readyResolver(); } // Initialize with default search if provided if (config.defaultSearchQuery) { setSearchQuery(config.defaultSearchQuery); handleSearch(); } // Initialize with default category if provided if (config.defaultCategory !== 'all') { setFilters(prev => ({ ...prev, category: config.defaultCategory })); } }, []); // Expose methods to parent window React.useEffect(() => { // Create API for parent window collectiblesApp = { search: (query, filterOptions) => { setSearchQuery(query); if (filterOptions) { setFilters(prev => ({ ...prev, ...filterOptions })); } setTimeout(handleSearch, 0); }, setCategory: (category) => { setFilters(prev => ({ ...prev, category: category })); }, reset: () => { setSearchQuery(''); setFilters({ category: 'all', minPrice: '', maxPrice: '', rarity: 'all', condition: 'all' }); setCollectibles([]); setCurrentPage(1); } }; }, []); // Render pagination const renderPagination = () => { if (totalPages <= 1) return null; const pageButtons = []; const maxButtons = 5; let startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2)); let endPage = Math.min(totalPages, startPage + maxButtons - 1); if (endPage - startPage + 1 < maxButtons) { startPage = Math.max(1, endPage - maxButtons + 1); } // Previous button pageButtons.push( React.createElement('button', { key: 'prev', className: `enigmatic-page-button ${currentPage === 1 ? 'disabled' : ''}`, onClick: () => currentPage > 1 && handlePageChange(currentPage - 1), disabled: currentPage === 1 }, '←') ); // Page numbers for (let i = startPage; i <= endPage; i++) { pageButtons.push( React.createElement('button', { key: i, className: `enigmatic-page-button ${currentPage === i ? 'active' : ''}`, onClick: () => handlePageChange(i) }, i) ); } // Next button pageButtons.push( React.createElement('button', { key: 'next', className: `enigmatic-page-button ${currentPage === totalPages ? 'disabled' : ''}`, onClick: () => currentPage < totalPages && handlePageChange(currentPage + 1), disabled: currentPage === totalPages }, '→') ); return React.createElement('div', { className: 'enigmatic-pagination' }, pageButtons); }; // Render detail modal const renderDetailModal = () => { if (!selectedCollectible) return null; return React.createElement('div', { className: 'enigmatic-modal-overlay', onClick: handleCloseDetail }, React.createElement('div', { className: 'enigmatic-modal', onClick: e => e.stopPropagation() }, React.createElement('button', { className: 'enigmatic-modal-close', onClick: handleCloseDetail }, '×'), React.createElement('div', { className: 'enigmatic-modal-content' }, React.createElement('div', { className: 'enigmatic-detail-grid' }, // Left column - Image React.createElement('div', { className: 'enigmatic-detail-image-container' }, React.createElement('img', { src: selectedCollectible.imageUrl, alt: selectedCollectible.title, className: 'enigmatic-detail-image' }) ), // Right column - Info React.createElement('div', { className: 'enigmatic-detail-info' }, React.createElement('h2', null, selectedCollectible.title), React.createElement('div', { className: 'enigmatic-detail-price' }, formatPrice(selectedCollectible.price) ), React.createElement('div', { className: 'enigmatic-detail-meta' }, React.createElement('div', { className: 'enigmatic-detail-meta-item' }, React.createElement('span', { className: 'enigmatic-detail-meta-label' }, 'Category:'), React.createElement('span', { className: 'enigmatic-detail-meta-value' }, selectedCollectible.category) ), React.createElement('div', { className: 'enigmatic-detail-meta-item' }, React.createElement('span', { className: 'enigmatic-detail-meta-label' }, 'Year:'), React.createElement('span', { className: 'enigmatic-detail-meta-value' }, selectedCollectible.year || 'Unknown') ), React.createElement('div', { className: 'enigmatic-detail-meta-item' }, React.createElement('span', { className: 'enigmatic-detail-meta-label' }, 'Condition:'), React.createElement('span', { className: 'enigmatic-detail-meta-value' }, selectedCollectible.condition || 'Unknown') ), React.createElement('div', { className: 'enigmatic-detail-meta-item' }, React.createElement('span', { className: 'enigmatic-detail-meta-label' }, 'Rarity:'), React.createElement('span', { className: 'enigmatic-detail-meta-value' }, selectedCollectible.rarity || 'Unknown') ) ), React.createElement('div', { className: 'enigmatic-detail-description' }, selectedCollectible.description ), React.createElement('div', { className: 'enigmatic-detail-buttons' }, React.createElement('button', { className: 'enigmatic-button-primary' }, selectedCollectible.isAuction ? 'Place Bid' : 'Buy Now' ), React.createElement('button', { className: 'enigmatic-button-secondary' }, 'Add to Watchlist') ) ) ) ) ) ); }; // Render collectibles grid const renderCollectiblesGrid = () => { if (loading) { return React.createElement('div', { className: 'enigmatic-loading-results' }, React.createElement('div', { className: `${config.cssPrefix}spinner` }), React.createElement('p', null, 'Searching for collectibles...') ); } if (collectibles.length === 0) { return React.createElement('div', { className: 'enigmatic-no-results' }, React.createElement('p', null, searchQuery ? 'No collectibles found matching your criteria.' : 'Start searching to discover valuable collectibles!' ) ); } return React.createElement('div', { className: 'enigmatic-collectibles-grid' }, collectibles.map(collectible => React.createElement('div', { key: collectible.id, className: 'enigmatic-collectible-card', onClick: () => handleCollectibleSelect(collectible) }, React.createElement('img', { src: collectible.imageUrl, alt: collectible.title, className: 'enigmatic-collectible-image' }), React.createElement('div', { className: 'enigmatic-collectible-info' }, React.createElement('h3', { className: 'enigmatic-collectible-title' }, collectible.title), React.createElement('div', { className: 'enigmatic-collectible-category' }, collectible.category), React.createElement('div', { className: 'enigmatic-collectible-price' }, formatPrice(collectible.price)), React.createElement('div', { className: 'enigmatic-collectible-rarity' }, collectible.rarity) ) ) ) ); }; // Render filters const renderFilters = () => { return React.createElement('div', { className: 'enigmatic-filters' }, // Category filter React.createElement('div', { className: 'enigmatic-filter-section' }, React.createElement('h3', { className: 'enigmatic-filter-title' }, 'Categories'), React.createElement('div', { className: 'enigmatic-filter-content' }, categories.map(category => React.createElement('div', { key: category.id, className: 'enigmatic-filter-option' }, React.createElement('input', { type: 'radio', id: `category-${category.id}`, name: 'category', value: category.id, checked: filters.category === category.id, onChange: () => handleFilterChange('category', category.id) }), React.createElement('label', { htmlFor: `category-${category.id}` }, category.name) ) ) ) ), // Price range filter React.createElement('div', { className: 'enigmatic-filter-section' }, React.createElement('h3', { className: 'enigmatic-filter-title' }, 'Price Range'), React.createElement('div', { className: 'enigmatic-filter-content' }, React.createElement('div', { className: 'enigmatic-price-inputs' }, React.createElement('div', { className: 'enigmatic-price-input' }, React.createElement('input', { type: 'number', placeholder: 'Min $', value: filters.minPrice, onChange: (e) => handleFilterChange('minPrice', e.target.value), min: '0' }) ), React.createElement('div', { className: 'enigmatic-price-input' }, React.createElement('input', { type: 'number', placeholder: 'Max $', value: filters.maxPrice, onChange: (e) => handleFilterChange('maxPrice', e.target.value), min: '0' }) ) ) ) ), // Rarity filter React.createElement('div', { className: 'enigmatic-filter-section' }, React.createElement('h3', { className: 'enigmatic-filter-title' }, 'Rarity'), React.createElement('div', { className: 'enigmatic-filter-content' }, [ { id: 'all', name: 'All Rarities' }, { id: 'common', name: 'Common' }, { id: 'uncommon', name: 'Uncommon' }, { id: 'rare', name: 'Rare' }, { id: 'veryrare', name: 'Very Rare' }, { id: 'ultrarare', name: 'Ultra Rare' }, { id: 'unique', name: 'One of a Kind' } ].map(rarity => React.createElement('div', { key: rarity.id, className: 'enigmatic-filter-option' }, React.createElement('input', { type: 'radio', id: `rarity-${rarity.id}`, name: 'rarity', value: rarity.id, checked: filters.rarity === rarity.id, onChange: () => handleFilterChange('rarity', rarity.id) }), React.createElement('label', { htmlFor: `rarity-${rarity.id}` }, rarity.name) ) ) ) ), // Condition filter React.createElement('div', { className: 'enigmatic-filter-section' }, React.createElement('h3', { className: 'enigmatic-filter-title' }, 'Condition'), React.createElement('div', { className: 'enigmatic-filter-content' }, [ { id: 'all', name: 'All Conditions' }, { id: 'mint', name: 'Mint' }, { id: 'nearmint', name: 'Near Mint' }, { id: 'excellent', name: 'Excellent' }, { id: 'verygood', name: 'Very Good' }, { id: 'good', name: 'Good' }, { id: 'fair', name: 'Fair' }, { id: 'poor', name: 'Poor' } ].map(condition => React.createElement('div', { key: condition.id, className: 'enigmatic-filter-option' }, React.createElement('input', { type: 'radio', id: `condition-${condition.id}`, name: 'condition', value: condition.id, checked: filters.condition === condition.id, onChange: () => handleFilterChange('condition', condition.id) }), React.createElement('label', { htmlFor: `condition-${condition.id}` }, condition.name) ) ) ) ), // Reset filters button React.createElement('button', { className: 'enigmatic-button-secondary', onClick: () => { setFilters({ category: 'all', minPrice: '', maxPrice: '', rarity: 'all', condition: 'all' }); }, style: { width: '100%', marginTop: '16px' } }, 'Reset Filters') ); }; // Main render return React.createElement('div', { className: 'enigmatic-collectibles-app' }, // Header config.showHeader && React.createElement('header', { className: 'enigmatic-app-header' }, React.createElement('h1', null, 'Enigmatic Collectibles'), React.createElement('p', null, 'Discover rare and valuable treasures') ), // Search form React.createElement('div', { className: 'enigmatic-search-container' }, React.createElement('form', { className: 'enigmatic-search-form', onSubmit: handleSearch }, React.createElement('input', { type: 'text', className: 'enigmatic-search-input', placeholder: 'Search for rare comics, coins, art, memorabilia...', value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) }), React.createElement('button', { type: 'submit', className: 'enigmatic-search-button' }, 'Search') ) ), // Main content React.createElement('div', { className: 'enigmatic-main-content' }, // Filters sidebar renderFilters(), // Results area React.createElement('div', { className: 'enigmatic-results' }, renderCollectiblesGrid(), renderPagination() ) ), // Footer config.showFooter && React.createElement('footer', { className: 'enigmatic-app-footer' }, React.createElement('p', null, `© ${new Date().getFullYear()} Enigmatic1.com - Collectibles Treasure Hunter`) ), // Detail modal renderDetailModal() ); }; // Render the React app ReactDOM.render( React.createElement(EnigmaticCollectiblesApp), widgetRoot ); } /** * Generate mock collectibles data * @returns {Array} Array of collectible objects */ function generateMockCollectibles() { // Base collectibles const collectibles = [ { id: 'c1', title: "Action Comics #1 (First Superman)", category: "Comics", price: 3500000, year: 1938, condition: "Good", rarity: "Ultra Rare", description: "The holy grail of comic books featuring the first appearance of Superman. This iconic issue marked the beginning of the superhero genre.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Action%20Comics%20%231", isAuction: true }, { id: 'c2', title: "Detective Comics #27 (First Batman)", category: "Comics", price: 1800000, year: 1939, condition: "Very Good", rarity: "Ultra Rare", description: "The first appearance of Batman, one of the most iconic superheroes of all time. This issue is highly sought after by serious collectors.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Detective%20Comics%20%2327", isAuction: false }, { id: 'c3', title: "1794 Flowing Hair Silver Dollar", category: "Coins", price: 10000000, year: 1794, condition: "Excellent", rarity: "Unique", description: "One of the first silver dollars minted by the United States. This specimen is believed to be the first silver dollar struck by the U.S. Mint.", imageUrl: "https://placeholder.pics/svg/300x300/DEDEDE/555555/1794%20Silver%20Dollar", isAuction: true }, { id: 'c4', title: "1933 Double Eagle Gold Coin", category: "Coins", price: 7500000, year: 1933, condition: "Mint", rarity: "Ultra Rare", description: "One of the most famous and valuable coins in the world. Most 1933 Double Eagles were melted down following an executive order, making the few survivors extremely rare.", imageUrl: "https://placeholder.pics/svg/300x300/DEDEDE/555555/1933%20Double%20Eagle", isAuction: false }, { id: 'c5', title: "Original Frank Frazetta 'Death Dealer' Painting", category: "Art", price: 1200000, year: 1973, condition: "Excellent", rarity: "Unique", description: "The iconic fantasy painting by Frank Frazetta featuring a menacing warrior atop a steed. One of the most recognizable fantasy art pieces ever created.", imageUrl: "https://placeholder.pics/svg/400x300/DEDEDE/555555/Death%20Dealer", isAuction: true }, { id: 'c6', title: "Original Jack Kirby Silver Surfer Artwork", category: "Art", price: 350000, year: 1966, condition: "Very Good", rarity: "Unique", description: "Original pen and ink artwork by legendary comic artist Jack Kirby featuring the Silver Surfer. Page from Fantastic Four #48.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Silver%20Surfer", isAuction: false }, { id: 'c7', title: "Original 1979 Kenner Boba Fett Rocket-Firing Prototype", category: "Toys", price: 185000, year: 1979, condition: "Mint", rarity: "Ultra Rare", description: "The legendary unreleased prototype Boba Fett action figure with working rocket-firing backpack. Canceled due to safety concerns, making it one of the holy grails of Star Wars collecting.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Rocket%20Fett", isAuction: true }, { id: 'c8', title: "1938 Superman Tin Wind-Up Toy", category: "Toys", price: 75000, year: 1938, condition: "Good", rarity: "Very Rare", description: "Extremely rare pre-war Superman tin wind-up toy manufactured by Marx. One of the earliest Superman toys ever produced.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Superman%20Tin%20Toy", isAuction: false }, { id: 'c9', title: "Babe Ruth Game-Used Bat from 1932 World Series", category: "Sports", price: 1265000, year: 1932, condition: "Very Good", rarity: "Unique", description: "The bat Babe Ruth used during the 1932 World Series, including his famous 'Called Shot' home run. One of the most significant pieces of baseball memorabilia in existence.", imageUrl: "https://placeholder.pics/svg/400x300/DEDEDE/555555/Ruth%20Bat", isAuction: true }, { id: 'c10', title: "1952 Topps Mickey Mantle Rookie Card #311", category: "Cards", price: 5200000, year: 1952, condition: "Near Mint", rarity: "Very Rare", description: "The most valuable post-war baseball card in existence. This iconic Mickey Mantle rookie card from the 1952 Topps set is in exceptional condition.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Mantle%20Rookie", isAuction: false }, { id: 'c11', title: "Original Darth Vader Helmet from 'The Empire Strikes Back'", category: "Movies", price: 3500000, year: 1980, condition: "Very Good", rarity: "Unique", description: "Screen-used Darth Vader helmet worn by David Prowse during the filming of 'The Empire Strikes Back'. One of the most iconic props in film history.", imageUrl: "https://placeholder.pics/svg/300x400/DEDEDE/555555/Vader%20Helmet", isAuction: true }, { id: 'c12', title: "Original 'Rosebud' Sled from Citizen Kane", category: "Movies", price: 800000, year: 1941, condition: "Good", rarity: "Unique", description: "The original 'Rosebud' sled from the classic film Citizen Kane. One of the most famous movie props of all time and a piece of cinema history.", imageUrl: "https://placeholder.pics/svg/400x300/DEDEDE/555555/Rosebud%20Sled", isAuction: false } ]; // Generate additional items const categories = ["Comics", "Coins", "Art", "Toys", "Sports", "Movies", "Cards"]; const conditions = ["Mint", "Near Mint", "Excellent", "Very Good", "Good", "Fair", "Poor"]; const rarities = ["Common", "Uncommon", "Rare", "Very Rare", "Ultra Rare", "Unique"]; for (let i = 0; i < 50; i++) { const category = categories[Math.floor(Math.random() * categories.length)]; const condition = conditions[Math.floor(Math.random() * conditions.length)]; const rarity = rarities[Math.floor(Math.random() * rarities.length)]; const price = Math.floor(Math.random() * 50000) + 100; const year = Math.floor(Math.random() * 100) + 1920; const isAuction = Math.random() > 0.5; collectibles.push({ id: `additional-${i}`, title: `${category} Collectible Item #${i+1}`, category: category, price: price, year: year, condition: condition, rarity: rarity, description: `A ${condition.toLowerCase()} condition ${rarity.toLowerCase()} ${category.toLowerCase()} collectible from ${year}.`, imageUrl: `https://placeholder.pics/svg/300x300/DEDEDE/555555/${category}%20${i+1}`, isAuction: isAuction }); } return collectibles; } /** * Search for collectibles * @param {string} query - Search query * @param {object} filters - Optional filters */ function search(query, filters = {}) { if (!isInitialized) { console.warn('EnigmaticCollectiblesWidget not initialized. Call init() first.'); return; } if (collectiblesApp && collectiblesApp.search) { collectiblesApp.search(query, filters); } else { // Queue the search for when the app is ready messageQueue.push({ type: 'search', data: { query, filters } }); } } /** * Set the active category * @param {string} category - Category ID */ function setCategory(category) { if (!isInitialized) { console.warn('EnigmaticCollectiblesWidget not initialized. Call init() first.'); return; } if (collectiblesApp && collectiblesApp.setCategory) { collectiblesApp.setCategory(category); } else { // Queue the category change for when the app is ready messageQueue.push({ type: 'setCategory', data: { category } }); } } /** * Reset the widget to its initial state */ function reset() { if (!isInitialized) { console.warn('EnigmaticCollectiblesWidget not initialized. Call init() first.'); return; } if (collectiblesApp && collectiblesApp.reset) { collectiblesApp.reset(); } else { // Queue the reset for when the app is ready messageQueue.push({ type: 'reset', data: {} }); } } /** * Destroy the widget and clean up */ function destroy() { if (!isInitialized) { return; } // Clean up React app if (isReactDOMLoaded && widgetRoot) { ReactDOM.unmountComponentAtNode(widgetRoot); } // Remove elements if (widgetContainer) { widgetContainer.innerHTML = ''; } // Reset state isInitialized = false; isWidgetReady = false; messageQueue = []; collectiblesApp = null; // Create new ready promise readyPromise = new Promise(resolve => { readyResolver = resolve; }); } // Process any queued messages when the app is ready readyPromise.then(() => { while (messageQueue.length > 0) { const message = messageQueue.shift(); switch (message.type) { case 'search': search(message.data.query, message.data.filters); break; case 'setCategory': setCategory(message.data.category); break; case 'reset': reset(); break; } } }); // Export the public API window.EnigmaticCollectiblesWidget = { init, search, setCategory, reset, destroy, version: '1.0.0' }; })(window, document);