overview / js /main.js
Yacine Jernite
visuals
5daef86
raw
history blame
6.88 kB
// main.js
import { app } from './init.js';
import { teamMembers, teamTagData } from './data/team.js';
import { initializeSearchUI } from './utils/search.js';
// Use global background image (loaded in index.html <head>)
const overallBackgroundImage = window.overallBackgroundImage;
// Scroll to section utility
export function scrollToSection(sectionId) {
const element = document.getElementById(sectionId);
if (element) {
const elementRect = element.getBoundingClientRect();
const absoluteElementTop = elementRect.top + window.pageYOffset;
const offset = 120; // Account for fixed header + some padding
window.scrollTo({
top: absoluteElementTop - offset,
behavior: 'smooth'
});
}
}
// Team member component
export function createTeamMember(name, role, hfUsername, tags) {
const colors = ['blue', 'green', 'purple', 'orange', 'indigo', 'pink'];
const colorIndex = name.length % colors.length;
const color = colors[colorIndex];
const initials = name.split(' ').map(n => n[0]).join('');
const tagElements = tags.map(tag => {
const tagInfo = teamTagData[tag];
return `<span class="inline-block px-2.5 py-1 text-sm bg-gray-100 text-gray-700 rounded-full hover:bg-blue-100 hover:text-blue-800 cursor-pointer transition-colors whitespace-nowrap" onclick="window.scrollToSection('${tagInfo.id}')">${tagInfo.name}</span>`;
}).join('');
return `
<div class="flex items-start space-x-3 p-3 rounded-lg hover:bg-gray-50 transition-colors">
<div class="flex-shrink-0">
<div class="w-14 h-14 rounded-full overflow-hidden bg-gradient-to-br from-${color}-400 to-${color}-600 flex items-center justify-center relative">
<img
src="/images/${hfUsername}.jpeg"
alt="${name}"
class="w-full h-full object-cover"
loading="lazy"
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';"
/>
<span class="text-white font-semibold text-base hidden w-full h-full items-center justify-center absolute">${initials}</span>
</div>
</div>
<div class="flex-1 min-w-0">
<h4 class="font-semibold text-gray-900 text-base">
<a href="https://huggingface.co/${hfUsername}" class="hover:text-blue-600 transition-colors" target="_blank">
${name}
</a>
</h4>
<p class="text-sm text-gray-600 mb-1.5">${role}</p>
<div class="flex gap-1.5 overflow-x-auto scrollbar-hide">
${tagElements}
</div>
</div>
</div>
`;
}
// Make router's scrollToSection globally available for onclick handlers
window.scrollToSection = scrollToSection;
// Scroll to top functionality
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
// Make scrollToTop globally available
window.scrollToTop = scrollToTop;
// Note: Navigation handling moved to router.js for unified control
// Initialize scroll to top button functionality
function initializeScrollToTop() {
const scrollToTopBtn = document.getElementById('scroll-to-top');
if (!scrollToTopBtn) return;
// Add click event listener
scrollToTopBtn.addEventListener('click', scrollToTop);
// Show/hide button based on scroll position
function toggleScrollToTopButton() {
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
const showThreshold = 300; // Show button after scrolling 300px
if (scrollPosition > showThreshold) {
scrollToTopBtn.classList.remove('opacity-0', 'invisible');
scrollToTopBtn.classList.add('opacity-100', 'visible');
} else {
scrollToTopBtn.classList.remove('opacity-100', 'visible');
scrollToTopBtn.classList.add('opacity-0', 'invisible');
}
}
// Listen for scroll events
window.addEventListener('scroll', toggleScrollToTopButton);
// Initial check
toggleScrollToTopButton();
}
// Main UI initialization - called by bootstrap.js
export async function initializeUI() {
// Set overall background image
const backgroundImg = document.querySelector('#overall-background img');
if (backgroundImg) {
backgroundImg.src = `images/${overallBackgroundImage.image}`;
backgroundImg.alt = overallBackgroundImage.altText;
}
// Initialize scroll to top functionality
initializeScrollToTop();
// Initialize search UI with loaded artifacts
initializeSearchUI(window.allArtifacts || []);
// Initialize search sidebar toggle
initializeSearchToggle();
// Note: The router handles page-specific component initialization
// (e.g., team members, area cards) when loading each page
}
// Search sidebar toggle functionality
function initializeSearchToggle() {
const searchToggle = document.getElementById('search-toggle');
const searchSidebar = document.getElementById('search-sidebar');
const searchClose = document.getElementById('search-close');
const mainContent = document.getElementById('main-content');
const overlay = document.getElementById('sidebar-overlay');
function toggleSearch() {
const isOpen = !searchSidebar.classList.contains('translate-x-full');
const rightSidebarBg = document.getElementById('right-sidebar-background');
const isMobile = window.innerWidth < 768;
if (isOpen) {
searchSidebar.classList.add('translate-x-full');
rightSidebarBg.classList.add('hidden');
// Only adjust main content margin on desktop
if (!isMobile) {
mainContent.classList.remove('mr-80');
}
overlay.classList.add('hidden');
document.body.style.overflow = ''; // Re-enable scroll
} else {
searchSidebar.classList.remove('translate-x-full');
rightSidebarBg.classList.remove('hidden');
// Only adjust main content margin on desktop
if (!isMobile) {
mainContent.classList.add('mr-80');
}
overlay.classList.remove('hidden');
// Prevent body scroll on mobile when search is open
if (isMobile) {
document.body.style.overflow = 'hidden';
}
}
}
if (searchToggle) searchToggle.addEventListener('click', toggleSearch);
if (searchClose) searchClose.addEventListener('click', toggleSearch);
if (overlay) overlay.addEventListener('click', toggleSearch);
}