Something went wrong. Try again.
📰 A single-page application to manage standard.site publication on the AT Protocol cuducos.tngl.io/std-pub
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253module Lexicons exposing ( blobRefDecoder , documentDecoder , emptyPublication , hexToRgb , publicationListItemDecoder , publicationRecordEncoder , rgbToHex )
import Json.Decode as Decode exposing (Decoder)import Json.Encode as Encodeimport Types exposing (..)
-- Publication
publicationListItemDecoder : Decoder PublicationpublicationListItemDecoder = Decode.map8 Publication (Decode.field "uri" rkeyFromUri) (Decode.field "value" (Decode.field "url" Decode.string)) (Decode.field "value" (Decode.field "name" Decode.string)) (Decode.field "value" (Decode.maybe (Decode.field "description" Decode.string))) (Decode.field "value" (Decode.maybe (Decode.field "icon" blobRefDecoder))) (Decode.field "value" (Decode.maybe (Decode.field "basicTheme" basicThemeDecoder))) (Decode.field "value" (Decode.maybe (Decode.field "preferences" preferencesDecoder))) (Decode.field "value" (Decode.maybe (Decode.field "createdAt" Decode.string)))
rkeyFromUri : Decoder StringrkeyFromUri = Decode.string |> Decode.map (\uri -> uri |> String.split "/" |> List.reverse |> List.head |> Maybe.withDefault "" )
basicThemeDecoder : Decoder BasicThemebasicThemeDecoder = Decode.map4 BasicTheme (Decode.field "background" rgbDecoder) (Decode.field "foreground" rgbDecoder) (Decode.field "accent" rgbDecoder) (Decode.field "accentForeground" rgbDecoder)
rgbDecoder : Decoder RgbColorrgbDecoder = Decode.map3 RgbColor (Decode.field "r" Decode.int) (Decode.field "g" Decode.int) (Decode.field "b" Decode.int)
blobRefDecoder : Decoder BlobRefblobRefDecoder = Decode.map3 BlobRef (Decode.at [ "ref", "$link" ] Decode.string) (Decode.field "mimeType" Decode.string) (Decode.field "size" Decode.int)
preferencesDecoder : Decoder PreferencespreferencesDecoder = Decode.map Preferences (Decode.maybe (Decode.field "showInDiscover" Decode.bool))
-- Publication record encoder (only includes fields that are Just)
publicationRecordEncoder : Publication -> Encode.ValuepublicationRecordEncoder pub = let required : List ( String, Encode.Value ) required = [ ( "$type", Encode.string "site.standard.publication" ) , ( "url", Encode.string pub.url ) , ( "name", Encode.string pub.name ) ]
optionals : List ( String, Encode.Value ) optionals = List.filterMap identity [ Maybe.map (\d -> ( "description", Encode.string d )) pub.description , Maybe.map (\i -> ( "icon", blobRefEncoder i )) pub.icon , Maybe.map (\t -> ( "basicTheme", basicThemeEncoder t )) pub.basicTheme , Maybe.map (\p -> ( "preferences", preferencesEncoder p )) pub.preferences , Maybe.map (\c -> ( "createdAt", Encode.string c )) pub.createdAt ] in Encode.object (required ++ optionals)
basicThemeEncoder : BasicTheme -> Encode.ValuebasicThemeEncoder theme = Encode.object [ ( "$type", Encode.string "site.standard.theme.basic" ) , ( "background", rgbEncoder theme.background ) , ( "foreground", rgbEncoder theme.foreground ) , ( "accent", rgbEncoder theme.accent ) , ( "accentForeground", rgbEncoder theme.accentForeground ) ]
rgbEncoder : RgbColor -> Encode.ValuergbEncoder c = Encode.object [ ( "$type", Encode.string "site.standard.theme.color#rgb" ) , ( "r", Encode.int c.r ) , ( "g", Encode.int c.g ) , ( "b", Encode.int c.b ) ]
blobRefEncoder : BlobRef -> Encode.ValueblobRefEncoder blob = Encode.object [ ( "$type", Encode.string "blob" ) , ( "ref", Encode.object [ ( "$link", Encode.string blob.link ) ] ) , ( "mimeType", Encode.string blob.mimeType ) , ( "size", Encode.int blob.size ) ]
preferencesEncoder : Preferences -> Encode.ValuepreferencesEncoder prefs = Encode.object (List.filterMap identity [ Maybe.map (\b -> ( "showInDiscover", Encode.bool b )) prefs.showInDiscover ] )
-- Document
documentDecoder : Decoder DocumentdocumentDecoder = Decode.map6 Document (Decode.field "title" Decode.string) (Decode.maybe (Decode.field "path" Decode.string)) (Decode.field "site" Decode.string) (Decode.field "publishedAt" Decode.string) (Decode.maybe (Decode.field "url" Decode.string)) (Decode.maybe (Decode.field "description" Decode.string))
-- Hex ↔ RGB helpers
hexToRgb : String -> Maybe RgbColorhexToRgb raw = let cleaned : String cleaned = if String.startsWith "#" raw then String.dropLeft 1 raw
else raw in if String.length cleaned == 6 then Maybe.map3 RgbColor (parseHexByte (String.slice 0 2 cleaned)) (parseHexByte (String.slice 2 4 cleaned)) (parseHexByte (String.slice 4 6 cleaned))
else Nothing
rgbToHex : RgbColor -> StringrgbToHex c = "#" ++ byteToHex c.r ++ byteToHex c.g ++ byteToHex c.b
parseHexByte : String -> Maybe IntparseHexByte s = case String.toList (String.toLower s) of [ a, b ] -> Maybe.map2 (\x y -> x * 16 + y) (hexDigit a) (hexDigit b)
_ -> Nothing
hexDigit : Char -> Maybe InthexDigit c = if c >= '0' && c <= '9' then Just (Char.toCode c - Char.toCode '0')
else if c >= 'a' && c <= 'f' then Just (Char.toCode c - Char.toCode 'a' + 10)
else Nothing
byteToHex : Int -> StringbyteToHex n = let clamped : Int clamped = clamp 0 255 n
hi : Int hi = clamped // 16
lo : Int lo = modBy 16 clamped in hexDigitToChar hi ++ hexDigitToChar lo
hexDigitToChar : Int -> StringhexDigitToChar n = if n < 10 then String.fromInt n
else String.fromChar (Char.fromCode (Char.toCode 'a' + n - 10))
-- Empty publication (for Create flow)
emptyPublication : PublicationemptyPublication = { rkey = "" , url = "" , name = "" , description = Nothing , icon = Nothing , basicTheme = Nothing , preferences = Nothing , createdAt = Nothing }