Fix #45: Add a media viewer. (#46)

This commit is contained in:
Nicolas Perriault 2017-04-24 21:21:43 +02:00 committed by GitHub
parent 7e2896dcf0
commit b5fa55f49d
4 changed files with 173 additions and 6 deletions

View File

@ -8,7 +8,7 @@
"debug": "node_modules/.bin/elm-live src/Main.elm --dir=public/ --output=public/app.js --debug",
"deploy": "npm run build && node_modules/.bin/gh-pages --dist build/",
"start": "node_modules/.bin/elm-live src/Main.elm --dir=public/ --output=public/app.js",
"test": "node_modules/.bin/elm-make src/Main.elm --warn --output /tmp/tooty.html"
"test": "node_modules/.bin/elm-make src/Main.elm --warn --output app.js"
},
"repository": {
"type": "git",

View File

@ -130,6 +130,12 @@ body {
.attachment-entry {
margin-top: 5px;
transition: 0.3s;
opacity: .9;
}
.attachment-entry:hover {
opacity: 1;
}
.attachment-entry input {
@ -274,3 +280,78 @@ body {
text-align:center;
padding: 15px;
}
/* Viewer */
.viewer {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.9);
}
/* Modal Content (Image) */
.viewer-content {
display: block;
margin: auto;
max-width: 80vw;
max-height: 90vh;
animation-name: zoom;
animation-duration: 0.1s;
}
@keyframes zoom {
from { transform: scale(.9) }
to { transform: scale(1) }
}
.viewer > .close {
position: absolute;
top: 15px;
right: 35px;
color: #eee;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
text-shadow: initial;
opacity: 1;
}
.viewer > .close:hover,
.viewer > .close:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
.prev, .next {
font-size: 72px;
opacity: .5;
transition: opacity .5s;
text-decoration: none;
margin: 0 10px;
}
.prev:hover,
.next:hover {
opacity: 1;
}
.prev:active, .prev:focus, .prev:hover,
.next:active, .next:focus, .next:hover {
text-decoration: none;
}
/* 100% image width on smaller screens */
@media only screen and (max-width: 700px) {
.viewer-content {
width: 100%;
}
}

View File

@ -25,6 +25,11 @@ type DraftMsg
| ToggleSpoiler Bool
type ViewerMsg
= CloseViewer
| OpenViewer (List Mastodon.Attachment) Mastodon.Attachment
type
Msg
{-
@ -56,6 +61,7 @@ type
| Unreblog Int
| Unreblogged (Result Mastodon.Error Mastodon.Status)
| UserTimeline (Result Mastodon.Error (List Mastodon.Status))
| ViewerEvent ViewerMsg
type alias Draft =
@ -67,6 +73,12 @@ type alias Draft =
}
type alias Viewer =
{ attachments : List Mastodon.Attachment
, attachment : Mastodon.Attachment
}
type alias Model =
{ server : String
, registration : Maybe Mastodon.AppRegistration
@ -80,6 +92,7 @@ type alias Model =
, errors : List String
, location : Navigation.Location
, useGlobalTimeline : Bool
, viewer : Maybe Viewer
}
@ -121,6 +134,7 @@ init flags location =
, errors = []
, location = location
, useGlobalTimeline = False
, viewer = Nothing
}
! [ initCommands flags.registration flags.client authCode ]
@ -308,6 +322,16 @@ updateDraft draftMsg draft =
{ draft | in_reply_to = Nothing } ! []
updateViewer : ViewerMsg -> Maybe Viewer -> ( Maybe Viewer, Cmd Msg )
updateViewer viewerMsg viewer =
case viewerMsg of
CloseViewer ->
Nothing ! []
OpenViewer attachments attachment ->
(Just <| Viewer attachments attachment) ! []
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
@ -427,6 +451,13 @@ update msg model =
in
{ model | draft = draft } ! [ commands ]
ViewerEvent viewerMsg ->
let
( viewer, commands ) =
updateViewer viewerMsg model.viewer
in
{ model | viewer = viewer } ! [ commands ]
SubmitDraft ->
model
! case model.client of

View File

@ -4,8 +4,9 @@ import Dict
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import List.Extra exposing (elemIndex, getAt)
import Mastodon
import Model exposing (Model, Draft, DraftMsg(..), Msg(..))
import Model exposing (Model, Draft, DraftMsg(..), Viewer, ViewerMsg(..), Msg(..))
import ViewHelper
@ -64,8 +65,8 @@ accountAvatarLink account =
[ img [ class "avatar", src account.avatar ] [] ]
attachmentPreview : Maybe Bool -> Mastodon.Attachment -> Html Msg
attachmentPreview sensitive ({ url, preview_url } as attachment) =
attachmentPreview : Maybe Bool -> List Mastodon.Attachment -> Mastodon.Attachment -> Html Msg
attachmentPreview sensitive attachments ({ url, preview_url } as attachment) =
let
nsfw =
case sensitive of
@ -82,7 +83,8 @@ attachmentPreview sensitive ({ url, preview_url } as attachment) =
a
[ class "attachment-image"
, href url
, target "_blank"
, ViewHelper.onClickWithPreventAndStop <|
ViewerEvent (OpenViewer attachments attachment)
, style
[ ( "background"
, "url(" ++ preview_url ++ ") center center / cover no-repeat"
@ -113,7 +115,8 @@ attachmentListView { media_attachments, sensitive } =
text ""
attachments ->
ul [ class "attachments" ] <| List.map (attachmentPreview sensitive) attachments
ul [ class "attachments" ] <|
List.map (attachmentPreview sensitive attachments) attachments
statusContentView : Mastodon.Status -> Html Msg
@ -595,6 +598,52 @@ authView model =
]
viewerView : Viewer -> Html Msg
viewerView { attachments, attachment } =
let
index =
Maybe.withDefault -1 <| elemIndex attachment attachments
( prev, next ) =
( getAt (index - 1) attachments, getAt (index + 1) attachments )
navLink label className target =
case target of
Nothing ->
text ""
Just target ->
a
[ href ""
, class className
, ViewHelper.onClickWithPreventAndStop <|
ViewerEvent (OpenViewer attachments target)
]
[ text label ]
in
div
[ class "viewer"
, tabindex -1
, ViewHelper.onClickWithPreventAndStop <| ViewerEvent CloseViewer
]
[ span [ class "close" ] [ text "×" ]
, navLink "" "prev" prev
, case attachment.type_ of
"image" ->
img [ class "viewer-content", src attachment.url ] []
_ ->
video
[ class "viewer-content"
, preload "auto"
, autoplay True
, loop True
]
[ source [ src attachment.url ] [] ]
, navLink "" "next" next
]
view : Model -> Html Msg
view model =
div [ class "container-fluid" ]
@ -605,4 +654,10 @@ view model =
Nothing ->
authView model
, case model.viewer of
Just viewer ->
viewerView viewer
Nothing ->
text ""
]