My personal website & blog, powered by standard.site/leaflet and the AT Protocol.
Built with Astro (& React/Takumi-rs for the above OG-image) and deployed to Cloudflare Pages.
Designed by me.
Blog posts are fetched from the AT Protocol using the site.standard.document collection
(migrated from the original pub.leaflet.document lexicon). Documents are authored on
Leaflet and stored in the author's PDS.
-
src/lib/leaflet.ts— Type definitions and fetch logic. Callscom.atproto.repo.listRecordsagainst thesite.standard.documentcollection for the resolved DID. Each record wraps apub.leaflet.contentobject containing pages and blocks. -
src/lib/content-loader.ts— An Astro content collection loader that callsfetchLeafletPostsand stores each record in theblogcollection with its rkey as the ID. -
src/lib/leaflet-transform.ts— Converts the block-based Leaflet document model into HTML via markdown. Handles all block types (text,header,blockquote,code,image,unorderedList,orderedList,horizontalRule,website,bskyPost,button,iframe,math,poll,page) and rich text facets (bold,italic,underline,strikethrough,code,highlight,link,didMention,atMention,footnote). -
src/lib/leaflet-images.ts— Downloads and caches blob references (post images and website preview thumbnails) from the author's PDS intopublic/leaflet-images/during build.
site.standard.document
├── title, description, publishedAt, path, tags
├── site → at-uri to site.standard.publication
├── bskyPostRef → strongRef to cross-posted bsky feed post
└── content ($type: pub.leaflet.content)
└── pages[] ($type: pub.leaflet.pages.linearDocument)
└── blocks[] (pub.leaflet.blocks.*)
└── facets[] (pub.leaflet.richtext.facet#*)