chadtmiller.com/knotless
Git hosted in your atproto account, on any stock PDS, fast enough for agents.
git clone knotless://chadtmiller.com/knotlessneeds the knotless git helper. set it up
Show Markdown files rendered, with a plain view
A Markdown file's page now shows it made into HTML, as a README is, with Preview and Code links to switch; `?plain=1` shows its highlighted text, as GitHub does. Its links point from the file's own directory. The answer carries both, so switching needs nothing new from the server. READMEs and files share one test for Markdown, which takes .markdown, .mdown and .mkd as well as .md.
Showing 2 changed files with 19 additions and 2 deletions
web/src/lib/api/Blob.ts+8−2
| @@ -3,10 +3,16 @@ import type { RepoHead } from "./RepoHead"; | ||
| ||
/** | ||
* One file at a revision: an image, a binary, too large to show, or text | ||
* with the ranges its highlighting paints. | ||
* with the ranges its highlighting paints, and for Markdown, made into | ||
* HTML too. | ||
*/ | ||
export type Blob = { repo: RepoHead, rev: string, path: string, | ||
/** | ||
* `image`, `binary`, `large` or `text`. | ||
*/ | ||
shown: string, size: number, lines: number, text: string | null, ranges: string | null, }; | ||
shown: string, size: number, lines: number, text: string | null, ranges: string | null, | ||
/** | ||
* A Markdown file made into HTML, shown in place of its text unless the | ||
* page is asked for it plain. | ||
*/ | ||
html: string | null, }; | ||
web/src/routes/[authority]/[repo]/blob/[...rest]/+page.svelte+11−0
| @@ -1,4 +1,5 @@ | ||
<script lang="ts"> | ||
import { page } from '$app/state'; | ||
import { repoHref, size, urlPath } from '#lib/format.ts'; | ||
import Icon from '#lib/atoms/Icon.svelte'; | ||
import CodeView from '#lib/organisms/CodeView.svelte'; | ||
| @@ -9,12 +10,20 @@ | ||
const r = $derived(b.repo); | ||
const at = (view: string) => repoHref(r.authority, r.name, `/${view}/${urlPath(b.rev)}/${urlPath(b.path)}`); | ||
const shape = $derived(b.shown === 'image' || b.shown === 'binary' ? size(b.size) : `${b.lines} lines · ${size(b.size)}`); | ||
// Markdown is shown made into HTML, and as its text with `?plain=1`. | ||
const plain = $derived(page.url.searchParams.get('plain') === '1'); | ||
</script> | ||
| ||
<RepoPage repo={r} tab="code" title="{b.path} · {r.name}"> | ||
<Toolbar authority={r.authority} name={r.name} rev={b.rev} path={b.path} /> | ||
<div class="box"> | ||
<div class="boxhead"> | ||
{#if b.html !== null} | ||
<nav class="filter"> | ||
<a href={at('blob')} aria-current={plain ? undefined : 'page'}>Preview</a> | ||
<a href="{at('blob')}?plain=1" aria-current={plain ? 'page' : undefined}>Code</a> | ||
</nav> | ||
{/if} | ||
<span class="mute">{shape}</span> | ||
<span class="end"></span> | ||
<a class="btn" href={at('raw')} data-sveltekit-reload>Raw</a> | ||
| @@ -26,6 +35,8 @@ | ||
<div class="note">A binary file, not shown.</div> | ||
{:else if b.shown === 'large'} | ||
<div class="note">Too large to show here: view it raw.</div> | ||
{:else if b.html !== null && !plain} | ||
<div class="prose">{@html b.html}</div> | ||
{:else} | ||
<CodeView text={b.text ?? ''} lines={b.lines} ranges={b.ranges} /> | ||
{/if} | ||