Spaces:
Running
Running
<script lang="ts"> | |
import Leaderboard from "./Leaderboard.svelte"; | |
import ModelDetails from "./ModelDetails.svelte"; | |
import Viewer from "./Viewer.svelte"; | |
import Vote from "./Vote.svelte"; | |
import About from "./About.svelte"; | |
import { Filter, CheckmarkOutline } from "carbon-icons-svelte"; | |
import { onMount } from "svelte"; | |
import { CaretDown, Code } from "carbon-icons-svelte"; | |
interface Scene { | |
name: string; | |
url: string; | |
thumbnail: string; | |
} | |
let currentView: "Leaderboard" | "Vote" | "ModelDetails" | "Viewer" | "About" = "Vote"; | |
let selectedEntry: { name: string } | null = null; | |
let selectedScene: Scene | null = null; | |
let showOnlyOpenSource = false; | |
let showFilter = false; | |
let filterContainer: HTMLDivElement; | |
function handleClickOutside(event: MouseEvent) { | |
if (filterContainer && !filterContainer.contains(event.target as Node)) { | |
showFilter = false; | |
} | |
} | |
onMount(() => { | |
document.addEventListener("click", handleClickOutside); | |
return () => { | |
document.removeEventListener("click", handleClickOutside); | |
}; | |
}); | |
function goHome() { | |
window.location.href = "/"; | |
} | |
function showModelDetails(entry: { name: string }) { | |
selectedEntry = entry; | |
currentView = "ModelDetails"; | |
} | |
function showScene(scene: Scene) { | |
selectedScene = scene; | |
currentView = "Viewer"; | |
} | |
</script> | |
<div class="container"> | |
<div on:pointerdown={goHome} class="banner"> | |
<h1>3D Arena</h1> | |
<p>Generative 3D Leaderboard</p> | |
</div> | |
{#if currentView === "Leaderboard" || currentView === "Vote" || currentView === "About"} | |
<div class="tabs"> | |
<button on:click={() => (currentView = "Vote")} class={currentView === "Vote" ? "active" : ""}>Vote</button> | |
<button on:click={() => (currentView = "Leaderboard")} class={currentView === "Leaderboard" ? "active" : ""} | |
>Leaderboard</button | |
> | |
<button on:click={() => (currentView = "About")} class={currentView === "About" ? "active" : ""} | |
>About</button | |
> | |
{#if currentView === "Leaderboard"} | |
<div class="filter-container" bind:this={filterContainer}> | |
<button | |
class="filter-button" | |
on:click={() => (showFilter = !showFilter)} | |
aria-expanded={showFilter} | |
aria-haspopup="true" | |
> | |
<Filter size={20} /> | |
<CaretDown size={16} class="caret" /> | |
</button> | |
{#if showFilter} | |
<div class="filter-dropdown" role="menu" aria-label="Filter options"> | |
<div class="filter-section"> | |
<div class="filter-section-title">Filter Options</div> | |
<div | |
class="filter-option {showOnlyOpenSource ? 'active' : ''}" | |
on:click={() => (showOnlyOpenSource = !showOnlyOpenSource)} | |
on:keydown={(e) => e.key === "Enter" && (showOnlyOpenSource = !showOnlyOpenSource)} | |
role="menuitemcheckbox" | |
aria-checked={showOnlyOpenSource} | |
tabindex="0" | |
> | |
<div class="filter-label"> | |
<Code size={16} class="filter-icon" /> | |
Open source | |
</div> | |
<span class="filter-checkbox">✓</span> | |
</div> | |
</div> | |
</div> | |
{/if} | |
</div> | |
{/if} | |
</div> | |
{/if} | |
{#if currentView === "Leaderboard"} | |
<Leaderboard onEntryClick={showModelDetails} {showOnlyOpenSource} /> | |
{:else if currentView === "Vote"} | |
<Vote /> | |
{:else if currentView === "ModelDetails" && selectedEntry} | |
<ModelDetails | |
modelName={selectedEntry.name} | |
onBack={() => (currentView = "Leaderboard")} | |
onSceneClick={showScene} | |
/> | |
{:else if currentView === "Viewer" && selectedScene && selectedEntry} | |
<Viewer modelName={selectedEntry.name} scene={selectedScene} onBack={() => (currentView = "ModelDetails")} /> | |
{:else if currentView === "About"} | |
<About /> | |
{/if} | |
</div> | |