Allows you to use Mastodon and Bluesky comments on your Lustre blog hexdocs.pm/chilp/
blog gleam lustre indieweb mastodon bluesky comments
1
fork

Configure Feed

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

Rename Mastodon types to make space for Bsky types in the namespace

+27 -27
+16 -16
src/chilp/api_typing.gleam
··· 4 4 import gleam/option.{type Option} 5 5 6 6 /// A status, like the ones you get from urls like: https://pony.social/api/v1/statuses/115911235653686237/ 7 - pub type Status { 8 - Status( 7 + pub type MastodonStatus { 8 + MastodonStatus( 9 9 id: String, 10 10 /// E.g. 2026-01-17T15:51:34.812Z 11 11 created_at: String, ··· 24 24 edited_at: Option(String), 25 25 content: String, 26 26 // application: StatusApplication, 27 - account: Account, 27 + account: MastodonAccount, 28 28 media_attachments: List(String), 29 - mentions: List(Mentions), 29 + mentions: List(MastodonMentions), 30 30 tags: List(StatusTag), 31 31 ) 32 32 } 33 33 34 - pub fn status_decoder() -> decode.Decoder(Status) { 34 + pub fn status_decoder() -> decode.Decoder(MastodonStatus) { 35 35 use id <- decode.field("id", decode.string) 36 36 use created_at <- decode.field("created_at", decode.string) 37 37 use in_reply_to_id <- field_or( ··· 60 60 ) 61 61 use mentions <- decode.field("mentions", decode.list(mentions_decoder())) 62 62 use tags <- field_or("tags", decode.list(status_tag_decoder()), []) 63 - decode.success(Status( 63 + decode.success(MastodonStatus( 64 64 id:, 65 65 created_at:, 66 66 in_reply_to_id:, ··· 94 94 // decode.success(StatusApplication(name:, website:)) 95 95 // } 96 96 97 - pub type Account { 97 + pub type MastodonAccount { 98 98 Account( 99 99 id: String, 100 100 username: String, ··· 125 125 ) 126 126 } 127 127 128 - pub fn account_decoder() -> decode.Decoder(Account) { 128 + pub fn account_decoder() -> decode.Decoder(MastodonAccount) { 129 129 use id <- decode.field("id", decode.string) 130 130 use username <- decode.field("username", decode.string) 131 131 use acct <- decode.field("acct", decode.string) ··· 194 194 next(val |> option.unwrap(default)) 195 195 } 196 196 197 - pub type Mentions { 198 - Mentions(id: String, username: String, url: String, acct: String) 197 + pub type MastodonMentions { 198 + MastodonMentions(id: String, username: String, url: String, acct: String) 199 199 } 200 200 201 - fn mentions_decoder() -> decode.Decoder(Mentions) { 201 + fn mentions_decoder() -> decode.Decoder(MastodonMentions) { 202 202 use id <- decode.field("id", decode.string) 203 203 use username <- decode.field("username", decode.string) 204 204 use url <- decode.field("url", decode.string) 205 205 use acct <- decode.field("acct", decode.string) 206 - decode.success(Mentions(id:, username:, url:, acct:)) 206 + decode.success(MastodonMentions(id:, username:, url:, acct:)) 207 207 } 208 208 209 - pub type StatusContext { 210 - StatusContext(ancestors: List(Status), descendants: List(Status)) 209 + pub type MastodonStatusContext { 210 + MastodonStatusContext(ancestors: List(MastodonStatus), descendants: List(MastodonStatus)) 211 211 } 212 212 213 - pub fn status_context_decoder() -> decode.Decoder(StatusContext) { 213 + pub fn status_context_decoder() -> decode.Decoder(MastodonStatusContext) { 214 214 let dec = status_decoder() 215 215 use ancestors <- decode.field("ancestors", decode.list(dec)) 216 216 use descendants <- decode.field("descendants", decode.list(dec)) 217 - decode.success(StatusContext(ancestors:, descendants:)) 217 + decode.success(MastodonStatusContext(ancestors:, descendants:)) 218 218 } 219 219 220 220 pub type StatusTag {
+11 -11
src/chilp/widget/base.gleam
··· 232 232 233 233 fn view_commentlist( 234 234 attributes: CommentWidget(msg), 235 - status: api_typing.Status, 236 - context: api_typing.StatusContext, 235 + status: api_typing.MastodonStatus, 236 + context: api_typing.MastodonStatusContext, 237 237 ) { 238 238 let sorted_descendants = 239 239 context.descendants ··· 251 251 }) 252 252 html.section( 253 253 attributes.comments_section, 254 - list.map(sorted_descendants, fn(comm: api_typing.Status) -> element.Element( 254 + list.map(sorted_descendants, fn(comm: api_typing.MastodonStatus) -> element.Element( 255 255 msg, 256 256 ) { 257 257 render_comment( ··· 270 270 attribs attribs: CommentWidget(msg), 271 271 comm_id comm_id: String, 272 272 recursion recursion: Int, 273 - parent parent: api_typing.Status, 274 - original_parent original_parent: api_typing.Status, 275 - sorted_descendants descendants: List(api_typing.Status), 273 + parent parent: api_typing.MastodonStatus, 274 + original_parent original_parent: api_typing.MastodonStatus, 275 + sorted_descendants descendants: List(api_typing.MastodonStatus), 276 276 ) { 277 277 let comm_result = list.find(descendants, fn(comm_) { comm_.id == comm_id }) 278 278 case comm_result, recursion <= attribs.recursion_limit { ··· 307 307 } 308 308 309 309 fn view_comment( 310 - comment: api_typing.Status, 310 + comment: api_typing.MastodonStatus, 311 311 is_authors: Bool, 312 312 attribs: CommentWidget(msg), 313 313 children: List(element.Element(msg)), ··· 464 464 465 465 pub opaque type ChilpModel { 466 466 ChilpModel( 467 - stati: dict.Dict(MastodonPost, api_typing.Status), 468 - context: dict.Dict(MastodonPost, #(api_typing.StatusContext, Float)), 467 + stati: dict.Dict(MastodonPost, api_typing.MastodonStatus), 468 + context: dict.Dict(MastodonPost, #(api_typing.MastodonStatusContext, Float)), 469 469 busy: dict.Dict(MastodonPost, option.Option(String)), 470 470 ) 471 471 } ··· 639 639 fn uncloth( 640 640 m: ChilpModel, 641 641 ) -> #( 642 - List(#(MastodonPost, api_typing.Status)), 643 - List(#(MastodonPost, #(api_typing.StatusContext, Float))), 642 + List(#(MastodonPost, api_typing.MastodonStatus)), 643 + List(#(MastodonPost, #(api_typing.MastodonStatusContext, Float))), 644 644 ) { 645 645 case m { 646 646 ChilpModel(stati:, context:, ..) -> {