annot.at is a service for syncing static websites, such as blogs, to atproto and standard.site annot.at
elixir atproto standardsite
3

Configure Feed

Select the types of activity you want to include in your feed.

Add support for HTML body

Using the org.wordpress.html type in the hopes that it's compatible with some existing apps.

Also fixes the missing tags from the actual publishing step

Johanna Larsson (Jul 2, 2026, 5:45 AM +0100) 79608706 f03a8fe4

+28 -2
+20
lib/annot_at/atproto/standard_site.ex
··· 13 13 @publication "site.standard.publication" 14 14 @document "site.standard.document" 15 15 @wellknown_path "/.well-known/site.standard.publication" 16 + @html_content "org.wordpress.html" 17 + @html_max_graphemes 100_000 16 18 17 19 @doc """ 18 20 Creates or updates the user's publication record. ··· 161 163 |> put_optional("updatedAt", iso8601(d.updated_at)) 162 164 |> put_optional("description", d.description) 163 165 |> put_optional("textContent", d.text_content) 166 + |> put_optional("content", to_content(d.content)) 164 167 |> put_optional("tags", d.tags) 165 168 |> put_optional("coverImage", cover_image) 166 169 end ··· 189 192 |> List.last() 190 193 191 194 %{rkey: rkey, url: value["url"], name: value["name"]} 195 + end 196 + 197 + defp to_content(nil), do: nil 198 + 199 + defp to_content(content) do 200 + %{ 201 + "$type" => @html_content, 202 + "html" => truncate_graphemes(content, @html_max_graphemes) 203 + } 204 + end 205 + 206 + defp truncate_graphemes(text, max) do 207 + if String.length(text) <= max do 208 + text 209 + else 210 + String.slice(text, 0, max) 211 + end 192 212 end 193 213 end
+2
lib/annot_at/atproto/standard_site/document.ex
··· 11 11 :updated_at, 12 12 :description, 13 13 :text_content, 14 + :content, 14 15 :tags, 15 16 :cover_image 16 17 ] ··· 24 25 updated_at: DateTime.t() | nil, 25 26 description: String.t() | nil, 26 27 text_content: String.t() | nil, 28 + content: String.t() | nil, 27 29 tags: [String.t()] | nil, 28 30 cover_image: {binary(), String.t()} | nil 29 31 }
+3 -1
lib/annot_at_web/controllers/live/posts_live.ex
··· 364 364 published_at: entry.published_at, 365 365 description: entry.summary, 366 366 text_content: text_content_of(entry.content), 367 - cover_image: fetch_cover(entry) 367 + content: entry.content, 368 + cover_image: fetch_cover(entry), 369 + tags: entry.categories 368 370 } 369 371 end 370 372
+3 -1
test/annot_at_web/live/posts_live_test.exs
··· 38 38 title: title, 39 39 published_at: ~U[2024-10-02 13:00:00Z], 40 40 summary: "a summary", 41 - content: "the body" 41 + content: "the body", 42 + categories: ["category"] 42 43 } 43 44 ] 44 45 } ··· 61 62 assert user_id == user.id 62 63 assert title == document.title 63 64 assert document.rkey =~ ~r/^[234567abcdefghij]/ 65 + assert ["category"] = document.tags 64 66 {:ok, %{"uri" => "at://x"}} 65 67 end) 66 68