adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
377 lines
7.5 KiB
Svelte
377 lines
7.5 KiB
Svelte
<script lang="ts">
|
|
import "./prism.css";
|
|
|
|
import Prism from "prismjs";
|
|
import "prismjs/components/prism-python";
|
|
import "prismjs/components/prism-typescript";
|
|
|
|
import { onMount, tick } from "svelte";
|
|
|
|
interface Param {
|
|
type: string | null;
|
|
description: string;
|
|
default: string | null;
|
|
name?: string;
|
|
}
|
|
|
|
let {
|
|
docs,
|
|
linkify = [],
|
|
header,
|
|
anchor_links,
|
|
max_height
|
|
}: {
|
|
docs: Record<string, Param>;
|
|
linkify: string[];
|
|
header: string | null;
|
|
anchor_links: string | boolean;
|
|
max_height: number | string | undefined;
|
|
} = $props();
|
|
|
|
let component_root: HTMLElement;
|
|
let all_open = $state(false);
|
|
let lang: "python" | "typescript" = "python";
|
|
|
|
let _docs = $derived(highlight_code(docs, lang));
|
|
|
|
function create_slug(name: string, anchor_links: string | boolean): string {
|
|
let prefix = "param-";
|
|
if (typeof anchor_links === "string") {
|
|
prefix += anchor_links + "-";
|
|
}
|
|
return prefix + name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
}
|
|
|
|
function highlight(code: string, lang: "python" | "typescript"): string {
|
|
let highlighted = Prism.highlight(code, Prism.languages[lang], lang);
|
|
|
|
for (const link of linkify) {
|
|
highlighted = highlighted.replace(
|
|
new RegExp(link, "g"),
|
|
`<a href="#h-${link.toLocaleLowerCase()}">${link}</a>`
|
|
);
|
|
}
|
|
|
|
return highlighted;
|
|
}
|
|
|
|
function highlight_code(
|
|
_docs: typeof docs,
|
|
lang: "python" | "typescript"
|
|
): Param[] {
|
|
if (!_docs) {
|
|
return [];
|
|
}
|
|
return Object.entries(_docs).map(
|
|
([name, { type, description, default: _default }]) => {
|
|
let highlighted_type = type ? highlight(type, lang) : null;
|
|
|
|
return {
|
|
name: name,
|
|
type: highlighted_type,
|
|
description: description,
|
|
default: _default ? highlight(_default, lang) : null
|
|
};
|
|
}
|
|
);
|
|
}
|
|
|
|
function toggle_all(): void {
|
|
all_open = !all_open;
|
|
const details = component_root.querySelectorAll(".param");
|
|
details.forEach((detail) => {
|
|
if (detail instanceof HTMLDetailsElement) {
|
|
detail.open = all_open;
|
|
}
|
|
});
|
|
}
|
|
|
|
function render_links(description: string): string {
|
|
const escaped = description
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
|
|
const markdown_links = escaped.replace(
|
|
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
'<a href="$2" target="_blank">$1</a>'
|
|
);
|
|
return markdown_links;
|
|
}
|
|
|
|
onMount(() => {
|
|
if (window.location.hash) {
|
|
open_parameter_from_hash(window.location.hash);
|
|
}
|
|
|
|
window.addEventListener("hashchange", (e) => {
|
|
open_parameter_from_hash(window.location.hash);
|
|
});
|
|
});
|
|
|
|
function open_parameter_from_hash(hash: string): void {
|
|
if (!component_root) return;
|
|
|
|
const id = hash.slice(1);
|
|
const detail = component_root.querySelector(`#${id}`);
|
|
|
|
if (detail instanceof HTMLDetailsElement) {
|
|
detail.open = true;
|
|
detail.scrollIntoView({ behavior: "smooth" });
|
|
}
|
|
}
|
|
|
|
const get_dimension = (
|
|
dimension_value: string | number | undefined
|
|
): string | undefined => {
|
|
if (dimension_value === undefined) {
|
|
return undefined;
|
|
}
|
|
if (typeof dimension_value === "number") {
|
|
return dimension_value + "px";
|
|
} else if (typeof dimension_value === "string") {
|
|
return dimension_value;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<div
|
|
class="wrap"
|
|
bind:this={component_root}
|
|
style:max-height={get_dimension(max_height)}
|
|
>
|
|
<div class="header">
|
|
{#if header !== null}
|
|
<span class="title">{header}</span>
|
|
{/if}
|
|
<button
|
|
class="toggle-all"
|
|
on:click={toggle_all}
|
|
title={all_open ? "Close All" : "Open All"}
|
|
>
|
|
{all_open ? "▲" : "▼"}
|
|
</button>
|
|
</div>
|
|
{#if _docs}
|
|
<div class="param-content">
|
|
{#each _docs as { type, description, default: _default, name } (name)}
|
|
<details
|
|
class="param md"
|
|
id={anchor_links ? create_slug(name || "", anchor_links) : undefined}
|
|
>
|
|
<summary class="type">
|
|
{#if anchor_links}
|
|
<a
|
|
href="#{create_slug(name || '', anchor_links)}"
|
|
class="param-link"
|
|
>
|
|
<span class="link-icon">🔗</span>
|
|
</a>
|
|
{/if}
|
|
<pre class="language-{lang}"><code
|
|
>{name}{#if type}: {@html type}{/if}</code
|
|
></pre>
|
|
</summary>
|
|
{#if _default}
|
|
<div class="default" class:last={!description}>
|
|
<span style:padding-right={"4px"}>default</span>
|
|
<code>= {@html _default}</code>
|
|
</div>
|
|
{/if}
|
|
{#if description}
|
|
<div class="description">
|
|
<p>{@html render_links(description)}</p>
|
|
</div>
|
|
{/if}
|
|
</details>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 0.7rem 1rem;
|
|
border-bottom: 1px solid var(--table-border-color);
|
|
}
|
|
|
|
.title {
|
|
font-size: var(--scale-0);
|
|
font-weight: 600;
|
|
color: var(--body-text-color);
|
|
}
|
|
|
|
.toggle-all {
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
color: var(--body-text-color);
|
|
font-size: 0.7em;
|
|
line-height: 1;
|
|
opacity: 0.7;
|
|
transition:
|
|
opacity 0.2s ease,
|
|
transform 0.3s ease;
|
|
}
|
|
|
|
.toggle-all:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
:global(.wrap[data-all-open="true"]) .toggle-all {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.default :global(pre),
|
|
.default :global(.highlight) {
|
|
display: inline-block;
|
|
}
|
|
|
|
.wrap :global(pre),
|
|
.wrap :global(.highlight) {
|
|
margin: 0 !important;
|
|
background: transparent !important;
|
|
font-family: var(--font-mono);
|
|
font-weight: 400;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
.wrap :global(pre a) {
|
|
color: var(--link-text-color-hover);
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.wrap :global(pre a:hover) {
|
|
color: var(--link-text-color-hover);
|
|
}
|
|
|
|
.default > span {
|
|
text-transform: uppercase;
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.default > code {
|
|
border: none;
|
|
}
|
|
code {
|
|
background: none;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.wrap {
|
|
padding: 0rem;
|
|
border-radius: 5px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
margin: 0;
|
|
box-shadow: var(--block-shadow);
|
|
border-width: var(--block-border-width);
|
|
border-color: var(--block-border-color);
|
|
border-radius: var(--block-radius);
|
|
width: 100%;
|
|
line-height: var(--line-sm);
|
|
color: var(--body-text-color);
|
|
display: grid;
|
|
grid-template-rows: auto 1fr;
|
|
}
|
|
|
|
.type {
|
|
position: relative;
|
|
padding: 0.7rem 1rem;
|
|
padding-left: 2rem;
|
|
background: var(--table-odd-background-fill);
|
|
border-bottom: 0px solid var(--table-border-color);
|
|
list-style: none;
|
|
}
|
|
|
|
.type::after {
|
|
content: "▼";
|
|
position: absolute;
|
|
top: 50%;
|
|
right: 15px;
|
|
transform: translateY(-50%);
|
|
transition: transform 0.3s ease;
|
|
font-size: 0.7em;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
details[open] .type::after {
|
|
transform: translateY(-50%) rotate(180deg);
|
|
}
|
|
|
|
.default {
|
|
padding: 0.2rem 1rem 0.3rem 1rem;
|
|
border-bottom: 1px solid var(--table-border-color);
|
|
background: var(--block-background-fill);
|
|
}
|
|
|
|
.default.last {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.description {
|
|
padding: 0.7rem 1rem;
|
|
font-size: var(--scale-00);
|
|
font-family: var(--font-sans);
|
|
background: var(--block-background-fill);
|
|
}
|
|
|
|
.param {
|
|
border-bottom: 1px solid var(--table-border-color);
|
|
}
|
|
|
|
.param:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
details[open] .type {
|
|
border-bottom-width: 1px;
|
|
}
|
|
|
|
.param.md code {
|
|
background: none;
|
|
}
|
|
|
|
details > summary {
|
|
cursor: pointer;
|
|
}
|
|
|
|
details > summary::-webkit-details-marker {
|
|
display: none;
|
|
}
|
|
|
|
.param-link {
|
|
opacity: 0;
|
|
position: absolute;
|
|
left: 8px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
transition: opacity 0.2s;
|
|
color: var(--body-text-color);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.link-icon {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.type:hover .param-link {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.param-link:hover {
|
|
opacity: 1 !important;
|
|
}
|
|
|
|
.param-content {
|
|
overflow-y: auto;
|
|
}
|
|
</style>
|