| function searchModel() { |
| const keyword = document.getElementById('searchKeyword').value.trim(); |
| if (keyword) { |
| const domain = window.location.hostname; |
| const url = `https://${domain}/models?search=${encodeURIComponent(keyword)}`; |
| window.location.href = url; |
| } |
| } |
|
|
| let isDropdownNavigationActive = false; |
| document.getElementById('searchKeyword').addEventListener('keypress', function (event) { |
| if (event.keyCode === 13) { |
| event.preventDefault(); |
| if (!isDropdownNavigationActive) { |
| searchModel(); |
| } else { |
| |
| |
| |
| |
| |
| const items = document.querySelectorAll('.search-result-item'); |
| if (selectedIndex > -1) { |
| items[selectedIndex].click(); |
| } |
| } |
| isDropdownNavigationActive = false; |
| } |
| }); |
| let debounceTimer; |
| const searchInput = document.getElementById('searchKeyword'); |
| const searchResults = document.getElementById('searchResults'); |
| let abortController; |
|
|
| function search(){ |
| selectedIndex = -1; |
| clearTimeout(debounceTimer); |
| debounceTimer = setTimeout(async function () { |
| const query = searchInput.value.trim(); |
| if (query) { |
| |
| if (abortController) { |
| abortController.abort(); |
| } |
|
|
| |
| abortController = new AbortController(); |
| sessionStorage.setItem('searchKeyword', query); |
| try { |
| const response = await fetch(`https://hf-mirror.com/api/quicksearch?q=${encodeURIComponent(query)}&type=model&type=dataset`, { signal: abortController.signal }); |
| const data = await response.json(); |
| let resultsHtml = ''; |
| ['models', 'datasets'].forEach(type => { |
| if (data[type]) { |
| resultsHtml += `<div class="search-result-type"><strong>${type}</strong></div>`; |
| data[type].forEach(item => { |
| resultsHtml += `<div class="search-result-item" onclick="openLink('/${type === 'models' ? '' : type + '/'}${item.id}')">${item.id}</div>`; |
| }); |
| } |
| }); |
| searchResults.innerHTML = resultsHtml; |
| searchResults.style.display = 'block'; |
| |
| } catch (error) { |
| if (error.name === 'AbortError') { |
| |
| } else { |
| |
| console.error(error); |
| } |
| } |
| } else { |
| searchResults.innerHTML = ''; |
| searchResults.style.display = 'none'; |
| } |
| }, 300); |
| } |
| searchInput.addEventListener('input', function () { |
| search(); |
| }); |
|
|
|
|
| searchInput.addEventListener('focus', function () { |
| if (searchInput.value.trim()) { |
| search(); |
| |
| } |
| }); |
|
|
| searchInput.addEventListener('blur', function () { |
| setTimeout(function () { |
| searchResults.style.display = 'none'; |
| }, 2000); |
| }); |
|
|
| function openLink(url) { |
| |
| |
| window.location.href = url; |
| } |
|
|
| function copyCode(btn) { |
| const code = btn.previousElementSibling.textContent; |
| navigator.clipboard.writeText(code).then(() => { |
| btn.textContent = 'Copied!'; |
| setTimeout(() => { |
| btn.textContent = 'Copy'; |
| }, 2000); |
| }); |
| } |
|
|
|
|
|
|
| document.addEventListener("DOMContentLoaded", function () { |
| const donateArea = document.querySelector('.donate'); |
| const qrcode = document.querySelector('.qrcode'); |
|
|
| |
| const isMobile = /Mobi|Android/i.test(navigator.userAgent); |
|
|
| if (isMobile) { |
| |
| donateArea.addEventListener('click', function () { |
| qrcode.classList.toggle('show-qrcode'); |
| }); |
| } else { |
| |
| } |
| }); |
|
|
| document.addEventListener("DOMContentLoaded", function () { |
| const donateArea = document.querySelector('.groups'); |
| const qrcode = document.querySelector('.groups_qrcode'); |
|
|
| |
| const isMobile = /Mobi|Android/i.test(navigator.userAgent); |
|
|
| if (isMobile) { |
| |
| donateArea.addEventListener('click', function () { |
| qrcode.classList.toggle('show-qrcode'); |
| }); |
| } else { |
| |
| } |
| }); |
|
|
| let selectedIndex = -1; |
|
|
| searchInput.addEventListener('keydown', function (event) { |
| const items = document.querySelectorAll('.search-result-item'); |
| if (event.key === 'ArrowDown') { |
| isDropdownNavigationActive = true; |
| |
| if (selectedIndex < items.length - 1) { |
| selectedIndex++; |
| items[selectedIndex].classList.add('selected'); |
| if (selectedIndex > 0) { |
| items[selectedIndex - 1].classList.remove('selected'); |
| } |
| } |
| } else if (event.key === 'ArrowUp') { |
| isDropdownNavigationActive = true; |
| |
| if (selectedIndex > 0) { |
| selectedIndex--; |
| items[selectedIndex].classList.add('selected'); |
| items[selectedIndex + 1].classList.remove('selected'); |
| } |
| } else if (event.key === 'Enter') { |
| |
| if (selectedIndex > -1) { |
| items[selectedIndex].click(); |
| } |
| } |
| }); |
|
|
|
|
| window.addEventListener('pageshow', function () { |
| const storedKeyword = sessionStorage.getItem('searchKeyword'); |
| if (storedKeyword !== null) { |
| |
| searchInput.value = storedKeyword; |
| |
| |
| |
| |
| |
| } |
| }); |
| |
| const config = { |
| models: { |
| url: "https://hf-mirror.com/models-json?sort=trending", |
| containerSelector: '.models ul', |
| itemTemplate: (item) => ` |
| <span class="model-id">${item.id}</span> |
| <div class="model-info"> |
| <span class="model-downloads">⬇️${item.downloads}</span> |
| <span class="model-likes">❤️${item.likes}</span> |
| </div> |
| ` |
| }, |
| datasets: { |
| url: "https://hf-mirror.com/models-json?sort=trending", |
| containerSelector: '.dataset ul', |
| itemTemplate: (item) => ` |
| <span class="model-id">${item.id}</span> |
| <div class="model-info"> |
| <span class="model-downloads">⬇️${item.downloads}</span> |
| <span class="model-likes">❤️${item.likes}</span> |
| </div> |
| ` |
| } |
| }; |
|
|
| |
| function fetchAndRenderList({ url, containerSelector, itemTemplate }, limit = 10) { |
| fetch(url) |
| .then(response => response.json()) |
| .then(data => { |
| const items = data["models"]; |
| if (!items || !Array.isArray(items)) { |
| throw new Error('Invalid data format'); |
| } |
| const container = document.querySelector(containerSelector); |
| if (!container) { |
| throw new Error('List container element not found'); |
| } |
| container.innerHTML = ''; |
| items.slice(0, limit).forEach(item => { |
| const li = document.createElement('li'); |
| li.innerHTML = itemTemplate(item); |
| container.appendChild(li); |
| }); |
| }) |
| .catch(error => { |
| console.error('Error:', error); |
| }); |
| } |
|
|
| function timeAgo(date) { |
| const now = new Date(); |
| const updatedDate = new Date(date); |
| const diffTime = Math.abs(now - updatedDate); |
| const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); |
| if (diffDays < 60) { |
| return `${diffDays}天前更新`; |
| } else { |
| |
| const year = updatedDate.getFullYear(); |
| let month = updatedDate.getMonth() + 1; |
| let day = updatedDate.getDate(); |
|
|
| |
| month = month < 10 ? '0' + month : month; |
| day = day < 10 ? '0' + day : day; |
|
|
| |
| return `${year}-${month}-${day}更新`; |
| } |
| } |
|
|
| function abbreviateNumber(num) { |
| if (num >= 1000000) { |
| return `${(num / 1000000).toFixed(1)}M`; |
| } else if (num >= 1000) { |
| return `${(num / 1000).toFixed(1)}k`; |
| } else { |
| return num; |
| } |
| } |
| let isExpanded = false; |
| let maxItemsToShow = 3; |
|
|
| document.addEventListener('DOMContentLoaded', function () { |
| const screenWidth = window.innerWidth; |
| if (sessionStorage.getItem('isExpanded')){ |
| isExpanded = sessionStorage.getItem('isExpanded') === 'true'; |
| } |
| else { |
| isExpanded = screenWidth >= 650; |
| sessionStorage.setItem('isExpanded', isExpanded); |
| } |
|
|
|
|
| async function fetchTrending(type) { |
| let data = sessionStorage.getItem(`rankingList_${type}`); |
| let expiry = sessionStorage.getItem(`expiry_ranking`); |
| const now = new Date().getTime(); |
|
|
| if (!data || !expiry || now >= expiry) { |
| const response = await fetch(`https://hf-mirror.com/api/trending?limit=10&type=${type}`); |
| data = await response.json(); |
| expiry = new Date().getTime() + 1 * 60 * 1000; |
| sessionStorage.setItem(`rankingList_${type}`, JSON.stringify(data)); |
| sessionStorage.setItem(`expiry_ranking`, expiry); |
| } |
| else { |
| data = JSON.parse(data); |
| } |
| const filteredData = data.recentlyTrending.filter(item => item.repoType !== 'space'); |
| lastScrollPosition = 0; |
| updateTrendingItems(filteredData.slice(0, 10)); |
| } |
|
|
| function updateTrendingItems(items) { |
| const container = document.getElementById('trendingItems'); |
| container.innerHTML = ''; |
|
|
| maxItemsToShow = screenWidth > 650 ? 10: 3; |
| items.forEach((item, index) => { |
| const element = createTrendingItemElement(item, index); |
| container.appendChild(element); |
| }); |
|
|
| updateToggleButton(); |
| } |
|
|
| function createTrendingItemElement(item, index) { |
| const element = document.createElement('div'); |
| element.className = 'trending-item'; |
| if (index >= maxItemsToShow && !isExpanded) { |
| element.classList.add('hidden-item'); |
| } |
| element.innerHTML = getTrendingItemHTML(item, index); |
| return element; |
| } |
|
|
| function getTrendingItemHTML(item, index) { |
| const repoId = item.repoData.id; |
| const repoLink = item.repoType === 'model' ? repoId : `/${item.repoType}s/${repoId}`; |
| const pipeline_tag = item.repoData.pipeline_tag; |
| const pipelineTagHTML = pipeline_tag ? `<a class="pipeline-tag" href="/models?pipeline_tag=${pipeline_tag}">${pipeline_tag}</a>` : ''; |
| const downloadCountHTML = item.repoData.downloads ? `<span class="count">${abbreviateNumber(item.repoData.downloads)}</span>` : `<span class="count">-</span>`; |
| let logoHTML; |
| switch (item.repoType) { |
| case 'model': |
| logoHTML = `<img class="model-logo" src="${item.repoData.authorData.avatarUrl}" alt="${item.repoData.author}" title="${item.repoData.authorData.fullname}">`; |
| break; |
| case 'dataset': |
| logoHTML = `<svg class="model-logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 25 25"><ellipse cx="12.5" cy="5" fill="currentColor" fill-opacity="0.25" rx="7.5" ry="2"></ellipse><path d="M12.5 15C16.6421 15 20 14.1046 20 13V20C20 21.1046 16.6421 22 12.5 22C8.35786 22 5 21.1046 5 20V13C5 14.1046 8.35786 15 12.5 15Z" fill="currentColor" opacity="0.5"></path><path d="M12.5 7C16.6421 7 20 6.10457 20 5V11.5C20 12.6046 16.6421 13.5 12.5 13.5C8.35786 13.5 5 12.6046 5 11.5V5C5 6.10457 8.35786 7 12.5 7Z" fill="currentColor" opacity="0.5"></path><path d="M5.23628 12C5.08204 12.1598 5 12.8273 5 13C5 14.1046 8.35786 15 12.5 15C16.6421 15 20 14.1046 20 13C20 12.8273 19.918 12.1598 19.7637 12C18.9311 12.8626 15.9947 13.5 12.5 13.5C9.0053 13.5 6.06886 12.8626 5.23628 12Z" fill="currentColor"></path></svg>`; |
| break; |
| case 'space': |
| logoHTML = `<img class="model-logo" src="${item.repoData.authorData.avatarUrl}" alt="${item.repoData.author}">`; |
| break; |
| default: |
| console.log('BUG'); |
| } |
| return ` |
| <div class="repo-content"> |
| <div class="item-rank">#${index + 1}</div> |
| ${logoHTML} |
| <div class="item-info"> |
| <a class= "repo-link" href="${repoLink}"> |
| <div class="model-name">${repoId}</div> |
| </a> |
| <div class="stats-line"> |
| ${pipelineTagHTML} |
| <div class="other-stats"> |
| <div class="stats-detail"> |
| <span>${timeAgo(item.repoData.lastModified)}</span> |
| </div> |
| <div class="stats-icons"> |
| <span class="downloads"> |
| <span class="svg-placeholder"><svg class="flex-none w-3 text-gray-400 mr-0.5" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" role="img" width="1em" height="1em" viewBox="0 0 32 32"><path fill="currentColor" d="M26 24v4H6v-4H4v4a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-4zm0-10l-1.41-1.41L17 20.17V2h-2v18.17l-7.59-7.58L6 14l10 10l10-10z"></path></svg></span> |
| <span class="count">${downloadCountHTML}</span> |
| </span> |
| <span class="likes"> |
| <span class="svg-placeholder"><svg class="flex-none w-3 text-gray-400 mr-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32" fill="currentColor"><path d="M22.45,6a5.47,5.47,0,0,1,3.91,1.64,5.7,5.7,0,0,1,0,8L16,26.13,5.64,15.64a5.7,5.7,0,0,1,0-8,5.48,5.48,0,0,1,7.82,0L16,10.24l2.53-2.58A5.44,5.44,0,0,1,22.45,6m0-2a7.47,7.47,0,0,0-5.34,2.24L16,7.36,14.89,6.24a7.49,7.49,0,0,0-10.68,0,7.72,7.72,0,0,0,0,10.82L16,29,27.79,17.06a7.72,7.72,0,0,0,0-10.82A7.49,7.49,0,0,0,22.45,4Z"></path></svg></span> |
| <span class="count">${abbreviateNumber(item.likes)}</span> |
| </span> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div> |
| `; |
| } |
|
|
| let lastScrollPosition = 0; |
| function updateToggleButton() { |
| const toggleButton = document.getElementById('toggleButton'); |
| if (!isExpanded) { |
| window.scrollTo({ top: lastScrollPosition, behavior: 'smooth' }); |
| } |
| toggleButton.classList.toggle('hidden', isExpanded); |
| toggleButton.innerText = isExpanded ? '收起' : '展开'; |
| if (isExpanded) { |
| lastScrollPosition = window.scrollY; |
| } |
| } |
|
|
| document.getElementById('toggleButton').addEventListener('click', toggleVisibility); |
| document.querySelectorAll('.tab').forEach(tab => tab.addEventListener('click', handleTabClick)); |
|
|
|
|
| const tabs = document.querySelectorAll('.tab'); |
| const savedTabType = sessionStorage.getItem('activeTabType'); |
| if (savedTabType) { |
| tabs.forEach(tab => { |
| if (tab.getAttribute('data-type') === savedTabType) { |
| tab.click(); |
| } |
| }); |
| } |
| else if (tabs.length > 0) { |
| tabs[0].click(); |
| } |
|
|
| function toggleVisibility() { |
| isExpanded = !isExpanded; |
| sessionStorage.setItem('isExpanded', isExpanded); |
| document.querySelectorAll('.trending-item').forEach((item, index) => { |
| if (index >= maxItemsToShow) item.classList.toggle('hidden-item', !isExpanded); |
| }); |
| updateToggleButton(); |
| } |
|
|
| function handleTabClick() { |
| if (this.classList.contains('active')) return; |
| document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); |
| this.classList.add('active'); |
| const type = this.getAttribute('data-type'); |
| |
| sessionStorage.setItem('activeTabType', type); |
| displayMoreButton(type); |
| fetchTrending(type); |
| } |
|
|
| function displayMoreButton(type) { |
| let moreItemsLink = document.getElementById('moreItems'); |
| if (type === 'all') { |
| |
| } else { |
| moreItemsLink.style.display = 'block'; |
| let href = '/' + type + 's'; |
| moreItemsLink.setAttribute('href', href); |
| } |
| } |
|
|
| window.addEventListener('resize', adjustDisplayBasedOnWidth); |
| }); |
|
|
| function adjustDisplayBasedOnWidth() { |
| const screenWidth = window.innerWidth; |
|
|
| maxItemsToShow = screenWidth > 650 ? 10: 3; |
| const items = document.querySelectorAll('.trending-item'); |
| items.forEach((item, index) => { |
| if (index < maxItemsToShow || isExpanded) { |
| item.classList.remove('hidden-item'); |
| } else { |
| item.classList.add('hidden-item'); |
| } |
| }); |
| toggleButton.innerText = isExpanded ? '收起' : '展开'; |
| } |
|
|
| window.addEventListener('beforeunload', function () { |
| sessionStorage.setItem('expiry_ranking', new Date().getTime()); |
| }); |