<!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) { const filename = useTestData ? "test_data.json" : "subdomains.json" const res = await fetch( `https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/${filename}` ); const data = await res.json(); 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.floor(data.length + 15 - 1, 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>