* Render user mentions in the second column. * Add a timeline type toggler.
This commit is contained in:
parent
b10761a413
commit
440806fa80
@ -3,7 +3,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
min-height: 75px;
|
min-height: 50px;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,9 +11,18 @@ body {
|
|||||||
background: #493438;
|
background: #493438;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reblog > p:first-of-type {
|
.reblog > p:first-of-type,
|
||||||
|
.notification > p:first-of-type {
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
.reblog > p:first-of-type > a,
|
||||||
|
.notification > p:first-of-type > a {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification.follow > p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-heading {
|
.panel-heading {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -53,7 +62,7 @@ body {
|
|||||||
color: #efefef;
|
color: #efefef;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-text a, .u-url, .mention, .hashtag, .tag {
|
.status-text a, .u-url, .status .mention, .hashtag, .tag {
|
||||||
color: #9baec8;
|
color: #9baec8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ module Mastodon
|
|||||||
, Client
|
, Client
|
||||||
, Error(..)
|
, Error(..)
|
||||||
, Mention
|
, Mention
|
||||||
|
, Notification
|
||||||
, Reblog(..)
|
, Reblog(..)
|
||||||
, Status
|
, Status
|
||||||
, StatusRequestBody
|
, StatusRequestBody
|
||||||
@ -17,8 +18,9 @@ module Mastodon
|
|||||||
, getAuthorizationUrl
|
, getAuthorizationUrl
|
||||||
, getAccessToken
|
, getAccessToken
|
||||||
, fetchAccount
|
, fetchAccount
|
||||||
, fetchPublicTimeline
|
|
||||||
, fetchLocalTimeline
|
, fetchLocalTimeline
|
||||||
|
, fetchNotifications
|
||||||
|
, fetchPublicTimeline
|
||||||
, fetchUserTimeline
|
, fetchUserTimeline
|
||||||
, postStatus
|
, postStatus
|
||||||
, send
|
, send
|
||||||
@ -125,6 +127,22 @@ type alias Mention =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Notification =
|
||||||
|
{-
|
||||||
|
- id: The notification ID
|
||||||
|
- type_: One of: "mention", "reblog", "favourite", "follow"
|
||||||
|
- created_at: The time the notification was created
|
||||||
|
- account: The Account sending the notification to the user
|
||||||
|
- status: The Status associated with the notification, if applicable
|
||||||
|
-}
|
||||||
|
{ id : Int
|
||||||
|
, type_ : String
|
||||||
|
, created_at : String
|
||||||
|
, account : Account
|
||||||
|
, status : Maybe Status
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type alias Tag =
|
type alias Tag =
|
||||||
{ name : String
|
{ name : String
|
||||||
, url : String
|
, url : String
|
||||||
@ -287,6 +305,16 @@ mentionDecoder =
|
|||||||
|> Pipe.required "acct" Decode.string
|
|> Pipe.required "acct" Decode.string
|
||||||
|
|
||||||
|
|
||||||
|
notificationDecoder : Decode.Decoder Notification
|
||||||
|
notificationDecoder =
|
||||||
|
Pipe.decode Notification
|
||||||
|
|> Pipe.required "id" Decode.int
|
||||||
|
|> Pipe.required "type" Decode.string
|
||||||
|
|> Pipe.required "created_at" Decode.string
|
||||||
|
|> Pipe.required "account" accountDecoder
|
||||||
|
|> Pipe.optional "status" (Decode.nullable statusDecoder) Nothing
|
||||||
|
|
||||||
|
|
||||||
tagDecoder : Decode.Decoder Tag
|
tagDecoder : Decode.Decoder Tag
|
||||||
tagDecoder =
|
tagDecoder =
|
||||||
Pipe.decode Tag
|
Pipe.decode Tag
|
||||||
@ -450,17 +478,22 @@ fetchAccount client accountId =
|
|||||||
|
|
||||||
fetchUserTimeline : Client -> Request (List Status)
|
fetchUserTimeline : Client -> Request (List Status)
|
||||||
fetchUserTimeline client =
|
fetchUserTimeline client =
|
||||||
fetch client "/api/v1/timelines/home" (Decode.list statusDecoder)
|
fetch client "/api/v1/timelines/home" <| Decode.list statusDecoder
|
||||||
|
|
||||||
|
|
||||||
fetchLocalTimeline : Client -> Request (List Status)
|
fetchLocalTimeline : Client -> Request (List Status)
|
||||||
fetchLocalTimeline client =
|
fetchLocalTimeline client =
|
||||||
fetch client "/api/v1/timelines/public?local=true" (Decode.list statusDecoder)
|
fetch client "/api/v1/timelines/public?local=true" <| Decode.list statusDecoder
|
||||||
|
|
||||||
|
|
||||||
fetchPublicTimeline : Client -> Request (List Status)
|
fetchPublicTimeline : Client -> Request (List Status)
|
||||||
fetchPublicTimeline client =
|
fetchPublicTimeline client =
|
||||||
fetch client "/api/v1/timelines/public" (Decode.list statusDecoder)
|
fetch client "/api/v1/timelines/public" <| Decode.list statusDecoder
|
||||||
|
|
||||||
|
|
||||||
|
fetchNotifications : Client -> Request (List Notification)
|
||||||
|
fetchNotifications client =
|
||||||
|
fetch client "/api/v1/notifications" <| Decode.list notificationDecoder
|
||||||
|
|
||||||
|
|
||||||
postStatus : Client -> StatusRequestBody -> Request Status
|
postStatus : Client -> StatusRequestBody -> Request Status
|
||||||
|
@ -25,13 +25,15 @@ type Msg
|
|||||||
| AppRegistered (Result Mastodon.Error Mastodon.AppRegistration)
|
| AppRegistered (Result Mastodon.Error Mastodon.AppRegistration)
|
||||||
| DraftEvent DraftMsg
|
| DraftEvent DraftMsg
|
||||||
| LocalTimeline (Result Mastodon.Error (List Mastodon.Status))
|
| LocalTimeline (Result Mastodon.Error (List Mastodon.Status))
|
||||||
| PublicTimeline (Result Mastodon.Error (List Mastodon.Status))
|
| Notifications (Result Mastodon.Error (List Mastodon.Notification))
|
||||||
| OnLoadUserAccount Int
|
| OnLoadUserAccount Int
|
||||||
|
| PublicTimeline (Result Mastodon.Error (List Mastodon.Status))
|
||||||
| Register
|
| Register
|
||||||
| ServerChange String
|
| ServerChange String
|
||||||
| StatusPosted (Result Mastodon.Error Mastodon.Status)
|
| StatusPosted (Result Mastodon.Error Mastodon.Status)
|
||||||
| SubmitDraft
|
| SubmitDraft
|
||||||
| UrlChange Navigation.Location
|
| UrlChange Navigation.Location
|
||||||
|
| UseGlobalTimeline Bool
|
||||||
| UserAccount (Result Mastodon.Error Mastodon.Account)
|
| UserAccount (Result Mastodon.Error Mastodon.Account)
|
||||||
| UserTimeline (Result Mastodon.Error (List Mastodon.Status))
|
| UserTimeline (Result Mastodon.Error (List Mastodon.Status))
|
||||||
|
|
||||||
@ -43,10 +45,12 @@ type alias Model =
|
|||||||
, userTimeline : List Mastodon.Status
|
, userTimeline : List Mastodon.Status
|
||||||
, localTimeline : List Mastodon.Status
|
, localTimeline : List Mastodon.Status
|
||||||
, publicTimeline : List Mastodon.Status
|
, publicTimeline : List Mastodon.Status
|
||||||
|
, notifications : List Mastodon.Notification
|
||||||
, draft : Mastodon.StatusRequestBody
|
, draft : Mastodon.StatusRequestBody
|
||||||
, account : Maybe Mastodon.Account
|
, account : Maybe Mastodon.Account
|
||||||
, errors : List String
|
, errors : List String
|
||||||
, location : Navigation.Location
|
, location : Navigation.Location
|
||||||
|
, useGlobalTimeline : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,10 +86,12 @@ init flags location =
|
|||||||
, userTimeline = []
|
, userTimeline = []
|
||||||
, localTimeline = []
|
, localTimeline = []
|
||||||
, publicTimeline = []
|
, publicTimeline = []
|
||||||
|
, notifications = []
|
||||||
, draft = defaultDraft
|
, draft = defaultDraft
|
||||||
, account = Nothing
|
, account = Nothing
|
||||||
, errors = []
|
, errors = []
|
||||||
, location = location
|
, location = location
|
||||||
|
, useGlobalTimeline = False
|
||||||
}
|
}
|
||||||
! [ initCommands flags.registration flags.client authCode ]
|
! [ initCommands flags.registration flags.client authCode ]
|
||||||
|
|
||||||
@ -143,6 +149,7 @@ loadTimelines client =
|
|||||||
[ Mastodon.fetchUserTimeline client |> Mastodon.send UserTimeline
|
[ Mastodon.fetchUserTimeline client |> Mastodon.send UserTimeline
|
||||||
, Mastodon.fetchLocalTimeline client |> Mastodon.send LocalTimeline
|
, Mastodon.fetchLocalTimeline client |> Mastodon.send LocalTimeline
|
||||||
, Mastodon.fetchPublicTimeline client |> Mastodon.send PublicTimeline
|
, Mastodon.fetchPublicTimeline client |> Mastodon.send PublicTimeline
|
||||||
|
, Mastodon.fetchNotifications client |> Mastodon.send Notifications
|
||||||
]
|
]
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
@ -271,6 +278,9 @@ update msg model =
|
|||||||
Nothing ->
|
Nothing ->
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
UseGlobalTimeline flag ->
|
||||||
|
{ model | useGlobalTimeline = flag } ! []
|
||||||
|
|
||||||
LocalTimeline result ->
|
LocalTimeline result ->
|
||||||
case result of
|
case result of
|
||||||
Ok localTimeline ->
|
Ok localTimeline ->
|
||||||
@ -297,3 +307,11 @@ update msg model =
|
|||||||
|
|
||||||
StatusPosted _ ->
|
StatusPosted _ ->
|
||||||
{ model | draft = defaultDraft } ! [ loadTimelines model.client ]
|
{ model | draft = defaultDraft } ! [ loadTimelines model.client ]
|
||||||
|
|
||||||
|
Notifications result ->
|
||||||
|
case result of
|
||||||
|
Ok notifications ->
|
||||||
|
{ model | notifications = notifications } ! []
|
||||||
|
|
||||||
|
Err error ->
|
||||||
|
{ model | notifications = [], errors = (errorText error) :: model.errors } ! []
|
||||||
|
244
src/View.elm
244
src/View.elm
@ -39,6 +39,15 @@ icon name =
|
|||||||
i [ class <| "glyphicon glyphicon-" ++ name ] []
|
i [ class <| "glyphicon glyphicon-" ++ name ] []
|
||||||
|
|
||||||
|
|
||||||
|
accountLink : Mastodon.Account -> Html Msg
|
||||||
|
accountLink account =
|
||||||
|
a
|
||||||
|
[ href account.url
|
||||||
|
, ViewHelper.onClickWithPreventAndStop (OnLoadUserAccount account.id)
|
||||||
|
]
|
||||||
|
[ text <| "@" ++ account.username ]
|
||||||
|
|
||||||
|
|
||||||
attachmentPreview : Maybe Bool -> Mastodon.Attachment -> Html Msg
|
attachmentPreview : Maybe Bool -> Mastodon.Attachment -> Html Msg
|
||||||
attachmentPreview sensitive ({ url, preview_url } as attachment) =
|
attachmentPreview sensitive ({ url, preview_url } as attachment) =
|
||||||
let
|
let
|
||||||
@ -227,6 +236,61 @@ timelineView statuses label iconName =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
notificationHeading : Mastodon.Account -> String -> String -> Html Msg
|
||||||
|
notificationHeading account str iconType =
|
||||||
|
p [] <|
|
||||||
|
List.intersperse (text " ")
|
||||||
|
[ icon iconType, accountLink account, text str ]
|
||||||
|
|
||||||
|
|
||||||
|
notificationStatusView : Mastodon.Status -> Mastodon.Notification -> Html Msg
|
||||||
|
notificationStatusView status { type_, account } =
|
||||||
|
div [ class "notification mention" ]
|
||||||
|
[ case type_ of
|
||||||
|
"reblog" ->
|
||||||
|
notificationHeading account "boosted your toot" "fire"
|
||||||
|
|
||||||
|
"favourite" ->
|
||||||
|
notificationHeading account "favourited your toot" "star"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
text ""
|
||||||
|
, statusView status
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
notificationFollowView : Mastodon.Notification -> Html Msg
|
||||||
|
notificationFollowView { account } =
|
||||||
|
div [ class "notification follow" ]
|
||||||
|
[ notificationHeading account "started following you" "user" ]
|
||||||
|
|
||||||
|
|
||||||
|
notificationEntryView : Mastodon.Notification -> Html Msg
|
||||||
|
notificationEntryView notification =
|
||||||
|
li [ class "list-group-item" ]
|
||||||
|
[ case notification.status of
|
||||||
|
Just status ->
|
||||||
|
notificationStatusView status notification
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
notificationFollowView notification
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
notificationListView : List Mastodon.Notification -> Html Msg
|
||||||
|
notificationListView notifications =
|
||||||
|
div [ class "col-md-3" ]
|
||||||
|
[ div [ class "panel panel-default" ]
|
||||||
|
[ div [ class "panel-heading" ]
|
||||||
|
[ icon "bell"
|
||||||
|
, text "Notifications"
|
||||||
|
]
|
||||||
|
, ul [ class "list-group" ] <|
|
||||||
|
List.map notificationEntryView notifications
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
draftView : Model -> Html Msg
|
draftView : Model -> Html Msg
|
||||||
draftView { draft } =
|
draftView { draft } =
|
||||||
let
|
let
|
||||||
@ -237,108 +301,136 @@ draftView { draft } =
|
|||||||
option [ value visibility ]
|
option [ value visibility ]
|
||||||
[ text <| visibility ++ ": " ++ description ]
|
[ text <| visibility ++ ": " ++ description ]
|
||||||
in
|
in
|
||||||
div [ class "col-md-3" ]
|
div [ class "panel panel-default" ]
|
||||||
[ div [ class "panel panel-default" ]
|
[ div [ class "panel-heading" ] [ icon "envelope", text "Post a message" ]
|
||||||
[ div [ class "panel-heading" ] [ icon "envelope", text "Post a message" ]
|
, div [ class "panel-body" ]
|
||||||
, div [ class "panel-body" ]
|
[ Html.form [ class "form", onSubmit SubmitDraft ]
|
||||||
[ Html.form [ class "form", onSubmit SubmitDraft ]
|
[ div [ class "form-group checkbox" ]
|
||||||
[ div [ class "form-group checkbox" ]
|
[ label []
|
||||||
[ label []
|
[ input
|
||||||
[ input
|
[ type_ "checkbox"
|
||||||
[ type_ "checkbox"
|
, onCheck <| DraftEvent << ToggleSpoiler
|
||||||
, onCheck <| DraftEvent << ToggleSpoiler
|
, checked hasSpoiler
|
||||||
, checked hasSpoiler
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
, text " Add a spoiler"
|
|
||||||
]
|
]
|
||||||
|
[]
|
||||||
|
, text " Add a spoiler"
|
||||||
]
|
]
|
||||||
, if hasSpoiler then
|
]
|
||||||
div [ class "form-group" ]
|
, if hasSpoiler then
|
||||||
[ label [ for "spoiler" ] [ text "Visible part" ]
|
div [ class "form-group" ]
|
||||||
, textarea
|
[ label [ for "spoiler" ] [ text "Visible part" ]
|
||||||
[ id "spoiler"
|
|
||||||
, class "form-control"
|
|
||||||
, rows 5
|
|
||||||
, placeholder "This text will always be visible."
|
|
||||||
, onInput <| DraftEvent << UpdateSpoiler
|
|
||||||
, required True
|
|
||||||
, value <| Maybe.withDefault "" draft.spoiler_text
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
else
|
|
||||||
text ""
|
|
||||||
, div [ class "form-group" ]
|
|
||||||
[ label [ for "status" ]
|
|
||||||
[ text <|
|
|
||||||
if hasSpoiler then
|
|
||||||
"Hidden part"
|
|
||||||
else
|
|
||||||
"Status"
|
|
||||||
]
|
|
||||||
, textarea
|
, textarea
|
||||||
[ id "status"
|
[ id "spoiler"
|
||||||
, class "form-control"
|
, class "form-control"
|
||||||
, rows 8
|
, rows 5
|
||||||
, placeholder <|
|
, placeholder "This text will always be visible."
|
||||||
if hasSpoiler then
|
, onInput <| DraftEvent << UpdateSpoiler
|
||||||
"This text will be hidden by default, as you have enabled a spoiler."
|
|
||||||
else
|
|
||||||
"Once upon a time..."
|
|
||||||
, onInput <| DraftEvent << UpdateStatus
|
|
||||||
, required True
|
, required True
|
||||||
, value draft.status
|
, value <| Maybe.withDefault "" draft.spoiler_text
|
||||||
]
|
]
|
||||||
[]
|
[]
|
||||||
]
|
]
|
||||||
, div [ class "form-group" ]
|
else
|
||||||
[ label [ for "visibility" ] [ text "Visibility" ]
|
text ""
|
||||||
, select
|
, div [ class "form-group" ]
|
||||||
[ id "visibility"
|
[ label [ for "status" ]
|
||||||
, class "form-control"
|
[ text <|
|
||||||
, onInput <| DraftEvent << UpdateVisibility
|
if hasSpoiler then
|
||||||
, required True
|
"Hidden part"
|
||||||
, value draft.visibility
|
else
|
||||||
|
"Status"
|
||||||
|
]
|
||||||
|
, textarea
|
||||||
|
[ id "status"
|
||||||
|
, class "form-control"
|
||||||
|
, rows 8
|
||||||
|
, placeholder <|
|
||||||
|
if hasSpoiler then
|
||||||
|
"This text will be hidden by default, as you have enabled a spoiler."
|
||||||
|
else
|
||||||
|
"Once upon a time..."
|
||||||
|
, onInput <| DraftEvent << UpdateStatus
|
||||||
|
, required True
|
||||||
|
, value draft.status
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
]
|
||||||
|
, div [ class "form-group" ]
|
||||||
|
[ label [ for "visibility" ] [ text "Visibility" ]
|
||||||
|
, select
|
||||||
|
[ id "visibility"
|
||||||
|
, class "form-control"
|
||||||
|
, onInput <| DraftEvent << UpdateVisibility
|
||||||
|
, required True
|
||||||
|
, value draft.visibility
|
||||||
|
]
|
||||||
|
<|
|
||||||
|
List.map visibilityOptionView <|
|
||||||
|
Dict.toList visibilities
|
||||||
|
]
|
||||||
|
, div [ class "form-group checkbox" ]
|
||||||
|
[ label []
|
||||||
|
[ input
|
||||||
|
[ type_ "checkbox"
|
||||||
|
, onCheck <| DraftEvent << UpdateSensitive
|
||||||
|
, checked draft.sensitive
|
||||||
]
|
]
|
||||||
<|
|
[]
|
||||||
List.map visibilityOptionView <|
|
, text " This post is NSFW"
|
||||||
Dict.toList visibilities
|
|
||||||
]
|
|
||||||
, div [ class "form-group checkbox" ]
|
|
||||||
[ label []
|
|
||||||
[ input
|
|
||||||
[ type_ "checkbox"
|
|
||||||
, onCheck <| DraftEvent << UpdateSensitive
|
|
||||||
, checked draft.sensitive
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
, text " This post is NSFW"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, p [ class "text-right" ]
|
|
||||||
[ button [ class "btn btn-primary" ]
|
|
||||||
[ text "Toot!" ]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
, p [ class "text-right" ]
|
||||||
|
[ button [ class "btn btn-primary" ]
|
||||||
|
[ text "Toot!" ]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
optionsView : Model -> Html Msg
|
||||||
|
optionsView model =
|
||||||
|
div [ class "panel panel-default" ]
|
||||||
|
[ div [ class "panel-heading" ] [ icon "cog", text "options" ]
|
||||||
|
, div [ class "panel-body" ]
|
||||||
|
[ div [ class "checkbox" ]
|
||||||
|
[ label []
|
||||||
|
[ input
|
||||||
|
[ type_ "checkbox"
|
||||||
|
, onCheck UseGlobalTimeline
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
, text " 4th column renders the global timeline"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
sidebarView : Model -> Html Msg
|
||||||
|
sidebarView model =
|
||||||
|
div [ class "col-md-3" ]
|
||||||
|
[ draftView model
|
||||||
|
, optionsView model
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
homepageView : Model -> Html Msg
|
homepageView : Model -> Html Msg
|
||||||
homepageView model =
|
homepageView model =
|
||||||
div [ class "row" ]
|
div [ class "row" ]
|
||||||
[ draftView model
|
[ sidebarView model
|
||||||
, timelineView model.userTimeline "Home timeline" "home"
|
, timelineView model.userTimeline "Home timeline" "home"
|
||||||
, timelineView model.localTimeline "Local timeline" "th-large"
|
, notificationListView model.notifications
|
||||||
, case model.account of
|
, case model.account of
|
||||||
Just account ->
|
Just account ->
|
||||||
-- Todo: Load the user timeline
|
-- Todo: Load the user timeline
|
||||||
accountTimelineView account [] "Account" "user"
|
accountTimelineView account [] "Account" "user"
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
timelineView model.publicTimeline "Public timeline" "globe"
|
if model.useGlobalTimeline then
|
||||||
|
timelineView model.publicTimeline "Global timeline" "globe"
|
||||||
|
else
|
||||||
|
timelineView model.localTimeline "Local timeline" "th-large"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ import Html exposing (..)
|
|||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (onWithOptions)
|
import Html.Events exposing (onWithOptions)
|
||||||
import HtmlParser
|
import HtmlParser
|
||||||
import HtmlParser.Util
|
|
||||||
import Json.Decode as Decode
|
import Json.Decode as Decode
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import Model exposing (Msg(OnLoadUserAccount))
|
import Model exposing (Msg(OnLoadUserAccount))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user