3d-arena / src /routes /+page.svelte
dylanebert
open source filter option
5e88463
<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>