theme-gallery / index.html
abidlabs's picture
abidlabs HF staff
Update index.html (#3)
f6b7f82 verified
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Gradio theme gallery</title>
<meta name="description" content="Discover all gradio themes created by the community." />
<meta property="og:url" content="https://freddyaboulton-gradio-themes-gallery.hf.space/" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Gradio - Theme Gallery" />
<meta property="og:description" content="Discover all gradio themes created by the community." />
<meta property="og:image" content="https://huggingface-projects-diffusers-gallery.hf.space/Fo6vR6JX0AEjbw1.jpeg" />
<meta name="twitter:card" content="player" />
<meta property="twitter:url" content="https://freddyaboulton-gradio-themes-gallery.hf.space/" />
<meta name="twitter:description" content="Discover all gradio themes created by the community." />
<meta name="twitter:site" content="@huggingface" />
<meta name="twitter:title" content="Gradio - Theme Gallery" />
<meta name="twitter:image" content="https://huggingface-projects-diffusers-gallery.hf.space/Fo6vR6JX0AEjbw1.jpeg" />
<meta name="twitter:player" content="https://freddyaboulton-gradio-themes-gallery.hf.space/index.html" />
<meta name="twitter:player:width" content="100%" />
<meta name="twitter:player:height" content="600" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
iframe {
display: block;
border: none;
width: 100%;
height: 600px;
pointer-events: none;
}
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-gap: 10px;
margin-top: 3.5rem;
}
.grid-item {
position: relative;
overflow-y: hidden;
border-radius: 10px;
border: 1px solid rgb(55 65 81);
}
.grid-item:hover {
filter: brightness(75%);
}
.grid-item a {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
z-index: 1;
}
</style>
<script type="module">
import Alpine from "https://cdn.skypack.dev/alpinejs@3.13.9";
import Intersect from "https://cdn.skypack.dev/@alpinejs/intersect";
Alpine.plugin(Intersect);
Alpine.data("themesData", () => ({
async init() {
const data = await this.getThemes(this.page, this.sort, this.useTestData);
this.themes = data.themes;
this.totalPages = data.totalPages;
},
themes: [],
filter: "all",
sort: "likes",
page: 1,
totalPages: -1,
mode: "light",
useTestData: false,
buttonClass(attr, filter) {
if (this[attr] === filter) {
return "text-orange-600 bg-gradient-to-br from-orange-300 to-orange-100 px-2 md:px-3 py-1 rounded-full";
}
return "text-gray-800 hover:to-orange-300/100 hover:text-orange-600 dark:hover:bg-white";
},
async switchData() {
this.page = 1;
this.useTestData = !this.useTestData;
const data = await this.getThemes(this.page, this.sort, this.useTestData);
this.themes = data.themes;
this.totalPages = data.totalPages;
},
async switchTheme() {
this.mode = this.mode === "light" ? "dark": "light";
console.log(this.mode);
},
async sortThemes(sort) {
this.sort = sort;
this.page = 1;
const data = await this.getThemes(this.page, this.sort, this.useTestData);
this.themes = data.themes;
this.totalPages = data.totalPages;
},
async getThemes(page, sort, useTestData) {
let data;
if (useTestData) {
const res = await fetch(
`https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/test_data.json`
);
data = await res.json();
} else {
const res = await fetch(
'https://huggingface.co/api/spaces?limit=100&filter=gradio-theme&expand[]=subdomain&expand[]=lastModified&expand[]=likes&expand[]=runtime'
);
data = await res.json();
console.log(data)
// Transform the API response to match the expected format
data = data.filter(item => item.runtime?.stage === "RUNNING").map(item => ({
id: item.id,
subdomain: `https://${item.subdomain}.hf.space`,
likes: item.likes,
lastModified: item.lastModified
}));
}
if (sort === 'likes') {
data.sort((a, b) => (b.likes - a.likes));
} else {
data.sort((a, b) => (new Date(b.lastModified) - new Date(a.lastModified)));
}
const pageThemes = data.slice((page - 1) * 15, page * 15);
console.log(pageThemes);
return {
themes: pageThemes,
totalPages: Math.ceil(data.length / 15)
};
},
async nextPage() {
if (this.page < this.totalPages) {
this.page += 1;
const data = await this.getThemes(this.page, this.sort, this.useTestData);
this.themes = this.themes.concat(data.themes);
this.totalPages = data.totalPages;
}
},
}));
Alpine.start();
</script>
</head>
<body class="pb-10 pt-5 bg-white relative">
<section
x-data="themesData"
>
<section class="container px-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-14 mx-auto relative">
<div class="col-span-2 lg:col-span-1 flex flex-col gap-14 row-start">
<h1 class="text-lg font-semibold text-gray-800 whitespace-nowrap">Gradio Themes Gallery</h1>
</div>
<div class="col-span-2 md:col-span-3 flex items-center gap-14 flex flex-wrap lg-auto lg:ml-auto text-sm">
<div class="flex gap-2">
<span class="md:px-3 py-1 text-gray-800">sort by</span>
<button
:class="buttonClass('sort', 'likes')"
@click="sortThemes('likes')"
>
Most Likes
</button>
<button
:class="buttonClass('sort', 'recent')"
@click="sortThemes('recent')"
>
Recent
</button>
</div>
<div class="flex gap-0">
<!-- <input type="checkbox" @click="switchData()" class="rounded accent-orange-300">
<span class="md:px-3 py-1 text-gray-800 ml-0">Use Test Data</span> -->
<input type="checkbox" @click="switchTheme()" class="rounded accent-orange-300">
<span class="md:px-3 py-1 text-gray-800 ml-0">Show Dark Mode</span>
<!-- <button
:class="buttonClass('useTestData', false)"
class="px-2 md:px-3 py-1 rounded-full"
@click="switchData()"
>
Use Test Data
</button> -->
</div>
</div>
</section>
<div class="container px-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 mx-auto my-8 relative">
<template x-for="theme in themes" :key="theme.id">
<div class="grid-item">
<iframe :src="`${theme.subdomain}?_=${new Date().getTime()}&__theme=${mode}`" :alt="theme.id" scrolling="no" frameborder="0" loading="lazy"></iframe>
<a :href="`https://huggingface.co/spaces/${theme.id}`" target="_blank"></a>
</div>
</template>
</div>
<div class="h-12 relative" x-intersect="nextPage" data-iframe-height></div>
</section>
</body>
</html>