File size: 6,823 Bytes
aeeb334 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
// cards/ResourceCard.js - Resource card component for SPA
import { areasData } from '../data/areas.js';
export function createResourceCard(resource) {
// Get the primary area for this resource
const primaryArea = areasData[resource.areaTags[0]];
const primaryColor = primaryArea?.primaryColor || 'gray';
// Format date
const formattedDate = new Date(resource.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
// Generate area tags
const areaTagsHtml = resource.areaTags.map(areaId => {
const area = areasData[areaId];
if (!area) return '';
return `<span class="px-2 py-1 rounded-full text-xs font-medium ${area.colors.medium}">${area.name}</span>`;
}).join('');
// Generate sub-area tags
const subAreaTagsHtml = resource.subAreaTags.map(subAreaKey => {
// Find the sub-area name and color by looking through all areas
let subAreaName = subAreaKey; // fallback to key if not found
let textColor = 'text-gray-700'; // fallback color
for (const areaKey in areasData) {
const area = areasData[areaKey];
if (area.subAreas && area.subAreas[subAreaKey]) {
const subArea = area.subAreas[subAreaKey];
subAreaName = typeof subArea === 'string' ? subArea : subArea.name;
// Extract just the text color from the sub-area color
if (typeof subArea === 'object' && subArea.color) {
const colorMatch = subArea.color.match(/text-(\w+)-(\d+)/);
if (colorMatch) {
textColor = `text-${colorMatch[1]}-700`; // Use consistent 700 shade
}
}
break;
}
}
return `<span class="inline-block px-2 py-0.5 text-xs bg-gray-200 ${textColor} rounded">${subAreaName}</span>`;
}).join('');
// Type badge
const typeBadge = resource.type === 'dataset' ? 'Dataset' : 'Tool';
const typeColor = resource.type === 'dataset' ? 'bg-blue-100 text-blue-800' : 'bg-green-100 text-green-800';
return `
<div class="resource-card bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden flex-shrink-0 relative" style="height: 600px; width: 600px;">
<!-- Top Section - Single view with all information -->
<div class="resource-card-top h-48 bg-gradient-to-br from-${primaryColor}-50 to-${primaryColor}-100 relative overflow-hidden">
<!-- Background image for top section -->
<div class="absolute inset-0 opacity-10">
<img src="images/${primaryArea?.image || 'ai.png'}" alt="" class="w-full h-full object-cover">
</div>
<div class="relative z-10 p-4 h-full flex flex-col">
<!-- Header with type, link, and date -->
<div class="flex items-center justify-between mb-3">
<div class="flex items-center gap-2">
<span class="px-2 py-1 rounded-full text-xs font-medium ${typeColor}">${typeBadge}</span>
<a href="${resource.url}" target="_blank" class="text-xs text-blue-600 hover:text-blue-800 flex items-center">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
</svg>
View Resource
</a>
</div>
<span class="text-xs text-gray-600">${formattedDate}</span>
</div>
<!-- Title -->
<h3 class="text-lg font-semibold text-gray-900 mb-3 leading-tight">${resource.title}</h3>
<!-- Description -->
<p class="text-sm text-gray-700 mb-3 flex-1 overflow-hidden" style="display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;">
${resource.description}
</p>
<!-- Footer with tags and area image -->
<div class="flex items-center justify-between">
<div class="flex flex-wrap gap-1 flex-1">
${areaTagsHtml}
${subAreaTagsHtml}
</div>
<div class="w-8 h-8 rounded-full bg-white bg-opacity-50 flex items-center justify-center ml-3 flex-shrink-0">
<img src="images/${primaryArea?.image || 'ai.png'}" alt="" class="w-6 h-6 rounded-full object-cover">
</div>
</div>
</div>
</div>
<!-- Bottom Section - 70% of height -->
<div class="resource-card-bottom relative" style="height: 420px;">
${resource.embedUrl ? `
<!-- Iframe embed -->
<iframe
src="${resource.embedUrl}"
class="w-full h-full border-0"
loading="lazy"
title="${resource.title}"
></iframe>
` : `
<!-- Fallback with background image and text -->
<div class="w-full h-full relative overflow-hidden">
<div class="absolute inset-0 opacity-50">
<img src="images/${primaryArea?.image || 'ai.png'}" alt="" class="w-full h-full object-cover">
</div>
<div class="absolute inset-0 bg-black bg-opacity-20 flex items-center justify-center">
<div class="text-center text-white">
<div class="text-lg font-semibold mb-2">Iframe not available</div>
<a href="${resource.url}" target="_blank" class="text-sm text-blue-200 hover:text-blue-100 underline">
View on external site
</a>
</div>
</div>
</div>
`}
</div>
</div>
`;
}
export function initializeResourceCards() {
// Resource cards now have a single view, no toggle functionality needed
// This function is kept for consistency with the calling code
}
|