|
|
|
|
|
import { app } from './init.js'; |
|
|
import { teamMembers, teamTagData } from './data/team.js'; |
|
|
import { initializeSearchUI } from './utils/search.js'; |
|
|
|
|
|
|
|
|
const overallBackgroundImage = window.overallBackgroundImage; |
|
|
|
|
|
|
|
|
export function scrollToSection(sectionId) { |
|
|
const element = document.getElementById(sectionId); |
|
|
if (element) { |
|
|
const elementRect = element.getBoundingClientRect(); |
|
|
const absoluteElementTop = elementRect.top + window.pageYOffset; |
|
|
const offset = 120; |
|
|
|
|
|
window.scrollTo({ |
|
|
top: absoluteElementTop - offset, |
|
|
behavior: 'smooth' |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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> |
|
|
`; |
|
|
} |
|
|
|
|
|
|
|
|
window.scrollToSection = scrollToSection; |
|
|
|
|
|
|
|
|
function scrollToTop() { |
|
|
window.scrollTo({ |
|
|
top: 0, |
|
|
behavior: 'smooth' |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
window.scrollToTop = scrollToTop; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function initializeScrollToTop() { |
|
|
const scrollToTopBtn = document.getElementById('scroll-to-top'); |
|
|
if (!scrollToTopBtn) return; |
|
|
|
|
|
|
|
|
scrollToTopBtn.addEventListener('click', scrollToTop); |
|
|
|
|
|
|
|
|
function toggleScrollToTopButton() { |
|
|
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop; |
|
|
const showThreshold = 300; |
|
|
|
|
|
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'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
window.addEventListener('scroll', toggleScrollToTopButton); |
|
|
|
|
|
|
|
|
toggleScrollToTopButton(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export async function initializeUI() { |
|
|
|
|
|
const backgroundImg = document.querySelector('#overall-background img'); |
|
|
if (backgroundImg) { |
|
|
backgroundImg.src = `images/${overallBackgroundImage.image}`; |
|
|
backgroundImg.alt = overallBackgroundImage.altText; |
|
|
} |
|
|
|
|
|
|
|
|
initializeScrollToTop(); |
|
|
|
|
|
|
|
|
initializeSearchUI(window.allArtifacts || []); |
|
|
|
|
|
|
|
|
initializeSearchToggle(); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
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'); |
|
|
|
|
|
if (!isMobile) { |
|
|
mainContent.classList.remove('mr-80'); |
|
|
} |
|
|
overlay.classList.add('hidden'); |
|
|
document.body.style.overflow = ''; |
|
|
} else { |
|
|
searchSidebar.classList.remove('translate-x-full'); |
|
|
rightSidebarBg.classList.remove('hidden'); |
|
|
|
|
|
if (!isMobile) { |
|
|
mainContent.classList.add('mr-80'); |
|
|
} |
|
|
overlay.classList.remove('hidden'); |
|
|
|
|
|
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); |
|
|
} |