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 pdsls links on rkeys

Also puts your did on the bottom right. Just trying to make it clearer that this is your data, without me having to recreate a whole atproto viewer.

Johanna Larsson (Jul 3, 2026, 2:50 PM +0100) 8d479536 536c1361

+63 -17
+17
lib/annot_at/atproto.ex
··· 1 + defmodule AnnotAt.Atproto do 2 + @moduledoc """ 3 + atproto is the protocol that underpins all of the functionality 4 + in this service. 5 + 6 + https://atproto.com/ 7 + """ 8 + 9 + @inspect_site "https://pdsls.dev/" 10 + 11 + @doc """ 12 + Let users inspect their records. 13 + """ 14 + def inspect_url(aturi) do 15 + @inspect_site <> aturi 16 + end 17 + end
+7
lib/annot_at/atproto/standard_site.ex
··· 126 126 } 127 127 end 128 128 129 + @doc """ 130 + Construct an at-uri for a document, useful when referencing documents. 131 + """ 132 + def document_uri(did, rkey) do 133 + "at://#{did}/site.standard.document/#{rkey}" 134 + end 135 + 129 136 defp fetch_user(user_id) do 130 137 case Accounts.get_user(user_id) do 131 138 nil -> {:error, :no_session}
+8 -4
lib/annot_at_web/components/layouts.ex
··· 80 80 81 81 <aside 82 82 id="sidebar" 83 - class="fixed inset-y-0 left-0 z-50 flex w-60 -translate-x-full flex-col 84 - border-r-2 border-ink bg-paper p-4 transition-transform duration-200 lg:static 85 - lg:z-auto lg:translate-x-0" 83 + class="fixed inset-y-0 left-0 z-50 flex w-60 -translate-x-full flex-col border-r-2 border-ink bg-paper p-4 transition-transform duration-200 lg:sticky lg:top-0 lg:h-screen lg:self-start lg:overflow-y-auto lg:z-auto lg:translate-x-0" 86 84 > 87 85 <div class="flex items-center justify-between"> 88 86 <.link ··· 149 147 </div> 150 148 </div> 151 149 <.link 150 + class="block px-3 my-1.5 text-[10px] text-ink/30 font-mono" 151 + href={AnnotAt.Atproto.inspect_url(@current_scope.user.did)} 152 + > 153 + {@current_scope.user.did} 154 + </.link> 155 + <.link 152 156 href={~p"/logout"} 153 157 method="delete" 154 - class="block px-3 py-1.5 text-[11px] font-bold uppercase 158 + class="block px-3 py-1.5 text-[11px] font-bold 155 159 tracking-widest text-ink/45 hover:text-ink" 156 160 > 157 161 Sign out
+7 -1
lib/annot_at_web/controllers/live/login_live.ex
··· 24 24 Enter your atproto handle to Publish to the ATmosphere. 25 25 </p> 26 26 27 - <.form for={@form} phx-change="suggest" phx-submit="login" class="mt-6 space-y-4"> 27 + <.form 28 + for={@form} 29 + id="login-form" 30 + phx-change="suggest" 31 + phx-submit="login" 32 + class="mt-6 space-y-4" 33 + > 28 34 <div 29 35 id="handle-combobox" 30 36 class="relative"
+24 -12
lib/annot_at_web/controllers/live/site_live.ex
··· 58 58 class="size-5 transition-transform group-hover:translate-x-1" 59 59 /> 60 60 </.link> 61 - <.site_cards site={@site} record={@record} feed={@feed} /> 61 + <.site_cards site={@site} record={@record} feed={@feed} did={@current_scope.user.did} /> 62 62 <% :feed -> %> 63 63 <.feed_step feeds={@feeds} /> 64 64 <% :publication -> %> ··· 86 86 site…</p> 87 87 </:loading> 88 88 <:failed :let={_}> 89 - <p class="mt-4 text-sm font-bold text-red-600">Couldn't read your 90 - site.</p> 89 + <p class="mt-4 text-sm font-bold text-red-600">Couldn't read your site.</p> 91 90 </:failed> 92 91 93 92 <div class="mt-4 rounded-xl border-2 border-ink bg-sky-light p-4"> ··· 557 556 end 558 557 559 558 attr :label, :string, required: true 560 - attr :value, :string, default: nil 559 + attr :value, :string, required: true 560 + attr :href, :string, default: nil 561 561 562 562 defp record_field(assigns) do 563 563 ~H""" 564 564 <div> 565 - <dt class="text-xs font-bold uppercase tracking-wide 566 - text-ink/45">{@label}</dt> 567 - <dd :if={@value} class="break-all font-medium">{@value}</dd> 568 - <dd :if={is_nil(@value)} class="text-sm italic text-ink/40">Not set 569 - yet</dd> 565 + <dt class="text-xs font-bold uppercase tracking-wide text-ink/45">{@label}</dt> 566 + <dd :if={@value} class="break-all font-medium"> 567 + <%= if @href do %> 568 + <.link class="underline" href={@href}>{@value}</.link> 569 + <% else %> 570 + {@value} 571 + <% end %> 572 + </dd> 573 + <dd :if={is_nil(@value)} class="text-sm italic text-ink/40">Not set yet</dd> 570 574 </div> 571 575 """ 572 576 end ··· 574 578 attr :site, :map, required: true 575 579 attr :record, :any, required: true 576 580 attr :feed, :any, required: true 581 + attr :did, :string, required: true 577 582 578 583 defp site_cards(assigns) do 579 584 ~H""" ··· 582 587 <:badge> 583 588 <span 584 589 :if={@feed.ok?} 585 - class="inline-flex items-center gap-1 rounded-full border-2 586 - border-ink bg-paper px-2.5 py-0.5 text-xs font-bold text-ink/60" 590 + class="inline-flex items-center gap-1 rounded-full border-2 border-ink bg-paper px-2.5 py-0.5 text-xs font-bold text-ink/60" 587 591 > 588 592 <.icon name="hero-clock" class="size-3.5" /> Checked just now 589 593 </span> ··· 654 658 </:failed> 655 659 656 660 <dl class="space-y-3"> 657 - <.record_field label="rkey" value={@site.rkey} /> 661 + <.record_field 662 + label="rkey" 663 + value={@site.rkey} 664 + href={ 665 + AnnotAt.Atproto.inspect_url( 666 + AnnotAt.Atproto.StandardSite.publication_uri(@did, @site.rkey) 667 + ) 668 + } 669 + /> 658 670 <.record_field label="Name" value={record["name"]} /> 659 671 <.record_field label="URL" value={record["url"]} /> 660 672 <.record_field label="Description" value={record["description"]} />