// Card.js - Unified card component // Uses template strings for HTML generation (simple, clear, and efficient for our use case) // All card types are defined here for consistency and maintainability import { renderTagSet } from '../utils/tags.js'; // Use global areasData (loaded in index.html ) const areasData = window.areasData; /** * Main card creation function * @param {string} type - Card type: 'artifact', 'area' * @param {object} data - Card data * @param {object} options - Additional options * @returns {string} HTML string for the card */ export function createCard(type, data, options = {}) { const renderers = { artifact: renderArtifactCard, area: renderAreaCard }; const renderer = renderers[type]; if (!renderer) { console.warn(`Unknown card type: ${type}`); return ''; } return renderer(data, options); } /** * Renders an artifact card (for carousels) */ function renderArtifactCard(artifact, options = {}) { const { index = 0, containerId = 'default' } = options; // Handle both old and new field names const title = artifact.title; const date = artifact.date; const type = artifact.type; const description = artifact.description; const areaTags = artifact.areas || artifact.areaTags || []; const subAreaTags = artifact.topics || artifact.subAreaTags || []; const sourceUrl = artifact.url || artifact.sourceUrl || ''; // Type-based styling const typeStyles = { 'blog': { icon: '📝', textColor: 'text-blue-700' }, 'paper': { icon: '📄', textColor: 'text-green-700' }, 'dataset': { icon: '📊', textColor: 'text-purple-700' }, 'space': { icon: '🚀', textColor: 'text-orange-700' }, 'external': { icon: '🔗', textColor: 'text-gray-700' } }; const style = typeStyles[type] || typeStyles['external']; // Get area data for background const primaryArea = areaTags[0]; const primaryAreaData = areasData[primaryArea]; const backgroundImage = primaryAreaData?.image || ''; const imageCredit = primaryAreaData?.imageAttribution || ''; // Render tags const { areaTagsHtml, topicTagsHtml } = renderTagSet(areaTags, subAreaTags); // Generate unique card ID by including container ID to avoid duplicates across multiple carousels const cardId = `artifact-card-${containerId}-${index}`; return `
${backgroundImage ? `
` : ''}
${style.icon} ${type}
${date}

${title}

${areaTagsHtml}
${subAreaTags.length > 0 ? `
${topicTagsHtml}
` : ''}
${backgroundImage ? `
${primaryAreaData.name}
` : ''}
${sourceUrl ? ` ` : ''}
`; } /** * Renders an area card (for homepage) */ function renderAreaCard(area, options = {}) { // Get short description const shortDesc = area.description?.short || area.description.split('.')[0] + '.'; // Get topic names and colors from the topics const topics = Object.values(area.topics).map(topic => { const topicName = topic.navName || topic.name; let bgColor = 'bg-gray-200'; let textColor = 'text-gray-700'; // Extract background and text color from the topic color class if (topic.color) { const bgMatch = topic.color.match(/bg-(\w+)-(\d+)/); const textMatch = topic.color.match(/text-(\w+)-(\d+)/); if (bgMatch) { bgColor = `bg-${bgMatch[1]}-${bgMatch[2]}`; } if (textMatch) { textColor = `text-${textMatch[1]}-700`; } } return { name: topicName, bgColor, textColor }; }); return ` ${area.image ? `
` : ''}

${area.title}

${shortDesc}

Topics:

${topics.map(topic => ` ${topic.name} `).join('')}
${area.imageAttribution ? `

${area.imageAttribution}

` : ''}
`; } // Export individual renderers for backward compatibility export { renderArtifactCard, renderAreaCard };