-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial commit * First draft * add changeset * better close button * Improve card * Switch * Add code * Add code * Use icons folder + snake_case * lockfile fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
- Loading branch information
1 parent
4d1cbbc
commit 21ce721
Showing
6 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"website": minor | ||
--- | ||
|
||
feat:Custom component gallery |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<svg | ||
width="100%" | ||
height="100%" | ||
viewBox="0 0 5 5" | ||
version="1.1" | ||
xmlns="http://www.w3.org/2000/svg" | ||
xmlns:xlink="http://www.w3.org/1999/xlink" | ||
xml:space="preserve" | ||
style="fill:currentColor;fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" | ||
> | ||
<g> | ||
<path | ||
d="M3.789,0.09C3.903,-0.024 4.088,-0.024 4.202,0.09L4.817,0.705C4.931,0.819 4.931,1.004 4.817,1.118L1.118,4.817C1.004,4.931 0.819,4.931 0.705,4.817L0.09,4.202C-0.024,4.088 -0.024,3.903 0.09,3.789L3.789,0.09Z" | ||
/> | ||
<path | ||
d="M4.825,3.797C4.934,3.907 4.934,4.084 4.825,4.193L4.193,4.825C4.084,4.934 3.907,4.934 3.797,4.825L0.082,1.11C-0.027,1.001 -0.027,0.823 0.082,0.714L0.714,0.082C0.823,-0.027 1.001,-0.027 1.11,0.082L4.825,3.797Z" | ||
/> | ||
</g> | ||
</svg> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<script lang="ts"> | ||
import { svgCopy, svgCheck } from "$lib/assets/copy.js"; | ||
export let content: string = ""; | ||
let copied = false; | ||
async function copy() { | ||
await navigator.clipboard.writeText(content); | ||
copied = true; | ||
setTimeout(() => (copied = false), 2000); | ||
} | ||
</script> | ||
|
||
<button on:click={copy} role="button" tabindex={0}> | ||
{#if !copied} | ||
{@html svgCopy} | ||
{:else} | ||
{@html svgCheck} | ||
{/if} | ||
</button> |
160 changes: 160 additions & 0 deletions
160
js/_website/src/routes/custom_components/gallery/+page.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
<script lang="ts"> | ||
import { onMount, tick } from "svelte"; | ||
import type { ComponentData } from "./utils"; | ||
import { getRandomIntInclusive, classToEmojiMapping } from "./utils"; | ||
import Card from "./Card.svelte"; | ||
import Close from "$lib/icons/Close.svelte"; | ||
const API = "https://gradio-custom-component-gallery-backend.hf.space/"; | ||
const OFFSET = 0; | ||
const LIMIT = 50; | ||
let components: ComponentData[] = []; | ||
let selection: string = ""; | ||
let selected_component: ComponentData | null = null; | ||
const COLOR_SETS = [ | ||
["from-green-100", "to-green-50"], | ||
["from-yellow-100", "to-yellow-50"], | ||
["from-red-100", "to-red-50"], | ||
["from-blue-100", "to-blue-50"], | ||
["from-pink-100", "to-pink-50"], | ||
["from-purple-100", "to-purple-50"], | ||
["from-green-100", "to-green-50"], | ||
["from-yellow-100", "to-yellow-50"], | ||
["from-red-100", "to-red-50"], | ||
["from-blue-100", "to-blue-50"], | ||
["from-pink-100", "to-pink-50"], | ||
["from-purple-100", "to-purple-50"] | ||
]; | ||
function random_color(): string { | ||
const color = COLOR_SETS[getRandomIntInclusive(0, COLOR_SETS.length - 1)]; | ||
return `${color[0]} ${color[1]}`; | ||
} | ||
const handle_box_click = (component: ComponentData) => { | ||
selected_component = component; | ||
}; | ||
async function fetch_components(selection: string[] = []) { | ||
components = await fetch( | ||
`${API}components?offset=${OFFSET}&limit=${LIMIT}&name_or_tags=${selection.join( | ||
"," | ||
)}` | ||
) | ||
.then((response) => response.json()) | ||
.catch((error) => `Error: ${error}`); | ||
components.map((x) => (x.background_color = random_color())); | ||
} | ||
onMount(fetch_components); | ||
async function handle_keypress(e: KeyboardEvent): Promise<void> { | ||
await tick(); | ||
if (e.key === "Enter") { | ||
e.preventDefault(); | ||
fetch_components(selection.split(",")); | ||
} | ||
} | ||
</script> | ||
|
||
<div class="flex flex-col relative h-full"> | ||
<input | ||
type="text" | ||
class="m-8 border border-gray-200 p-1 rounded-md outline-none text-center text-lg mb-1 focus:placeholder-transparent focus:shadow-none focus:border-orange-500 focus:ring-0" | ||
placeholder="Search component names, keywords and descriptions. Separate multiple keywords with commas and press Enter." | ||
autocomplete="off" | ||
on:keypress={handle_keypress} | ||
bind:value={selection} | ||
/> | ||
<div class="grid relative"> | ||
{#each components as component (component.id)} | ||
<div | ||
on:click={() => handle_box_click(component)} | ||
class="box h-36 group font:thin relative rounded-xl shadow-sm hover:shadow-alternate transition-shadow bg-gradient-to-r {component.background_color}" | ||
> | ||
<div class="absolute opacity-30 text-6xl mb-1"> | ||
{classToEmojiMapping[component.template] || "❓"} | ||
</div> | ||
<h2 | ||
class="group-hover:underline font-md text-black font-bold max-w-full truncate text-center" | ||
> | ||
{component.name} | ||
</h2> | ||
<span | ||
class="font-sm text-gray-600 text-end max-w-full truncate" | ||
style="position:absolute; bottom:0;" | ||
> | ||
Tags: {component.tags.split(",").join(", ")}</span | ||
> | ||
</div> | ||
{/each} | ||
</div> | ||
</div> | ||
{#if selected_component} | ||
<div class="details-panel open"> | ||
<button | ||
class="absolute right-3 top-3 w-4" | ||
on:click={() => (selected_component = null)} | ||
> | ||
<Close /> | ||
</button> | ||
<div> | ||
<p class="text-4xl text-black text-center font-bold"> | ||
{selected_component.name} | ||
</p> | ||
</div> | ||
<Card data={selected_component}></Card> | ||
</div> | ||
{/if} | ||
|
||
<style> | ||
.grid { | ||
display: grid; | ||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | ||
gap: 16px; | ||
margin: 16px; | ||
} | ||
.close-button { | ||
position: absolute; | ||
top: 0; | ||
right: 5; | ||
width: var(--size-1); | ||
color: var(--body-text-color); | ||
} | ||
.box { | ||
border: 1px solid #ddd; | ||
padding: 16px; | ||
cursor: pointer; | ||
display: flex; | ||
position: relative; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
text-align: left; | ||
} | ||
.details-panel { | ||
overflow-y: scroll; | ||
position: fixed; | ||
top: 0; | ||
right: 0; | ||
height: 100%; | ||
width: 80%; | ||
background-color: white; | ||
box-shadow: -4px 0 4px rgba(0, 0, 0, 0.1); | ||
z-index: 1000; | ||
transition: transform 0.3s ease-out; | ||
transform: translateX(100%); | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
.details-panel.open { | ||
transform: translateX(0); | ||
} | ||
</style> |
145 changes: 145 additions & 0 deletions
145
js/_website/src/routes/custom_components/gallery/Card.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
<script lang="ts"> | ||
import type { ComponentData } from "./utils"; | ||
import CopyButton from "$lib/icons/CopyButton.svelte"; | ||
import { BaseCode } from "@gradio/code"; | ||
import { onMount } from "svelte"; | ||
export let data: ComponentData; | ||
let source_code_link = `https://huggingface.co/spaces/${data.id}`; | ||
let author_link = `https://huggingface.co/${data.author}`; | ||
let discussion_link = `https://huggingface.co/spaces/${data.id}/discussions/new`; | ||
let code_url = `https://huggingface.co/spaces/${data.id}/raw/main/app.py`; | ||
const tabs = ["Demo", "Code"]; | ||
let active_tab = 0; | ||
let code: string; | ||
onMount(async () => { | ||
code = await fetch(code_url).then((res) => res.text()); | ||
}); | ||
</script> | ||
|
||
<div class="card space-y-2 bg-gradient-to-r {data.background_color}"> | ||
<h1 class="text-xl font-black">{data.description}</h1> | ||
<div class="flex flex-row"> | ||
<div class="ml-2"> | ||
<code class="code text-md"> | ||
pip install {data.name.replace("_", "-")} | ||
<CopyButton content={`pip install ${data.name.replace("_", "-")}`} /> | ||
</code> | ||
</div> | ||
<div class="ml-2"> | ||
<strong>🖋️ Author</strong> | ||
<a | ||
href={author_link} | ||
target="_blank" | ||
class="link text-orange-400 font-bold">{data.author}</a | ||
> | ||
</div> | ||
<div class="ml-2"> | ||
<strong>📑 Template</strong> | ||
{data.template} | ||
</div> | ||
<div class="ml-2"> | ||
<strong>🔢 Version:</strong> | ||
{data.version} | ||
</div> | ||
<div class="ml-2"> | ||
<strong>🧬</strong> | ||
<a | ||
href={source_code_link} | ||
target="_blank" | ||
class="link text-orange-400 font-bold">code</a | ||
> | ||
</div> | ||
</div> | ||
<div class="flex flex-row"> | ||
<div class="ml-2"> | ||
<strong>🔖 Tags:</strong> | ||
{data.tags.split(",").join(", ")} | ||
</div> | ||
</div> | ||
<div class="flex flex-row"> | ||
<div class="ml-2"> | ||
<strong>🤝 Feedback? Stuck?</strong> | ||
<a | ||
href={discussion_link} | ||
target="_blank" | ||
class="link text-orange-400 font-bold" | ||
> | ||
Ask for help</a | ||
> | ||
</div> | ||
</div> | ||
<div class="flex flex-col relative h-full"> | ||
<div class="tabs flex flex-row relative"> | ||
{#each tabs as tab, index} | ||
<div | ||
class="tab bg-white {active_tab === index | ||
? 'active' | ||
: ''} {active_tab === index | ||
? '' | ||
: 'border-b-2'} px-8 py-1 rounded-t-md border-x-2 border-t-2 border-orange-300 content-center" | ||
on:click={() => { | ||
active_tab = index; | ||
}} | ||
> | ||
{tab} | ||
</div> | ||
{/each} | ||
</div> | ||
{#if active_tab === 0} | ||
<iframe | ||
src={`https://${data.subdomain}.hf.space?__theme=light`} | ||
height="100%" | ||
width="100%" | ||
></iframe> | ||
{:else} | ||
<div class="bg-white"> | ||
<BaseCode value={code} language="python" dark_mode={false} /> | ||
</div> | ||
{/if} | ||
</div> | ||
</div> | ||
|
||
<style> | ||
.card { | ||
border: 1px solid #ccc; | ||
border-radius: 8px; | ||
padding: 16px; | ||
margin: 16px; | ||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); | ||
display: flex; | ||
flex-direction: column; | ||
overflow-y: auto; | ||
height: 100%; | ||
} | ||
.card p { | ||
margin: 8px 0; | ||
color: rgb(206 100 0 / var(--tw-text-opacity)); | ||
} | ||
.link { | ||
text-decoration: underline; | ||
} | ||
.code { | ||
font-family: monospace; | ||
background-color: #f8f9fa; | ||
padding: 0.2em 0.4em; | ||
border-radius: 4px; | ||
} | ||
.tabs { | ||
display: flex; | ||
margin-bottom: -1px; | ||
} | ||
.tab { | ||
cursor: pointer; | ||
} | ||
.active { | ||
font-weight: bold; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
export type ComponentData = { | ||
id: string; | ||
name: string; | ||
template: string; | ||
author: string; | ||
description: string; | ||
tags: string; | ||
version: string; | ||
subdomain: string; | ||
background_color: string; | ||
}; | ||
|
||
export function getRandomIntInclusive(min: number, max: number): number { | ||
min = Math.ceil(min); | ||
max = Math.floor(max); | ||
return Math.floor(Math.random() * (max - min + 1) + min); // The maximum is inclusive and the minimum is inclusive | ||
} | ||
|
||
export const classToEmojiMapping: { [key: string]: string } = { | ||
AnnotatedImage: "🖼️", | ||
Audio: "🔊", | ||
Plot: "📈", | ||
Button: "🔘", | ||
Chatbot: "🤖", | ||
Code: "💻", | ||
ColorPicker: "🎨", | ||
Dataframe: "📊", | ||
Dataset: "📚", | ||
Fallback: "🔄", | ||
File: "📄", | ||
FileExplorer: "📂", | ||
Gallery: "🎨", | ||
HighlightedText: "✨", | ||
HTML: "🔗", | ||
Image: "🖼️", | ||
JSON: "📝", | ||
Label: "🏷️", | ||
Markdown: "📝", | ||
Model3D: "🗿", | ||
State: "🔢", | ||
UploadButton: "📤", | ||
Video: "🎥" | ||
}; |