This is the code that runs https://bandolier.learnjsthehardway.com/ for you to review. It uses the https://git.learnjsthehardway.com/learn-javascript-the-hard-way/bandolier-template to create the documentation for the project.
https://bandolier.learnjsthehardway.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
312 lines
7.7 KiB
312 lines
7.7 KiB
<script>
|
|
import { link } from 'svelte-spa-router';
|
|
import { onMount } from 'svelte';
|
|
import Layout from '$/client/Layout.svelte';
|
|
import Icon from '$/client/components/Icon.svelte';
|
|
import Code from "$/client/components/Code.svelte";
|
|
import HTML from "$/client/components/HTML.svelte";
|
|
import api from "$/client/api.js";
|
|
|
|
let index = {};
|
|
let docs_data;
|
|
let url = "/docs/";
|
|
export let params;
|
|
|
|
const caps_to_icon = {
|
|
"BUG": "bug",
|
|
"TODO": "clipboard-check",
|
|
"WARNING": "alert-triangle",
|
|
"FOOTGUN": "bomb",
|
|
"DEPRECATED": "axe"
|
|
}
|
|
|
|
const jump = (id) => {
|
|
let node = document.getElementById(id);
|
|
if(node) node.scrollIntoView();
|
|
}
|
|
|
|
const jump_top = () => jump("top-scroll");
|
|
|
|
const load_docs = async (to_load) => {
|
|
// only load if the URL changed
|
|
if(to_load !== url) {
|
|
const [status, data] = await api.get(`/docs/api/${to_load}.json`);
|
|
|
|
docs_data = status === 200 ? data : {};
|
|
url = to_load;
|
|
jump_top();
|
|
}
|
|
}
|
|
|
|
const load_index = async () => {
|
|
const [status, data] = await api.get("/docs/api/index.json");
|
|
index = status === 200 ? data : {};
|
|
}
|
|
|
|
const type_to_syntax = {
|
|
"callexpression": "()",
|
|
"objectexpression": "{}",
|
|
"function": "()",
|
|
"class": "{}",
|
|
"method": "()"
|
|
}
|
|
|
|
onMount(load_index);
|
|
|
|
$: if(params.wild) {
|
|
// load_docs will ignore any calls where params.wild doesn't change url
|
|
load_docs(params.wild)
|
|
} else {
|
|
url = "/docs/";
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
sidebar {
|
|
max-width: 300px;
|
|
min-height: 100vh;
|
|
height: 100vh;
|
|
max-height: 100vh;
|
|
margin: unset;
|
|
}
|
|
|
|
sidebar items {
|
|
overflow-y: auto;
|
|
}
|
|
|
|
right {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100vh;
|
|
height: 100vh;
|
|
max-height: 100vh;
|
|
overflow-y: auto;
|
|
width: 100%;
|
|
}
|
|
|
|
right > div {
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
export {
|
|
border-top: 1px solid var(--value5);
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
export.member {
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
export.class-def {
|
|
background-color: var(--value7);
|
|
}
|
|
|
|
export > heading {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
export > heading h4,
|
|
export > heading h2,
|
|
export > heading h1
|
|
{
|
|
margin-top: 0.5rem;
|
|
font-family: var(--font-family);
|
|
font-weight: 600;
|
|
}
|
|
|
|
export > heading meta-data {
|
|
display: grid;
|
|
gap: 0.5rem;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
grid-template-rows: auto;
|
|
}
|
|
|
|
export > info {
|
|
display: block;
|
|
padding-top: 0.5rem;
|
|
}
|
|
|
|
export > info commment {
|
|
display: block;
|
|
}
|
|
|
|
/* FOOTGUN: https://github.com/sveltejs/svelte/issues/2967
|
|
When you @html in Svelte it can't apply any styles from here.
|
|
You have to scope the a tag style inside module-header, BUT,
|
|
set it to global so Svelte will apply it to the whole doc,
|
|
not its special class.
|
|
*/
|
|
module-header :global(a) {
|
|
color: var(--color-text-inverted);
|
|
}
|
|
|
|
module-header {
|
|
display: block;
|
|
padding: 0.5rem;
|
|
background-color: var(--color-bg-inverted);
|
|
color: var(--color-text-inverted);
|
|
}
|
|
|
|
module-header :global(h2),
|
|
module-header :global(h3),
|
|
module-header :global(h4) {
|
|
margin-top: 3rem;
|
|
}
|
|
|
|
|
|
toc {
|
|
display: grid;
|
|
grid-template-columns: repeat(5, 1fr);
|
|
background-color: var(--value3);
|
|
color: var(--value9);
|
|
}
|
|
|
|
toc span {
|
|
border: 1px solid black;
|
|
padding: 0.5rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.no-doc {
|
|
background-color: var(--color-error);
|
|
}
|
|
|
|
@media only screen and (max-width: 600px) {
|
|
content {
|
|
flex-direction: column;
|
|
}
|
|
|
|
content > right,
|
|
content > left {
|
|
max-width: 100%;
|
|
min-width: 100%;
|
|
width: 100%;
|
|
overflow-y: initial;
|
|
padding-left: 0px;
|
|
padding-right: 0px;
|
|
}
|
|
|
|
toc {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
padding: 0px;
|
|
font-size: 0.8em;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
|
|
<Layout footer={ false} header={ false } centered={ true } fullwidth={ true }>
|
|
<content>
|
|
<sidebar class:mobile-hide={ url !== "/docs/" }>
|
|
<top><h4><a href="/" use:link><Icon name="arrow-left-circle" /> API Docs</a> </h4></top>
|
|
<items>
|
|
<a class:active={ url === "/docs/" } href="/docs/" use:link>Introduction</a>
|
|
{#each Object.keys(index) as item}
|
|
<a class:active={ item === url } href="/docs/{item}" use:link>{item}</a>
|
|
{/each}
|
|
</items>
|
|
</sidebar>
|
|
|
|
<right>
|
|
<span id="top-scroll"></span>
|
|
<div class:mobile-hide={ url === "/docs/" } class:mobile={ url !== "/docs/" } >
|
|
<a href="/docs/" use:link><Icon name="arrow-left-circle" /> { url }</a>
|
|
</div>
|
|
{#if url === "/docs/"}
|
|
<div>
|
|
<HTML url="/docs/api/index.html" />
|
|
</div>
|
|
{:else if docs_data}
|
|
<toc>
|
|
{#each docs_data.exports as exp}
|
|
<span class:no-doc={ !exp.comment } on:click={ () => jump(exp.slug) }>{ exp.name }
|
|
{#each exp.caps as cap_word}<Icon name={ caps_to_icon[cap_word] } size="24" light={ true }/>{/each}
|
|
</span>
|
|
|
|
{#if exp.isa == "class"}
|
|
{#each exp.methods as member}
|
|
<span class:no-doc={ !member.comment } on:click={ () => jump(member.slug) }>.{ member.name }
|
|
{#each member.caps as cap_word}<Icon name={ caps_to_icon[cap_word] } size="24" light={ true } />{/each}
|
|
</span>
|
|
{/each}
|
|
{/if}
|
|
|
|
{/each}
|
|
</toc>
|
|
<module-header>
|
|
<h1>{ url }</h1>
|
|
{#if docs_data.comment}
|
|
{@html docs_data.comment}
|
|
{/if}
|
|
</module-header>
|
|
|
|
{#each docs_data.exports as exp}
|
|
{#if exp.isa === "class"}
|
|
<export class="class-def">
|
|
<heading>
|
|
<h2 on:click={ () => jump_top() } id={ exp.slug }>class { exp.name }</h2>
|
|
<Code content={ exp.code } language="javascript" />
|
|
</heading>
|
|
<comment>
|
|
{#if exp.comment}
|
|
{@html exp.comment}
|
|
{/if}
|
|
</comment>
|
|
</export>
|
|
|
|
{#each exp.methods as member}
|
|
<export class="member">
|
|
<heading>
|
|
<h4 id={ member.slug } on:click={ () => jump(exp.slug) }>.{member.name}{ type_to_syntax[member.isa] || "" }
|
|
</h4>
|
|
<meta-data>
|
|
{docs_data.source}:{ member.line_start }
|
|
<em>{ member.isa } of { exp.name }</em>
|
|
{#if member.static}<b>static</b>{/if}
|
|
{#if member.async}<b>async</b>{/if}
|
|
{#if member.generator}<b>generator</b>{/if}
|
|
</meta-data>
|
|
</heading>
|
|
<info>
|
|
{#if member.comment}
|
|
<comment>
|
|
{ @html member.comment }
|
|
</comment>
|
|
{/if}
|
|
<Code content={ member.code } language="javascript" />
|
|
</info>
|
|
</export>
|
|
{/each}
|
|
{:else}
|
|
<export>
|
|
<heading>
|
|
<h4 on:click={ () => jump_top() }
|
|
id={ exp.slug }>{exp.name}{ type_to_syntax[exp.isa] || "" }
|
|
</h4>
|
|
<meta-data>
|
|
{docs_data.source}:{ exp.line_start }
|
|
<em>{ exp.isa }</em>
|
|
{#if exp.static}<b>static</b>{/if}
|
|
{#if exp.async}<b>async</b>{/if}
|
|
{#if exp.generator}<b>generator</b>{/if}
|
|
</meta-data>
|
|
</heading>
|
|
<info>
|
|
{#if exp.comment}
|
|
<comment>
|
|
{@html exp.comment}
|
|
</comment>
|
|
{/if}
|
|
<Code content={ exp.code } language="javascript" />
|
|
</info>
|
|
</export>
|
|
{/if}
|
|
{/each}
|
|
{/if}
|
|
</right>
|
|
</content>
|
|
</Layout>
|
|
|