Spaces:
Running
Running
| <script lang="ts"> | |
| import { onMount } from "svelte"; | |
| import { ProgressBarRound } from "carbon-icons-svelte"; | |
| import { getConfig } from "./utils/getConfig"; | |
| interface Entry { | |
| name: string; | |
| rank: number; | |
| score: number; | |
| votes: number; | |
| open_source: boolean; | |
| displayName?: string; | |
| } | |
| export let onEntryClick: (entry: Entry) => void; | |
| export let showOnlyOpenSource: boolean; | |
| export let voteType: string = "render"; | |
| const baseUrl = "https://huggingface.co/datasets/dylanebert/3d-arena/resolve/main/outputs"; | |
| let leaderboard: Entry[] = []; | |
| let filteredLeaderboard: Entry[] = []; | |
| let isLoading = false; | |
| const fetchLeaderboardData = async () => { | |
| isLoading = true; | |
| try { | |
| const url = `/api/leaderboard?vote_type=${voteType}`; | |
| const response = await fetch(url, { | |
| method: "GET", | |
| headers: { | |
| "Cache-Control": "no-cache", | |
| }, | |
| }); | |
| const data = (await response.json()) as Entry[]; | |
| const entriesWithDisplayNames = await Promise.all( | |
| data.map(async (entry) => { | |
| const config = await getConfig(entry.name); | |
| return { ...entry, displayName: config.DisplayName || entry.name }; | |
| }), | |
| ); | |
| entriesWithDisplayNames.sort((a, b) => a.rank - b.rank); | |
| leaderboard = entriesWithDisplayNames; | |
| updateFilteredLeaderboard(); | |
| } finally { | |
| isLoading = false; | |
| } | |
| }; | |
| const updateFilteredLeaderboard = () => { | |
| filteredLeaderboard = showOnlyOpenSource | |
| ? leaderboard.filter((entry) => entry.open_source) | |
| : leaderboard; | |
| }; | |
| $: { | |
| showOnlyOpenSource; | |
| updateFilteredLeaderboard(); | |
| } | |
| $: { | |
| voteType; | |
| fetchLeaderboardData(); | |
| } | |
| onMount(async () => { | |
| await fetchLeaderboardData(); | |
| }); | |
| </script> | |
| {#if isLoading} | |
| <div class="loading-container"> | |
| <ProgressBarRound class="loading-icon" /> | |
| <div class="loading-text">Loading...</div> | |
| </div> | |
| {:else if filteredLeaderboard.length > 0} | |
| <div class="grid"> | |
| {#each filteredLeaderboard as entry, index} | |
| <button class="grid-item" on:click={() => onEntryClick(entry)}> | |
| <img | |
| src={`${baseUrl}/${entry.name}/thumbnail.png`} | |
| alt={entry.name} | |
| class="thumbnail" | |
| /> | |
| <div class="ranking">{index + 1}</div> | |
| <div class="title">{entry.displayName}</div> | |
| <div class="score-container"> | |
| <div class="score"> | |
| <span class="label">Score:</span> | |
| {entry.score} | |
| </div> | |
| <div class="votes"> | |
| <span class="label">Votes:</span> | |
| {entry.votes} | |
| </div> | |
| </div> | |
| </button> | |
| {/each} | |
| </div> | |
| {:else} | |
| <div class="loading-container"> | |
| <ProgressBarRound class="loading-icon" /> | |
| <div class="loading-text">Loading...</div> | |
| </div> | |
| {/if} | |