|
<script lang="ts"> |
|
import "./prism.css"; |
|
|
|
import Prism from "prismjs"; |
|
import "prismjs/components/prism-python"; |
|
import "prismjs/components/prism-typescript"; |
|
|
|
interface Param { |
|
type: string | null; |
|
description: string; |
|
default: string | null; |
|
name?: string; |
|
} |
|
|
|
export let docs: Record<string, Param>; |
|
export let lang: "python" | "typescript" = "python"; |
|
export let linkify: string[] = []; |
|
export let header: string | null; |
|
|
|
let component_root: HTMLElement; |
|
let _docs: Param[]; |
|
let all_open = false; |
|
|
|
$: _docs = highlight_code(docs, lang); |
|
|
|
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; |
|
} |
|
}); |
|
} |
|
</script> |
|
|
|
<div class="wrap" bind:this={component_root}> |
|
{#if header !== null} |
|
<div class="header"> |
|
<span class="title">{header}</span> |
|
<button |
|
class="toggle-all" |
|
on:click={toggle_all} |
|
title={all_open ? "Close All" : "Open All"} |
|
> |
|
▼ |
|
</button> |
|
</div> |
|
{/if} |
|
{#if _docs} |
|
{#each _docs as { type, description, default: _default, name } (name)} |
|
<details class="param md"> |
|
<summary class="type"> |
|
<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>{description}</p></div> |
|
{/if} |
|
</details> |
|
{/each} |
|
{/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; |
|
border: 1px solid #eee; |
|
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); |
|
} |
|
|
|
.type { |
|
position: relative; |
|
padding: 0.7rem 1rem; |
|
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; |
|
} |
|
</style> |
|
|