Spaces:
Runtime error
Runtime error
<script lang="ts"> | |
import { Block } from "@gradio/atoms"; | |
import type { SvelteComponent, ComponentType } from "svelte"; | |
import type { Gradio, SelectData } from "@gradio/utils"; | |
import { get_fetchable_url_or_file } from "@gradio/client"; | |
export let components: string[]; | |
export let component_props: Record<string, any>[]; | |
export let component_map: Map< | |
string, | |
Promise<{ | |
name: string; | |
component: { default: ComponentType<SvelteComponent> }; | |
}> | |
>; | |
export let label = "Examples"; | |
export let headers: string[]; | |
export let samples: any[][]; | |
export let elem_id = ""; | |
export let elem_classes: string[] = []; | |
export let visible = true; | |
export let value: number | null = null; | |
export let root: string; | |
export let proxy_url: null | string; | |
export let samples_per_page = 10; | |
export let scale: number | null = null; | |
export let min_width: number | undefined = undefined; | |
export let gradio: Gradio<{ | |
click: number; | |
select: SelectData; | |
}>; | |
let samples_dir: string = get_fetchable_url_or_file(null, root, proxy_url); | |
let page = 0; | |
$: gallery = components.length < 2; | |
let paginate = samples.length > samples_per_page; | |
let selected_samples: any[][]; | |
let page_count: number; | |
let visible_pages: number[] = []; | |
let current_hover = -1; | |
function handle_mouseenter(i: number): void { | |
current_hover = i; | |
} | |
function handle_mouseleave(): void { | |
current_hover = -1; | |
} | |
$: { | |
if (paginate) { | |
visible_pages = []; | |
selected_samples = samples.slice( | |
page * samples_per_page, | |
(page + 1) * samples_per_page | |
); | |
page_count = Math.ceil(samples.length / samples_per_page); | |
[0, page, page_count - 1].forEach((anchor) => { | |
for (let i = anchor - 2; i <= anchor + 2; i++) { | |
if (i >= 0 && i < page_count && !visible_pages.includes(i)) { | |
if ( | |
visible_pages.length > 0 && | |
i - visible_pages[visible_pages.length - 1] > 1 | |
) { | |
visible_pages.push(-1); | |
} | |
visible_pages.push(i); | |
} | |
} | |
}); | |
} else { | |
selected_samples = samples.slice(); | |
} | |
} | |
let component_meta: { | |
value: any; | |
component: ComponentType<SvelteComponent>; | |
}[][] = []; | |
async function get_component_meta(selected_samples: any[][]): Promise<void> { | |
component_meta = await Promise.all( | |
selected_samples.map( | |
async (sample_row) => | |
await Promise.all( | |
sample_row.map(async (sample_cell, j) => { | |
return { | |
value: sample_cell, | |
component: (await component_map.get(components[j]))?.component | |
?.default as ComponentType<SvelteComponent> | |
}; | |
}) | |
) | |
) | |
); | |
} | |
$: get_component_meta(selected_samples); | |
</script> | |
<Block | |
{visible} | |
padding={false} | |
{elem_id} | |
{elem_classes} | |
{scale} | |
{min_width} | |
allow_overflow={false} | |
container={false} | |
> | |
<div class="label"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
xmlns:xlink="http://www.w3.org/1999/xlink" | |
aria-hidden="true" | |
role="img" | |
width="1em" | |
height="1em" | |
preserveAspectRatio="xMidYMid meet" | |
viewBox="0 0 32 32" | |
> | |
<path | |
fill="currentColor" | |
d="M10 6h18v2H10zm0 18h18v2H10zm0-9h18v2H10zm-6 0h2v2H4zm0-9h2v2H4zm0 18h2v2H4z" | |
/> | |
</svg> | |
{label} | |
</div> | |
{#if gallery} | |
<div class="gallery"> | |
{#each selected_samples as sample_row, i} | |
<button | |
class="gallery-item" | |
on:click={() => { | |
value = i + page * samples_per_page; | |
gradio.dispatch("click", value); | |
gradio.dispatch("select", { index: value, value: sample_row }); | |
}} | |
on:mouseenter={() => handle_mouseenter(i)} | |
on:mouseleave={() => handle_mouseleave()} | |
> | |
{#if component_meta.length && component_map.get(components[0])} | |
<svelte:component | |
this={component_meta[0][0].component} | |
{...component_props[0]} | |
value={sample_row[0]} | |
{samples_dir} | |
type="gallery" | |
selected={current_hover === i} | |
index={i} | |
/> | |
{/if} | |
</button> | |
{/each} | |
</div> | |
{:else} | |
<div class="table-wrap"> | |
<table tabindex="0" role="grid"> | |
<thead> | |
<tr class="tr-head"> | |
{#each headers as header} | |
<th> | |
{header} | |
</th> | |
{/each} | |
</tr> | |
</thead> | |
<tbody> | |
{#each component_meta as sample_row, i} | |
<tr | |
class="tr-body" | |
on:click={() => { | |
value = i + page * samples_per_page; | |
gradio.dispatch("click", value); | |
}} | |
on:mouseenter={() => handle_mouseenter(i)} | |
on:mouseleave={() => handle_mouseleave()} | |
> | |
{#each sample_row as { value, component }, j} | |
{@const component_name = components[j]} | |
{#if component_name !== undefined && component_map.get(component_name) !== undefined} | |
<td | |
style="max-width: {component_name === 'textbox' | |
? '35ch' | |
: 'auto'}" | |
class={component_name} | |
> | |
<svelte:component | |
this={component} | |
{...component_props[j]} | |
{value} | |
{samples_dir} | |
type="table" | |
selected={current_hover === i} | |
index={i} | |
/> | |
</td> | |
{/if} | |
{/each} | |
</tr> | |
{/each} | |
</tbody> | |
</table> | |
</div> | |
{/if} | |
{#if paginate} | |
<div class="paginate"> | |
Pages: | |
{#each visible_pages as visible_page} | |
{#if visible_page === -1} | |
<div>...</div> | |
{:else} | |
<button | |
class:current-page={page === visible_page} | |
on:click={() => (page = visible_page)} | |
> | |
{visible_page + 1} | |
</button> | |
{/if} | |
{/each} | |
</div> | |
{/if} | |
</Block> | |
<style> | |
.wrap { | |
display: inline-block; | |
width: var(--size-full); | |
max-width: var(--size-full); | |
color: var(--body-text-color); | |
} | |
.hide { | |
display: none; | |
} | |
.label { | |
display: flex; | |
align-items: center; | |
margin-bottom: var(--size-2); | |
color: var(--block-label-text-color); | |
font-weight: var(--block-label-text-weight); | |
font-size: var(--block-label-text-size); | |
line-height: var(--line-sm); | |
} | |
svg { | |
margin-right: var(--size-1); | |
} | |
.gallery { | |
display: flex; | |
flex-wrap: wrap; | |
gap: var(--spacing-lg); | |
} | |
.gallery-item { | |
border: 1px solid var(--border-color-primary); | |
border-radius: var(--button-large-radius); | |
overflow: hidden; | |
} | |
.gallery-item:hover { | |
border-color: var(--border-color-accent); | |
background: var(--table-row-focus); | |
} | |
.table-wrap { | |
border: 1px solid var(--border-color-primary); | |
border-radius: var(--table-radius); | |
width: var(--size-full); | |
table-layout: auto; | |
overflow-x: auto; | |
line-height: var(--line-sm); | |
} | |
table { | |
width: var(--size-full); | |
} | |
.tr-head { | |
box-shadow: var(--shadow-drop-lg); | |
border-bottom: 1px solid var(--border-color-primary); | |
} | |
.tr-head > * + * { | |
border-right-width: 0px; | |
border-left-width: 1px; | |
border-color: var(--border-color-primary); | |
} | |
th { | |
padding: var(--size-2); | |
white-space: nowrap; | |
} | |
.tr-body { | |
cursor: pointer; | |
border-bottom: 1px solid var(--border-color-primary); | |
background: var(--table-even-background-fill); | |
} | |
.tr-body:last-child { | |
border: none; | |
} | |
.tr-body:nth-child(odd) { | |
background: var(--table-odd-background-fill); | |
} | |
.tr-body:hover { | |
background: var(--table-row-focus); | |
} | |
.tr-body > * + * { | |
border-right-width: 0px; | |
border-left-width: 1px; | |
border-color: var(--border-color-primary); | |
} | |
.tr-body:hover > * + * { | |
border-color: var(--border-color-accent); | |
} | |
td { | |
padding: var(--size-2); | |
text-align: center; | |
} | |
.paginate { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
gap: var(--spacing-sm); | |
margin-top: var(--size-2); | |
color: var(--block-label-text-color); | |
font-size: var(--text-sm); | |
} | |
button.current-page { | |
font-weight: var(--weight-bold); | |
} | |
</style> | |