(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);