tooty/src/View.elm

327 lines
12 KiB
Elm
Raw Normal View History

2017-04-20 07:46:18 +00:00
module View exposing (view)
2017-04-21 12:03:39 +00:00
import Dict
2017-04-20 07:46:18 +00:00
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Mastodon
2017-04-20 18:30:19 +00:00
import Model exposing (Model, DraftMsg(..), Msg(..))
import ViewHelper
2017-04-20 07:46:18 +00:00
2017-04-21 12:03:39 +00:00
visibilities : Dict.Dict String String
visibilities =
Dict.fromList
[ ( "public", "post to public timelines" )
, ( "unlisted", "do not show in public timelines" )
, ( "private", "post to followers only" )
, ( "direct", "post to mentioned users only" )
]
2017-04-20 07:46:18 +00:00
errorView : String -> Html Msg
errorView error =
div [ class "alert alert-danger" ] [ text error ]
errorsListView : Model -> Html Msg
errorsListView model =
case model.errors of
[] ->
text ""
errors ->
div [] <| List.map errorView model.errors
icon : String -> Html Msg
icon name =
i [ class <| "glyphicon glyphicon-" ++ name ] []
statusContentView : Mastodon.Status -> Html Msg
statusContentView status =
case status.spoiler_text of
"" ->
div [ class "status-text" ] <| ViewHelper.formatContent status.content status.mentions
spoiler ->
-- Note: Spoilers are dealt with using pure CSS.
let
statusId =
"spoiler" ++ (toString status.id)
in
div [ class "status-text spoiled" ]
[ div [ class "spoiler" ] [ text status.spoiler_text ]
, input [ type_ "checkbox", id statusId, class "spoiler-toggler" ] []
, label [ for statusId ] [ text "Reveal content" ]
, div [ class "spoiled-content" ] <| (ViewHelper.formatContent status.content status.mentions)
]
2017-04-20 07:46:18 +00:00
statusView : Mastodon.Status -> Html Msg
statusView ({ account, content, reblog, mentions } as status) =
let
accountLinkAttributes =
[ href account.url
-- When clicking on a status, we should not let the browser
-- redirect to a new page. That's why we're preventing the default
-- behavior here
, ViewHelper.onClickWithPreventAndStop (OnLoadUserAccount account.id)
]
in
case reblog of
Just (Mastodon.Reblog reblog) ->
div [ class "reblog" ]
[ p []
[ icon "fire"
, a (accountLinkAttributes ++ [ class "reblogger" ])
[ text <| " " ++ account.username ]
, text " boosted"
]
, statusView reblog
2017-04-20 07:46:18 +00:00
]
Nothing ->
div [ class "status" ]
[ img [ class "avatar", src account.avatar ] []
, div [ class "username" ]
[ a accountLinkAttributes
[ text account.display_name
, span [ class "acct" ] [ text <| " @" ++ account.username ]
]
]
, statusContentView status
2017-04-20 13:43:15 +00:00
]
accountTimelineView : Mastodon.Account -> List Mastodon.Status -> String -> String -> Html Msg
accountTimelineView account statuses label iconName =
div [ class "col-md-3" ]
[ div [ class "panel panel-default" ]
[ div [ class "panel-heading" ]
[ icon iconName
, text label
2017-04-20 07:46:18 +00:00
]
, div [ class "account-detail", style [ ( "background-image", "url('" ++ account.header ++ "')" ) ] ]
[ div [ class "opacity-layer" ]
[ img [ src account.avatar ] []
, span [ class "account-display-name" ] [ text account.display_name ]
, span [ class "account-username" ] [ text ("@" ++ account.username) ]
, span [ class "account-note" ] (ViewHelper.formatContent account.note [])
]
]
, div [ class "row account-infos" ]
[ div [ class "col-md-4" ]
[ text "Statuses"
, br [] []
, text <| toString account.statuses_count
]
, div [ class "col-md-4" ]
[ text "Following"
, br [] []
, text <| toString account.following_count
]
, div [ class "col-md-4" ]
[ text "Followers"
, br [] []
, text <| toString account.followers_count
]
]
, ul [ class "list-group" ] <|
List.map
(\s ->
li [ class "list-group-item status" ]
[ statusView s ]
)
statuses
]
]
2017-04-20 07:46:18 +00:00
timelineView : List Mastodon.Status -> String -> String -> Html Msg
timelineView statuses label iconName =
2017-04-21 11:04:28 +00:00
div [ class "col-md-3" ]
2017-04-20 07:46:18 +00:00
[ div [ class "panel panel-default" ]
[ div [ class "panel-heading" ]
[ icon iconName
, text label
]
2017-04-20 07:46:18 +00:00
, ul [ class "list-group" ] <|
List.map
(\s ->
li [ class "list-group-item status" ]
[ statusView s ]
)
statuses
]
]
2017-04-20 18:30:19 +00:00
draftView : Model -> Html Msg
draftView { draft } =
let
hasSpoiler =
case draft.spoiler_text of
Nothing ->
False
Just _ ->
True
2017-04-21 12:03:39 +00:00
visibilityOptionView ( visibility, description ) =
option [ value visibility ]
[ text <| visibility ++ ": " ++ description ]
2017-04-20 18:30:19 +00:00
in
div [ class "col-md-3" ]
[ div [ class "panel panel-default" ]
[ div [ class "panel-heading" ] [ icon "envelope", text "Post a message" ]
2017-04-20 18:30:19 +00:00
, div [ class "panel-body" ]
[ Html.form [ class "form", onSubmit SubmitDraft ]
[ div [ class "form-group checkbox" ]
[ label []
[ input
[ type_ "checkbox"
, onCheck <| DraftEvent << ToggleSpoiler
, checked hasSpoiler
]
[]
, text " Add a spoiler"
]
]
, if hasSpoiler then
div [ class "form-group" ]
[ label [ for "spoiler" ] [ text "Visible part" ]
, textarea
[ 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
[ id "status"
, class "form-control"
, rows 8
, placeholder <|
if hasSpoiler then
2017-04-21 12:03:39 +00:00
"This text will be hidden by default, as you have enabled a spoiler."
2017-04-20 18:30:19 +00:00
else
"Once upon a time..."
, onInput <| DraftEvent << UpdateStatus
, required True
, value draft.status
]
[]
]
2017-04-21 12:03:39 +00:00
, 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
]
2017-04-20 18:30:19 +00:00
, div [ class "form-group checkbox" ]
[ label []
[ input
[ type_ "checkbox"
, onCheck <| DraftEvent << UpdateSensitive
, checked draft.sensitive
]
[]
2017-04-21 12:03:39 +00:00
, text " This post is NSFW"
2017-04-20 18:30:19 +00:00
]
]
, p [ class "text-right" ]
[ button [ class "btn btn-primary" ]
[ text "Toot!" ]
]
]
]
]
]
2017-04-20 07:46:18 +00:00
homepageView : Model -> Html Msg
homepageView model =
div [ class "row" ]
2017-04-20 18:30:19 +00:00
[ draftView model
, timelineView model.userTimeline "Home timeline" "home"
, timelineView model.localTimeline "Local timeline" "th-large"
, case model.account of
Just account ->
-- Todo: Load the user timeline
accountTimelineView account [] "Account" "user"
Nothing ->
timelineView model.publicTimeline "Public timeline" "globe"
2017-04-20 07:46:18 +00:00
]
authView : Model -> Html Msg
authView model =
div [ class "col-md-4 col-md-offset-4" ]
[ div [ class "panel panel-default" ]
[ div [ class "panel-heading" ] [ text "Authenticate" ]
, div [ class "panel-body" ]
[ Html.form [ class "form", onSubmit Register ]
[ div [ class "form-group" ]
[ label [ for "server" ] [ text "Mastodon server root URL" ]
, input
[ type_ "url"
, class "form-control"
, id "server"
, required True
, placeholder "https://mastodon.social"
, value model.server
, pattern "https://.+"
, onInput ServerChange
]
[]
, p [ class "help-block" ]
2017-04-21 12:03:39 +00:00
[ text <|
"You'll be redirected to that server to authenticate yourself. "
++ "We don't have access to your password."
]
2017-04-20 07:46:18 +00:00
]
, button [ class "btn btn-primary", type_ "submit" ]
[ text "Sign into Tooty" ]
]
]
]
]
view : Model -> Html Msg
view model =
div [ class "container-fluid" ]
[ h1 [] [ text "tooty" ]
, errorsListView model
, case model.client of
Just client ->
homepageView model
Nothing ->
authView model
]