chadtmiller.com/knotless

Git hosted in your atproto account, on any stock PDS, fast enough for agents.

git clone knotless://chadtmiller.com/knotless

needs 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.
chadtmiller.com committed on Oct 22, 2026 parent c2f591c commit 1ac35ce
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}