-module(chilp@widget). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/chilp/widget.gleam"). -export([element/2, bsky_thread_view_decoder/0, register/0]). -export_type([model/0, msg/0, bsky_thread_view/0, bsky_thread_reply/0, mastodon_status_context/0, mastodon_descendant/0, coalesced_view/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type model() :: {model, gleam@option:option(chilp@widget@anchors:mastodon()), list(mastodon_descendant()), binary(), gleam@option:option(chilp@widget@anchors:bluesky()), list(bsky_thread_reply()), binary(), gleam@option:option(binary()), list(coalesced_view()), integer()}. -type msg() :: mastodon_un_anchored | {mastodon_anchored, binary(), binary()} | bsky_un_anchored | {bsky_anchored, binary(), binary()} | {all_stopping_error, binary()} | {bsky_incoming_thread_view, bsky_thread_view()} | {incoming_coalesced_view, list(coalesced_view())} | {mastodon_incoming_status, mastodon_status_context()} | {mastodon_incoming_op_username, binary()} | {set_tab, integer()} | {mastodon_answer, binary()}. -type bsky_thread_view() :: {bsky_thread_view, binary(), list(bsky_thread_reply())}. -type bsky_thread_reply() :: {bsky_thread_reply, binary(), integer(), gleam@time@timestamp:timestamp(), binary(), binary(), binary(), binary(), binary(), list(bsky_thread_reply())}. -type mastodon_status_context() :: {mastodon_status_context, list(mastodon_descendant())}. -type mastodon_descendant() :: {mastodon_descendant, binary(), binary(), lustre@vdom@vnode:element(msg()), gleam@time@timestamp:timestamp(), integer(), list(mastodon_descendant()), binary(), binary(), binary(), binary()}. -type coalesced_view() :: {coalesced_view, gleam@time@timestamp:timestamp(), binary(), binary(), binary(), binary(), binary(), lustre@vdom@vnode:element(msg()), binary(), integer(), list(coalesced_view())}. -file("src/chilp/widget.gleam", 52). -spec element( gleam@option:option(chilp@widget@anchors:mastodon()), gleam@option:option(chilp@widget@anchors:bluesky()) ) -> lustre@vdom@vnode:element(any()). element(Mastodon_anchor, Bsky_anchor) -> lustre@element:element( <<"comment-widget"/utf8>>, [lustre@attribute:attribute( <<"mastodon-anchor"/utf8>>, case Mastodon_anchor of {some, Anchor} -> <<<<(erlang:element(2, Anchor))/binary, "\\"/utf8>>/binary, (erlang:element(3, Anchor))/binary>>; none -> <<""/utf8>> end ), lustre@attribute:attribute( <<"bluesky-anchor"/utf8>>, case Bsky_anchor of {some, Anchor@1} -> <<<<(erlang:element(2, Anchor@1))/binary, "\\"/utf8>>/binary, (erlang:element(3, Anchor@1))/binary>>; none -> <<""/utf8>> end )], [] ). -file("src/chilp/widget.gleam", 91). -spec init(any()) -> {model(), lustre@effect:effect(msg())}. init(_) -> {{model, none, [], <<"username"/utf8>>, none, [], <<""/utf8>>, none, [], begin _pipe = [1, 2], _pipe@1 = gleam@list:shuffle(_pipe), _pipe@2 = gleam@list:first(_pipe@1), gleam@result:unwrap(_pipe@2, 1) end}, lustre@effect:none()}. -file("src/chilp/widget.gleam", 524). -spec view_about_chilp() -> lustre@vdom@vnode:element(msg()). view_about_chilp() -> lustre@element@html:'div'( [lustre@attribute:class(<<"my-5 px-5 pb-5 "/utf8>>)], [lustre@element@html:p( [], [lustre@element:text( <<"This widget is powered by Chilp! 💬 By MLC Bloeiman"/utf8>> )] ), lustre@element@html:p( [], [lustre@element:text(<<"Want to read "/utf8>>), lustre@element@html:a( [lustre@attribute:href( <<"https://strawmelonjuice.com/post/chilpv2"/utf8>> ), lustre@attribute:class( <<"link link-primary-content"/utf8>> )], [lustre@element:text(<<"more about Chilp"/utf8>>)] ), lustre@element:text(<<" on "/utf8>>), lustre@element@html:img( [lustre@attribute:src( <<"https://strawmelonjuice.com/strawmelonjuice.svg"/utf8>> ), lustre@attribute:width(34), lustre@attribute:class( <<"inline bg-white/65 rounded-lg"/utf8>> )] ), lustre@element:text(<<" strawmelonjuice.com?"/utf8>>)] )] ). -file("src/chilp/widget.gleam", 551). -spec view_respond_on_bsky(binary()) -> lustre@vdom@vnode:element(msg()). view_respond_on_bsky(Bskylink) -> Icon_link = fun(Label, New_base, Color_class) -> lustre@element@html:a( [lustre@attribute:href( gleam@string:replace( Bskylink, <<"bsky.app"/utf8>>, New_base ) ), lustre@attribute:target(<<"_blank"/utf8>>), lustre@attribute:class( <<"btn btn-circle btn-sm btn-ghost tooltip "/utf8, Color_class/binary>> ), lustre@attribute:attribute(<<"data-tip"/utf8>>, Label)], [lustre@element:text(gleam@string:slice(Label, 0, 1))] ) end, lustre@element@html:'div'( [lustre@attribute:class(<<"my-5 px-5 pb-5 "/utf8>>)], [lustre@element:text( <<"Respond to this post on Bluesky to have it show up here!"/utf8>> ), lustre@element@html:'div'( [lustre@attribute:class(<<"flex gap-2 items-center"/utf8>>)], [lustre@element@html:span( [lustre@attribute:class( <<"text-xs mr-2 opacity-50"/utf8>> )], [lustre@element:text(<<"Open in:"/utf8>>)] ), Icon_link( <<"Bluesky"/utf8>>, <<"bsky.app"/utf8>>, <<"text-[#006aff] bg-white"/utf8>> ), Icon_link( <<"Blacksky"/utf8>>, <<"blacksky.community"/utf8>>, <<"text-white bg-black"/utf8>> ), Icon_link( <<"Witchsky"/utf8>>, <<"witchsky.app"/utf8>>, <<"text-[#ed5345] bg-white"/utf8>> )] )] ). -file("src/chilp/widget.gleam", 673). -spec error_view(binary()) -> lustre@vdom@vnode:element(any()). error_view(Error) -> lustre@element@html:'div'( [lustre@attribute:class(<<"alert alert-error"/utf8>>), lustre@attribute:role(<<"alert"/utf8>>)], [lustre@element@svg:svg( [lustre@attribute:attribute( <<"viewBox"/utf8>>, <<"0 0 24 24"/utf8>> ), lustre@attribute:attribute(<<"fill"/utf8>>, <<"none"/utf8>>), lustre@attribute:class( <<"h-6 w-6 shrink-0 stroke-current"/utf8>> ), lustre@attribute:attribute( <<"xmlns"/utf8>>, <<"http://www.w3.org/2000/svg"/utf8>> )], [lustre@element@svg:path( [lustre@attribute:attribute( <<"d"/utf8>>, <<"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/utf8>> ), lustre@attribute:attribute( <<"stroke-width"/utf8>>, <<"2"/utf8>> ), lustre@attribute:attribute( <<"stroke-linejoin"/utf8>>, <<"round"/utf8>> ), lustre@attribute:attribute( <<"stroke-linecap"/utf8>>, <<"round"/utf8>> )] )] ), lustre@element@html:span( [], [lustre@element@html:text( <<"AN ERROR OCCURED:"/utf8, Error/binary>> )] )] ). -file("src/chilp/widget.gleam", 746). -spec get_username_mastodon(model()) -> lustre@effect:effect(msg()). get_username_mastodon(Model) -> case erlang:element(2, Model) of {some, Anchor} -> Url = <<<<<<"https://"/utf8, (erlang:element(2, Anchor))/binary>>/binary, "/api/v1/statuses/"/utf8>>/binary, (erlang:element(3, Anchor))/binary>>, Handler = rsvp:expect_json( begin gleam@dynamic@decode:subfield( [<<"account"/utf8>>, <<"username"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(User) -> gleam@dynamic@decode:success(User) end ) end, fun(Response) -> case Response of {ok, Username} -> {mastodon_incoming_op_username, Username}; {error, Rsvperror} -> case Rsvperror of {unhandled_response, _} -> {all_stopping_error, <<"The response body we got back from Mastodon was misformed."/utf8>>}; {json_error, _} -> {all_stopping_error, <<"The response body we got back from Mastodon was misformed."/utf8>>}; bad_body -> {all_stopping_error, <<"The response body we got back from Mastodon was misformed."/utf8>>}; {bad_url, _} -> {all_stopping_error, <<"The API call to Mastodon failed. Did you enter the instance and post id correctly?"/utf8>>}; {http_error, _} -> {all_stopping_error, <<"Could not fetch comments from Mastodon."/utf8>>}; network_error -> {all_stopping_error, <<"Could not fetch comments from Mastodon."/utf8>>} end end end ), rsvp:get(Url, Handler); none -> lustre@effect:none() end. -file("src/chilp/widget.gleam", 827). -spec sort_comments(coalesced_view(), coalesced_view()) -> gleam@order:order(). sort_comments(C1, C2) -> case gleam@int:compare(erlang:element(10, C1), erlang:element(10, C2)) of eq -> gleam@time@timestamp:compare( erlang:element(2, C1), erlang:element(2, C2) ); Measure -> Measure end. -file("src/chilp/widget.gleam", 403). -spec view_rendered_comment(coalesced_view()) -> lustre@vdom@vnode:element(msg()). view_rendered_comment(Comment) -> lustre@element@html:article( [lustre@attribute:class(<<"comment mt-2"/utf8>>)], [lustre@element@html:header( [lustre@attribute:class(<<"flex"/utf8>>)], [lustre@element@html:img( [lustre@attribute:src(erlang:element(4, Comment)), lustre@attribute:class( <<"avatar w-[45px] h-[45px] mask mask-squircle flex-none"/utf8>> ), lustre@attribute:alt(<<"@"/utf8>>)] ), lustre@element@html:'div'( [lustre@attribute:class( <<"meta pl-4 max-h-[45px]"/utf8>> )], [lustre@element@html:span( [lustre@attribute:class(<<"display-name"/utf8>>)], [lustre@element@html:text( erlang:element(7, Comment) ), case erlang:element(6, Comment) of <<"Mastodon"/utf8>> -> lustre@element@html:'div'( [lustre@attribute:class( <<"badge badge-sm badge-info ms-2 bg-[#595aff] text-white"/utf8>> )], [lustre@element:text( <<"Mastodon"/utf8>> )] ); <<"Bluesky"/utf8>> -> lustre@element@html:'div'( [lustre@attribute:class( <<"badge badge-sm badge-info ms-2 bg-[#006aff] text-white"/utf8>> )], [lustre@element:text( <<"Bluesky"/utf8>> )] ); _ -> lustre@element:none() end] ), lustre@element@html:p( [lustre@attribute:class(<<"text-xs"/utf8>>)], [lustre@element@html:a( [lustre@attribute:href( erlang:element(3, Comment) ), lustre@attribute:class( <<"link link-secondary-content link-sm"/utf8>> )], [lustre@element:text( <<"@"/utf8, (erlang:element(5, Comment))/binary>> )] ), lustre@element:text(<<" • "/utf8>>), lustre@element@html:time( [lustre@attribute:attribute( <<"datetime"/utf8>>, begin _pipe = erlang:element( 2, Comment ), gleam@time@timestamp:to_rfc3339( _pipe, {duration, 0, 0} ) end )], [lustre@element:text( begin B = begin _pipe@3 = case begin _pipe@1 = gleam@time@timestamp:difference( erlang:element( 2, Comment ), gleam@time@timestamp:system_time( ) ), _pipe@2 = gleam@time@duration:approximate( _pipe@1 ), gleam@pair:map_second( _pipe@2, fun(D) -> case D of nanosecond -> <<"nanosecond"/utf8>>; microsecond -> <<"microsecond"/utf8>>; millisecond -> <<"millisecond"/utf8>>; second -> <<"second"/utf8>>; minute -> <<"minute"/utf8>>; hour -> <<"hour"/utf8>>; day -> <<"day"/utf8>>; week -> <<"week"/utf8>>; month -> <<"month"/utf8>>; year -> <<"year"/utf8>> end end ) end of {1, X} -> {1, X}; {X@1, D@1} -> {X@1, <>} end, gleam@pair:map_first( _pipe@3, fun erlang:integer_to_binary/1 ) end, <<<<<<(erlang:element(1, B))/binary, " "/utf8>>/binary, (erlang:element( 2, B ))/binary>>/binary, " ago."/utf8>> end )] )] )] )] ), lustre@element@html:section( [lustre@attribute:class(<<"content mt-5"/utf8>>)], [lustre@element@html:span([], [erlang:element(8, Comment)])] ), lustre@element@html:footer( [], [lustre@element@html:'div'( [lustre@attribute:class(<<"my-5"/utf8>>)], [lustre@element@html:a( [lustre@attribute:class( <<"btn btn-sm absolute right-8"/utf8>> ), lustre@attribute:href( erlang:element(9, Comment) ), lustre@attribute:target(<<"_blank"/utf8>>)], [lustre@element@html:text( <<"View comment on "/utf8, (erlang:element(6, Comment))/binary>> )] )] ), lustre@element@html:br( [lustre@attribute:class( <<"border-b-2 border-dotted"/utf8>> )] ), case erlang:element(11, Comment) of [] -> lustre@element:none(); _ -> lustre@element@html:section( [lustre@attribute:class( <<"pl-5 border-s-4 border-default bg-neutral-secondary-soft"/utf8>> )], begin _pipe@4 = gleam@list:sort( erlang:element(11, Comment), fun sort_comments/2 ), gleam@list:map( _pipe@4, fun view_rendered_comment/1 ) end ) end] )] ). -file("src/chilp/widget.gleam", 835). -spec js_browse(binary()) -> nil. js_browse(_) -> nil. -file("src/chilp/widget.gleam", 821). -spec browse(binary()) -> lustre@effect:effect(any()). browse(To) -> lustre@effect:from(fun(_) -> js_browse(To) end). -file("src/chilp/widget.gleam", 868). -spec bsky_thread_reply_decoder() -> gleam@dynamic@decode:decoder(bsky_thread_reply()). bsky_thread_reply_decoder() -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"record"/utf8>>, <<"createdAt"/utf8>>], gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Stringstamp) -> gleam@result:unwrap( gleam@time@timestamp:parse_rfc3339(Stringstamp), {timestamp, 0, 0} ) end ), fun(Created_at) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"uri"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(At_uri) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"record"/utf8>>, <<"text"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Body_text) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"author"/utf8>>, <<"did"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Author_did) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"author"/utf8>>, <<"handle"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Author_handle) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"author"/utf8>>, <<"displayName"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Author_displayname) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"author"/utf8>>, <<"avatar"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Author_avatar) -> gleam@dynamic@decode:subfield( [<<"post"/utf8>>, <<"likeCount"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Like_count) -> gleam@dynamic@decode:field( <<"replies"/utf8>>, gleam@dynamic@decode:list( bsky_thread_reply_decoder( ) ), fun( Children ) -> gleam@dynamic@decode:success( {bsky_thread_reply, At_uri, Like_count, Created_at, Body_text, Author_did, Author_handle, Author_displayname, Author_avatar, Children} ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/chilp/widget.gleam", 859). -spec bsky_thread_view_decoder() -> gleam@dynamic@decode:decoder(bsky_thread_view()). bsky_thread_view_decoder() -> gleam@dynamic@decode:subfield( [<<"thread"/utf8>>, <<"post"/utf8>>, <<"uri"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(At_uri) -> gleam@dynamic@decode:subfield( [<<"thread"/utf8>>, <<"replies"/utf8>>], gleam@dynamic@decode:list(bsky_thread_reply_decoder()), fun(Replies) -> gleam@dynamic@decode:success( {bsky_thread_view, At_uri, Replies} ) end ) end ). -file("src/chilp/widget.gleam", 712). -spec refresh_bsky(model()) -> lustre@effect:effect(msg()). refresh_bsky(Model) -> case erlang:element(5, Model) of {some, Anchor} -> Url = <<<<<<"https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=at://"/utf8, (erlang:element(2, Anchor))/binary>>/binary, "/app.bsky.feed.post/"/utf8>>/binary, (erlang:element(3, Anchor))/binary>>, Handler = rsvp:expect_json( bsky_thread_view_decoder(), fun(Response) -> case Response of {ok, Threadview} -> {bsky_incoming_thread_view, Threadview}; {error, Rsvperror} -> case Rsvperror of {unhandled_response, _} -> {all_stopping_error, <<"The response body we got back from Bluesky was misformed."/utf8>>}; {json_error, _} -> {all_stopping_error, <<"The response body we got back from Bluesky was misformed."/utf8>>}; bad_body -> {all_stopping_error, <<"The response body we got back from Bluesky was misformed."/utf8>>}; {bad_url, _} -> {all_stopping_error, <<"The API call to Bluesky failed. Did you enter the DID and post id correctly?"/utf8>>}; {http_error, _} -> {all_stopping_error, <<"Could not fetch comments from Bluesky."/utf8>>}; network_error -> {all_stopping_error, <<"Could not fetch comments from Bluesky."/utf8>>} end end end ), rsvp:get(Url, Handler); none -> lustre@effect:none() end. -file("src/chilp/widget.gleam", 938). -spec mastodon_decendant_inflater( mastodon_descendant(), list({mastodon_descendant(), binary()}) ) -> mastodon_descendant(). mastodon_decendant_inflater(Parent, All_children) -> {mastodon_descendant, erlang:element(2, Parent), erlang:element(3, Parent), erlang:element(4, Parent), erlang:element(5, Parent), erlang:element(6, Parent), gleam@list:filter_map( All_children, fun(C) -> case erlang:element(2, C) =:= erlang:element(2, Parent) of true -> {ok, erlang:element(1, C)}; false -> {error, nil} end end ), erlang:element(8, Parent), erlang:element(9, Parent), erlang:element(10, Parent), erlang:element(11, Parent)}. -file("src/chilp/widget.gleam", 971). ?DOC(" Decodes #(MastodonDescendant, ReplyingTo), to enable the parent decoder to make this into a recursive three.\n"). -spec mastodon_descendant_decoder() -> gleam@dynamic@decode:decoder({mastodon_descendant(), binary()}). mastodon_descendant_decoder() -> gleam@dynamic@decode:field( <<"in_reply_to_id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Replying_to) -> gleam@dynamic@decode:field( <<"id"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Id) -> gleam@dynamic@decode:field( <<"uri"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Uri) -> gleam@dynamic@decode:field( <<"created_at"/utf8>>, gleam@dynamic@decode:map( {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Stringstamp) -> gleam@result:unwrap( gleam@time@timestamp:parse_rfc3339( Stringstamp ), {timestamp, 0, 0} ) end ), fun(Created_at) -> gleam@dynamic@decode:field( <<"favourites_count"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_int/1}, fun(Favourite_count) -> gleam@dynamic@decode:field( <<"content"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Unescaped_html_content) -> Content = chilp@internal:sanitise_ls( Unescaped_html_content ), Children = [], gleam@dynamic@decode:subfield( [<<"account"/utf8>>, <<"url"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun(Author_url) -> gleam@dynamic@decode:subfield( [<<"account"/utf8>>, <<"avatar"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun( Author_avatar_url ) -> gleam@dynamic@decode:subfield( [<<"account"/utf8>>, <<"display_name"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun( Author_displayname ) -> gleam@dynamic@decode:subfield( [<<"account"/utf8>>, <<"acct"/utf8>>], {decoder, fun gleam@dynamic@decode:decode_string/1}, fun( Author_username ) -> gleam@dynamic@decode:success( {{mastodon_descendant, Id, Uri, Content, Created_at, Favourite_count, Children, Author_url, Author_avatar_url, Author_username, Author_displayname}, Replying_to} ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/chilp/widget.gleam", 914). -spec mastodon_status_context_decoder(binary()) -> gleam@dynamic@decode:decoder(mastodon_status_context()). mastodon_status_context_decoder(Original_id) -> gleam@dynamic@decode:field( <<"descendants"/utf8>>, gleam@dynamic@decode:list(mastodon_descendant_decoder()), fun(Flat_descendants) -> Descendants = gleam@list:filter_map( Flat_descendants, fun(Desc) -> case erlang:element(2, Desc) =:= Original_id of true -> _pipe = mastodon_decendant_inflater( erlang:element(1, Desc), Flat_descendants ), {ok, _pipe}; false -> {error, nil} end end ), gleam@dynamic@decode:success({mastodon_status_context, Descendants}) end ). -file("src/chilp/widget.gleam", 783). -spec refresh_mastodon(model()) -> lustre@effect:effect(msg()). refresh_mastodon(Model) -> case erlang:element(2, Model) of {some, Anchor} -> Url = <<<<<<<<"https://"/utf8, (erlang:element(2, Anchor))/binary>>/binary, "/api/v1/statuses/"/utf8>>/binary, (erlang:element(3, Anchor))/binary>>/binary, "/context"/utf8>>, Handler = rsvp:expect_json( mastodon_status_context_decoder(erlang:element(3, Anchor)), fun(Response) -> case Response of {ok, Status} -> {mastodon_incoming_status, Status}; {error, Rsvperror} -> case Rsvperror of {unhandled_response, _} -> {all_stopping_error, <<"The response body we got back from Mastodon was misformed."/utf8>>}; {json_error, _} -> {all_stopping_error, <<"The response body we got back from Mastodon was misformed."/utf8>>}; bad_body -> {all_stopping_error, <<"The response body we got back from Mastodon was misformed."/utf8>>}; {bad_url, _} -> {all_stopping_error, <<"The API call to Mastodon failed. Did you enter the instance and post id correctly?"/utf8>>}; {http_error, _} -> {all_stopping_error, <<"Could not fetch comments from Mastodon."/utf8>>}; network_error -> {all_stopping_error, <<"Could not fetch comments from Mastodon."/utf8>>} end end end ), rsvp:get(Url, Handler); none -> lustre@effect:none() end. -file("src/chilp/widget.gleam", 1014). -spec coalesce_views(list(bsky_thread_reply()), list(mastodon_descendant())) -> list(coalesced_view()). coalesce_views(Bsky, Mastodon) -> Mixed = begin _pipe = lists:append( gleam@list:map(Bsky, fun(M) -> {ok, M} end), gleam@list:map(Mastodon, fun(M@1) -> {error, M@1} end) ), gleam@list:shuffle(_pipe) end, gleam@list:map(Mixed, fun(Item) -> case Item of {ok, {bsky_thread_reply, At_uri, Like_count, Created_at, Body_text, Author_did, Author_handle, Author_displayname, Author_avatar, Children}} -> {coalesced_view, Created_at, <<"https://bluesky.app/profile/"/utf8, Author_did/binary>>, Author_avatar, Author_handle, <<"Bluesky"/utf8>>, Author_displayname, lustre@element:text(Body_text), <<"https://bsky.app/profile/"/utf8, (gleam@string:replace( At_uri, <<"/app.bsky.feed.post/"/utf8>>, <<"/post/"/utf8>> ))/binary>>, Like_count, (coalesce_views(Children, []))}; {error, {mastodon_descendant, Id, Uri, Content, Created_at@1, Favourite_count, Children@1, Author_url, Author_avatar_url, Author_username, Author_displayname@1}} -> {coalesced_view, Created_at@1, Author_url, Author_avatar_url, Author_username, <<"Mastodon"/utf8>>, Author_displayname@1, Content, Uri, Favourite_count, (coalesce_views([], Children@1))} end end). -file("src/chilp/widget.gleam", 701). -spec new_coalesced_view(list(bsky_thread_reply()), list(mastodon_descendant())) -> lustre@effect:effect(msg()). new_coalesced_view(Bsky_replies, Mastodon_descendants) -> lustre@effect:from( fun(Dispatch) -> Dispatch( {incoming_coalesced_view, coalesce_views(Bsky_replies, Mastodon_descendants)} ) end ). -file("src/chilp/widget.gleam", 124). -spec update(model(), msg()) -> {model(), lustre@effect:effect(msg())}. update(Model, Msg) -> case Msg of {all_stopping_error, Msg@1} -> {{model, erlang:element(2, Model), erlang:element(3, Model), erlang:element(4, Model), erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), {some, Msg@1}, erlang:element(9, Model), erlang:element(10, Model)}, lustre@effect:none()}; mastodon_un_anchored -> {{model, none, erlang:element(3, Model), erlang:element(4, Model), erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, lustre@effect:none()}; {mastodon_answer, Instance} -> case erlang:element(2, Model) of {some, Anchor} when Instance =/= <<""/utf8>> -> {Model, browse( (<<<<<<"https://"/utf8, Instance/binary>>/binary, "/authorize_interaction?uri="/utf8>>/binary, (begin _pipe = (<<<<<<<<<<"https://"/utf8, (erlang:element( 2, Anchor ))/binary>>/binary, "/@"/utf8>>/binary, (erlang:element(4, Model))/binary>>/binary, "/"/utf8>>/binary, (erlang:element(3, Anchor))/binary>>), gleam_stdlib:percent_encode(_pipe) end)/binary>>) )}; _ -> {Model, lustre@effect:none()} end; {mastodon_anchored, Instance@1, Post} -> Model@1 = {model, {some, {mastodon, Instance@1, Post}}, erlang:element(3, Model), erlang:element(4, Model), erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, {Model@1, lustre@effect:batch( [get_username_mastodon(Model@1), refresh_mastodon(Model@1)] )}; {mastodon_incoming_op_username, Mastodon_op_username} -> {{model, erlang:element(2, Model), erlang:element(3, Model), Mastodon_op_username, erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, lustre@effect:none()}; {mastodon_incoming_status, Status} -> {{model, erlang:element(2, Model), erlang:element(2, Status), erlang:element(4, Model), erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, new_coalesced_view( erlang:element(6, Model), erlang:element(2, Status) )}; bsky_un_anchored -> {{model, erlang:element(2, Model), erlang:element(3, Model), erlang:element(4, Model), none, erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, lustre@effect:none()}; {bsky_anchored, Did, Post@1} -> Model@2 = {model, erlang:element(2, Model), erlang:element(3, Model), erlang:element(4, Model), {some, {bluesky, Did, Post@1}}, erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, {Model@2, lustre@effect:batch([refresh_bsky(Model@2)])}; {bsky_incoming_thread_view, Threadview} -> {{model, erlang:element(2, Model), erlang:element(3, Model), erlang:element(4, Model), erlang:element(5, Model), erlang:element(3, Threadview), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), erlang:element(10, Model)}, new_coalesced_view( erlang:element(3, Threadview), erlang:element(3, Model) )}; {set_tab, Open_tab} -> {{model, erlang:element(2, Model), erlang:element(3, Model), erlang:element(4, Model), erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), erlang:element(9, Model), Open_tab}, lustre@effect:none()}; {incoming_coalesced_view, New} -> {{model, erlang:element(2, Model), erlang:element(3, Model), erlang:element(4, Model), erlang:element(5, Model), erlang:element(6, Model), erlang:element(7, Model), erlang:element(8, Model), New, erlang:element(10, Model)}, lustre@effect:none()} end. -file("src/chilp/widget.gleam", 666). -spec placeholder_instance(chilp@widget@anchors:mastodon()) -> binary(). placeholder_instance(Mastodon_anchor) -> _pipe = [erlang:element(2, Mastodon_anchor) | [<<"mastodon.social"/utf8>>, <<"pony.social"/utf8>>, <<"todon.nl"/utf8>>, <<"mstdn.social"/utf8>>, <<"infosec.exchange"/utf8>>, <<"woem.space"/utf8>>, <<"shitpost.trade"/utf8>>, <<"procial.tchncs.de"/utf8>>]], _pipe@1 = gleam@list:shuffle(_pipe), _pipe@2 = gleam@list:first(_pipe@1), gleam@result:unwrap(_pipe@2, erlang:element(2, Mastodon_anchor)). -file("src/chilp/widget.gleam", 592). -spec view_mastodon_respond_form(chilp@widget@anchors:mastodon()) -> lustre@vdom@vnode:element(msg()). view_mastodon_respond_form(Mastodon_anchor) -> lustre@element@html:'div'( [lustre@attribute:class(<<"my-5 px-5 pb-5 "/utf8>>)], [lustre@element@html:form( [lustre@attribute:class(<<"mb-8 w-full"/utf8>>), lustre@event:on_submit( fun(N) -> Value = begin _pipe = gleam@list:key_find( N, <<"userinstance"/utf8>> ), gleam@result:unwrap(_pipe, <<""/utf8>>) end, {mastodon_answer, Value} end )], [lustre@element@html:'div'( [lustre@attribute:class(<<"flex flex-col gap-2"/utf8>>)], [lustre@element@html:label( [lustre@attribute:for(<<"userinstance"/utf8>>), lustre@attribute:class( <<"text-sm font-semibold text-base-content/80"/utf8>> )], [lustre@element@html:text( <<"Enter your instance address to reply or "/utf8>> ), lustre@element@html:a( [lustre@attribute:href( <<<<"https://"/utf8, (placeholder_instance( Mastodon_anchor ))/binary>>/binary, "/auth/sign_up"/utf8>> ), lustre@attribute:class( <<"link link-primary-content"/utf8>> )], [lustre@element@html:text( <<"create an account"/utf8>> )] ), lustre@element@html:text(<<"!"/utf8>>)] ), lustre@element@html:p( [lustre@attribute:class( <<"text-xs italic opacity-50 -mt-1 mb-2 ml-1"/utf8>> )], [lustre@element@html:text( <<"on the instance recommended by this widget... or one you pick yourself!"/utf8>> )] ), lustre@element@html:'div'( [lustre@attribute:class( <<"join w-full shadow-sm"/utf8>> )], [lustre@element@html:input( [lustre@attribute:type_(<<"text"/utf8>>), lustre@attribute:required(true), lustre@attribute:placeholder( placeholder_instance( Mastodon_anchor ) ), lustre@attribute:pattern( <<"^([a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}$"/utf8>> ), lustre@attribute:name( <<"userinstance"/utf8>> ), lustre@attribute:class( <<"input input-bordered join-item flex-1 focus:outline-primary"/utf8>> )] ), lustre@element@html:button( [lustre@attribute:type_( <<"submit"/utf8>> ), lustre@attribute:class( <<"btn btn-primary join-item"/utf8>> )], [lustre@element@html:text( <<"Go reply"/utf8>> )] )] )] )] )] ). -file("src/chilp/widget.gleam", 219). -spec view_normal(model()) -> lustre@vdom@vnode:element(msg()). view_normal(Model) -> {Linkedto, Respond_here} = case {erlang:element(5, Model), erlang:element(2, Model)} of {{some, Bsky}, {some, Masto}} -> {begin _pipe = [lustre@element@html:a( [lustre@attribute:href( <<<<<<<<<<"https://"/utf8, (erlang:element( 2, Masto ))/binary>>/binary, "/@"/utf8>>/binary, (erlang:element(4, Model))/binary>>/binary, "/"/utf8>>/binary, (erlang:element(3, Masto))/binary>> ), lustre@attribute:class( <<"link text-[#595aff]"/utf8>> )], [lustre@element@html:text(<<"this post"/utf8>>)] ), lustre@element@html:text( <<" on Mastodon, and to "/utf8>> ), lustre@element@html:a( [lustre@attribute:href( <<<<<<"https://bsky.app/profile/"/utf8, (erlang:element(2, Bsky))/binary>>/binary, "/post/"/utf8>>/binary, (erlang:element(3, Bsky))/binary>> ), lustre@attribute:class( <<"link text-[#006aff]"/utf8>> )], [lustre@element@html:text(<<"this post"/utf8>>)] ), lustre@element@html:text(<<" on Bluesky."/utf8>>)], lustre@element:fragment(_pipe) end, begin _pipe@1 = [lustre@element@html:'div'( [lustre@attribute:class( <<"tabs tabs-box border-b-2 border-base-300 h-full"/utf8>> ), lustre@attribute:role(<<"tablist"/utf8>>)], [lustre@element@html:a( [lustre@attribute:role(<<"tab"/utf8>>), lustre@event:on_click({set_tab, 1}), lustre@attribute:classes( [{<<"tab"/utf8>>, true}, {<<"tab-active"/utf8>>, erlang:element(10, Model) =:= 1}] )], [lustre@element@html:text( <<"Mastodon"/utf8>> )] ), lustre@element@html:a( [lustre@attribute:role(<<"tab"/utf8>>), lustre@event:on_click({set_tab, 2}), lustre@attribute:classes( [{<<"tab"/utf8>>, true}, {<<"tab-active"/utf8>>, erlang:element(10, Model) =:= 2}] )], [lustre@element@html:text( <<"Bluesky"/utf8>> )] ), lustre@element@html:a( [lustre@attribute:role(<<"tab"/utf8>>), lustre@event:on_click({set_tab, 3}), lustre@attribute:classes( [{<<"tab"/utf8>>, true}, {<<"tab-active"/utf8>>, erlang:element(10, Model) =:= 3}] )], [lustre@element@html:text(<<"About"/utf8>>)] )] ), lustre@element@html:br([]), case erlang:element(10, Model) of 2 -> view_respond_on_bsky( <<<<<<"https://bsky.app/profile/"/utf8, (erlang:element(2, Bsky))/binary>>/binary, "/post/"/utf8>>/binary, (erlang:element(3, Bsky))/binary>> ); 3 -> view_about_chilp(); _ -> view_mastodon_respond_form(Masto) end], lustre@element:fragment(_pipe@1) end}; {none, {some, Masto@1}} -> {begin _pipe@2 = [lustre@element@html:a( [lustre@attribute:href( <<<<<<<<<<"https://"/utf8, (erlang:element( 2, Masto@1 ))/binary>>/binary, "/"/utf8>>/binary, (erlang:element(4, Model))/binary>>/binary, "/"/utf8>>/binary, (erlang:element(3, Masto@1))/binary>> ), lustre@attribute:class( <<"link text-[#595aff]"/utf8>> )], [lustre@element@html:text(<<"this post"/utf8>>)] ), lustre@element@html:text(<<" on Mastodon."/utf8>>)], lustre@element:fragment(_pipe@2) end, view_mastodon_respond_form(Masto@1)}; {{some, Bsky@1}, none} -> {begin _pipe@3 = [lustre@element@html:a( [lustre@attribute:href( <<<<<<"https://bsky.app/profile/"/utf8, (erlang:element(2, Bsky@1))/binary>>/binary, "/post/"/utf8>>/binary, (erlang:element(3, Bsky@1))/binary>> ), lustre@attribute:class( <<"link link-[#006aff]"/utf8>> )], [lustre@element@html:text(<<"this post"/utf8>>)] ), lustre@element@html:text(<<" on Bluesky."/utf8>>)], lustre@element:fragment(_pipe@3) end, view_respond_on_bsky( <<<<<<"https://bsky.app/profile/"/utf8, (erlang:element(2, Bsky@1))/binary>>/binary, "/post/"/utf8>>/binary, (erlang:element(3, Bsky@1))/binary>> )}; {none, none} -> {error_view( <<"No comment backends are configured for this widget."/utf8>> ), lustre@element:none()} end, lustre@element@html:'div'( [lustre@attribute:class(<<"comment-widget"/utf8>>)], [lustre@element@html:'div'( [lustre@attribute:class( <<"widget card bg-base-100 shadow-xl border border-base-200 p-10"/utf8>> )], [lustre@element@html:h1( [lustre@attribute:class( <<"text-2xl font-extrabold text-base-content"/utf8>> )], [lustre@element@html:text(<<"Comments"/utf8>>)] ), lustre@element@html:p( [lustre@attribute:class( <<"text-sm text-base-content/70"/utf8>> )], [lustre@element@html:text(<<"Linked to "/utf8>>), Linkedto] ), lustre@element@html:'div'( [lustre@attribute:class( <<"card card-dash bg-base-200/70 border-base-300"/utf8>> )], [Respond_here] ), lustre@element@html:section( [lustre@attribute:class(<<"pt-5 space-y-10"/utf8>>)], begin _pipe@4 = gleam@list:sort( erlang:element(9, Model), fun sort_comments/2 ), gleam@list:map(_pipe@4, fun view_rendered_comment/1) end )] )] ). -file("src/chilp/widget.gleam", 212). -spec view(model()) -> lustre@vdom@vnode:element(msg()). view(Model) -> case erlang:element(8, Model) of none -> view_normal(Model); {some, Error} -> error_view(Error) end. -file("src/chilp/widget.gleam", 30). -spec register() -> {ok, nil} | {error, lustre:error()}. register() -> Component = lustre:component( fun init/1, fun update/2, fun view/1, [lustre@component:on_attribute_change( <<"mastodon-anchor"/utf8>>, fun(Value) -> gleam@bool:guard( Value =:= <<""/utf8>>, {ok, mastodon_un_anchored}, fun() -> _pipe = Value, _pipe@1 = gleam@string:split_once( _pipe, <<"\\"/utf8>> ), gleam@result:map( _pipe@1, fun(A) -> {mastodon_anchored, erlang:element(1, A), erlang:element(2, A)} end ) end ) end ), lustre@component:on_attribute_change( <<"bluesky-anchor"/utf8>>, fun(Value@1) -> gleam@bool:guard( Value@1 =:= <<""/utf8>>, {ok, bsky_un_anchored}, fun() -> _pipe@2 = Value@1, _pipe@3 = gleam@string:split_once( _pipe@2, <<"\\"/utf8>> ), gleam@result:map( _pipe@3, fun(A@1) -> {bsky_anchored, erlang:element(1, A@1), erlang:element(2, A@1)} end ) end ) end )] ), lustre:register(Component, <<"comment-widget"/utf8>>).