// pages/AreaPage.js - Reusable area page component import { areasData } from '../data/areas.js'; import { featuredArtifacts } from '../data/artifacts.js'; import { createArtifactCarousel } from '../cards/ArtifactSummaryCard.js'; import { sampleResources } from '../data/resources.js'; import { createResourceCard, initializeResourceCards } from '../cards/ResourceCard.js'; export function renderAreaPage(areaId) { const area = areasData[areaId]; if (!area) { return { content: `

Area not found

`, init: () => {} }; } // Filter resources by area const areaResources = sampleResources.filter(resource => resource.areaTags.includes(areaId) ); // Get sub-areas as array for easier processing const subAreas = Object.entries(area.subAreas).map(([key, value]) => ({ id: key, name: typeof value === 'string' ? value : value.name, description: typeof value === 'string' ? '' : (value.description || ''), openness: typeof value === 'string' ? '' : (value.openness || ''), gradient: typeof value === 'object' ? value.gradient : null })); const content = `
${area.imageAttribution}

${area.title}

${area.description}

🤗 The Role of Openness

${area.openness}

Explore Sub-areas

${subAreas.map(subArea => `

${subArea.name}

`).join('')}
${subAreas.map(subArea => `

${subArea.name}

${subArea.description ? `

${subArea.description}

` : ''} ${subArea.openness ? `

🤗 The Role of Openness

${subArea.openness}

` : ''}

Related Research & Resources

`).join('')}

Technical Resources

Technical resources and tools related to ${area.name.toLowerCase()} research and development.

`; return { content, init: () => { // Initialize artifact carousels for each sub-area with a small delay // to ensure DOM elements are fully rendered setTimeout(() => { subAreas.forEach(subArea => { // For now, show all artifacts in each carousel // Later this will be filtered by the backend const carouselId = `${subArea.id}-artifacts-carousel`; createArtifactCarousel(featuredArtifacts, carouselId); }); }, 50); // Initialize resource cards initializeResourceCards(); // Initialize resource carousel if there are resources if (areaResources.length > 0) { initializeAreaResourceCarousel(areaResources); } // Initialize background attribution initializeAreaBackgroundAttribution(); } }; } export function getAreaPageSidebar(areaId) { const area = areasData[areaId]; if (!area) { return '
Area not found
'; } const subAreas = Object.entries(area.subAreas).map(([key, value]) => ({ id: key, name: typeof value === 'string' ? value : value.name })); return ` `; } function initializeAreaResourceCarousel(resources) { const carousel = document.querySelector('.resource-carousel'); const prevButton = document.querySelector('.resource-carousel-prev'); const nextButton = document.querySelector('.resource-carousel-next'); if (!carousel || !prevButton || !nextButton) { return; } let currentIndex = 0; const cardWidth = 624; // 600px card + 24px gap const visibleCards = 1.5; // Show 1.5 cards at a time (larger cards) const maxIndex = resources.length - 1; // Allow going to the last item function updateCarousel() { const translateX = -currentIndex * cardWidth; carousel.style.transform = `translateX(${translateX}px)`; // Update button states - no disabled states for looping prevButton.classList.remove('opacity-50', 'cursor-not-allowed'); nextButton.classList.remove('opacity-50', 'cursor-not-allowed'); } prevButton.addEventListener('click', () => { currentIndex = currentIndex > 0 ? currentIndex - 1 : maxIndex; updateCarousel(); }); nextButton.addEventListener('click', () => { currentIndex = currentIndex < maxIndex ? currentIndex + 1 : 0; updateCarousel(); }); // Initialize carousel state updateCarousel(); } function initializeAreaBackgroundAttribution() { const backgroundContainer = document.getElementById('area-background-container'); const attribution = document.getElementById('area-bg-attribution'); if (!backgroundContainer || !attribution) { return; } // Show attribution on hover over the background container backgroundContainer.addEventListener('mouseenter', () => { attribution.style.opacity = '1'; }); backgroundContainer.addEventListener('mouseleave', () => { attribution.style.opacity = '0'; }); } // Colors are now defined in the areas data and accessed via subArea.gradient