rapidoc
Version:
RapiDoc - Open API spec viewer with built in console
186 lines (176 loc) • 8.52 kB
JavaScript
import { html } from 'lit';
import { unsafeHTML } from 'lit/directives/unsafe-html.js'; // eslint-disable-line import/extensions
import { marked } from 'marked';
// Templates
import overviewTemplate from '~/templates/overview-template';
import headerTemplate from '~/templates/header-template';
import { schemaInObjectNotation, generateExample, standardizeExample } from '~/utils/schema-utils';
import '~/components/json-tree';
import '~/components/schema-tree';
import SetTheme from '~/utils/theme';
import { isValidHexColor } from '~/utils/color-utils';
/* eslint-disable indent */
// Json Schema Nav Template
function jsonSchemaNavTemplate() {
return html`
<nav class='nav-bar' part="section-navbar">
<slot name="nav-logo" class="logo"></slot>
<div style="display:flex;line-height:22px; padding:8px">
<input id="nav-bar-search"
part = "textbox textbox-nav-filter"
style = "width:100%; height: 26px; padding-right:20px; color:var(--nav-hover-text-color); border-color:var(--nav-accent-color); background-color:var(--nav-hover-bg-color)"
type = "text"
placeholder = "Filter"
@change = "${this.onSearchChange}"
spellcheck = "false"
>
<div style="margin: 6px 5px 0 -24px; font-size:var(--font-size-regular); cursor:pointer;">↩</div>
</div>
<nav style="flex:1" class='nav-scroll' part="section-navbar-scroll">
${this.resolvedSpec.schemaAndExamples.map((v) => html`
<div class='nav-bar-path' data-content-id='${v.elementId}' id='link-${v.elementId}'
@click = '${(e) => {
this.scrollToEventTarget(e, false);
}}'
>
${v.name}
</div>`)
}
</nav>
</nav>
`;
}
// Json Schema Body Template
function jsonSchemaBodyTemplate() {
return html`
${this.showInfo === 'true' ? overviewTemplate.call(this) : ''}
<div style="font-size:var(--font-size-regular);">
${this.resolvedSpec.schemaAndExamples.map((jSchemaBody) => {
const examplesObj = generateExample(jSchemaBody.schema, 'json', standardizeExample(jSchemaBody.examples), standardizeExample(jSchemaBody.example), true, false, 'json', true);
jSchemaBody.selectedExample = examplesObj[0]?.exampleId;
return html`
<section id='${jSchemaBody.elementId}' class='json-schema-and-example regular-font' style="display:flex; flex-direction: column; border:1px solid var(--border-color); margin-bottom:32px; border-top: 5px solid var(--border-color)">
<div style="padding:16px; border-bottom: 1px solid var(--border-color)">
<div style="font-size:var(--font-size-small); font-weight:bold">${jSchemaBody.name}</div>
<span class="json-schema-description m-markdown ">${unsafeHTML(marked(jSchemaBody.description || ''))}</span>
</div>
<div style="display:flex; flex-direction: row; gap:16px;">
<div class="json-schema-def" style="flex:1; padding:16px 0 16px 16px; ">
<schema-tree
.data = "${schemaInObjectNotation(jSchemaBody.schema, {})}"
schema-expand-level = "${this.schemaExpandLevel}"
schema-description-expanded = "${this.schemaDescriptionExpanded}"
allow-schema-description-expand-toggle = "${this.allowSchemaDescriptionExpandToggle}"
schema-hide-read-only = "false"
schema-hide-write-only = "false"
> </schema-tree>
</div>
<div class="json-schema-example-panel" style="width:400px; background-color: var(--input-bg); padding:16px 0 16px 16px; border-left: 1px dashed var(--border-color);">
${examplesObj.length > 1
? html`<select style="min-width:100px; max-width:100%" @change='${(e) => this.onSelectExample(e, jSchemaBody)}'>
${examplesObj.map((v) => html`
<option value="${v.exampleId}" ?selected=${(v.exampleId === jSchemaBody.selectedExample)}>
${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary}
</option>`)
}
</select>`
: html`<div style="font-size: var(--font-size-small);font-weight:700; margin:5px 0"> ${examplesObj[0].exampleSummary}</div>`
}
${examplesObj.map((v) => html`
<json-tree
.data = "${v.exampleValue}"
data-example = "${v.exampleId}"
class = "example"
style = "margin-top:16px; display: ${v.exampleId === jSchemaBody.selectedExample ? 'flex' : 'none'}"
></json-tree>`)
}
</div>
</div>
</section>`;
})
}
</div>
`;
}
/* eslint-enable indent */
// Json Schema Root Template
export default function jsonSchemaViewerTemplate(isMini = false) {
// export default function jsonSchemaViewerTemplate(isMini = false, pathsExpanded = false) {
if (!this.resolvedSpec) {
return '';
}
const newTheme = {
bg1: isValidHexColor(this.bgColor) ? this.bgColor : '',
fg1: isValidHexColor(this.textColor) ? this.textColor : '',
headerColor: isValidHexColor(this.headerColor) ? this.headerColor : '',
primaryColor: isValidHexColor(this.primaryColor) ? this.primaryColor : '',
navBgColor: isValidHexColor(this.navBgColor) ? this.navBgColor : '',
navTextColor: isValidHexColor(this.navTextColor) ? this.navTextColor : '',
navHoverBgColor: isValidHexColor(this.navHoverBgColor) ? this.navHoverBgColor : '',
navHoverTextColor: isValidHexColor(this.navHoverTextColor) ? this.navHoverTextColor : '',
navAccentColor: isValidHexColor(this.navAccentColor) ? this.navAccentColor : '',
navAccenttextColor: isValidHexColor(this.navAccentTextColor) ? this.navAccentTextColor : '',
};
/* eslint-disable indent */
if (this.resolvedSpec.specLoadError) {
if (isMini) {
return html`
${this.theme === 'dark' ? SetTheme.call(this, 'dark', newTheme) : SetTheme.call(this, 'light', newTheme)}
<div style="display:flex; align-items:center; border:1px dashed var(--border-color); height:42px; padding:5px; font-size:var(--font-size-small); color:var(--red); font-family:var(--font-mono)"> ${this.resolvedSpec.info.description} </div>
`;
}
return html`
${this.theme === 'dark' ? SetTheme.call(this, 'dark', newTheme) : SetTheme.call(this, 'light', newTheme)}
<!-- Header -->
${headerTemplate.call(this)}
<h1> Header </h1>
<main class="main-content regular-font" part="section-main-content">
<slot></slot>
<div style="margin:24px; text-align: center;">
<h1 style="color: var(--red)"> ${this.resolvedSpec.info.title} </h1>
<div style="font-family:var(--font-mono)"> ${this.resolvedSpec.info.description} </div>
</div>
</main>
`;
}
if (this.resolvedSpec.isSpecLoading) {
return html`
${this.theme === 'dark' ? SetTheme.call(this, 'dark', newTheme) : SetTheme.call(this, 'light', newTheme)}
<main class="main-content regular-font" part="section-main-content">
<slot></slot>
<div class="main-content-inner--${this.renderStyle}-mode">
<div class="loader"></div>
</div>
</main>
`;
}
return html`
${this.theme === 'dark' ? SetTheme.call(this, 'dark', newTheme) : SetTheme.call(this, 'light', newTheme)}
<!-- Header -->
${this.showHeader === 'false' ? '' : headerTemplate.call(this)}
<div id='the-main-body' class="body ${this.cssClasses}" dir= ${this.pageDirection}>
<!-- Side Nav -->
${jsonSchemaNavTemplate.call(this)}
<!-- Main Content -->
<main class="main-content regular-font" part="section-main-content">
<slot></slot>
<div class="main-content-inner--${this.renderStyle}-mode">
${this.loading === true
? html`<div class="loader"></div>`
: html`
${this.loadFailed === true
? html`<div style="text-align: center;margin: 16px;"> Unable to load the Spec</div>`
: html`
<div class="operations-root" @click="${(e) => { this.handleHref(e); }}">
${jsonSchemaBodyTemplate.call(this)}
</div>
`
}`
}
</div>
<slot name="footer"></slot>
</main>
</div>
`;
}
/* eslint-enable indent */