parent
7e2896dcf0
commit
b5fa55f49d
@ -8,7 +8,7 @@
|
|||||||
"debug": "node_modules/.bin/elm-live src/Main.elm --dir=public/ --output=public/app.js --debug",
|
"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/",
|
"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",
|
"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": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -130,6 +130,12 @@ body {
|
|||||||
|
|
||||||
.attachment-entry {
|
.attachment-entry {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
transition: 0.3s;
|
||||||
|
opacity: .9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-entry:hover {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachment-entry input {
|
.attachment-entry input {
|
||||||
@ -274,3 +280,78 @@ body {
|
|||||||
text-align:center;
|
text-align:center;
|
||||||
padding: 15px;
|
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%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,6 +25,11 @@ type DraftMsg
|
|||||||
| ToggleSpoiler Bool
|
| ToggleSpoiler Bool
|
||||||
|
|
||||||
|
|
||||||
|
type ViewerMsg
|
||||||
|
= CloseViewer
|
||||||
|
| OpenViewer (List Mastodon.Attachment) Mastodon.Attachment
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Msg
|
Msg
|
||||||
{-
|
{-
|
||||||
@ -56,6 +61,7 @@ type
|
|||||||
| Unreblog Int
|
| Unreblog Int
|
||||||
| Unreblogged (Result Mastodon.Error Mastodon.Status)
|
| Unreblogged (Result Mastodon.Error Mastodon.Status)
|
||||||
| UserTimeline (Result Mastodon.Error (List Mastodon.Status))
|
| UserTimeline (Result Mastodon.Error (List Mastodon.Status))
|
||||||
|
| ViewerEvent ViewerMsg
|
||||||
|
|
||||||
|
|
||||||
type alias Draft =
|
type alias Draft =
|
||||||
@ -67,6 +73,12 @@ type alias Draft =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Viewer =
|
||||||
|
{ attachments : List Mastodon.Attachment
|
||||||
|
, attachment : Mastodon.Attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ server : String
|
{ server : String
|
||||||
, registration : Maybe Mastodon.AppRegistration
|
, registration : Maybe Mastodon.AppRegistration
|
||||||
@ -80,6 +92,7 @@ type alias Model =
|
|||||||
, errors : List String
|
, errors : List String
|
||||||
, location : Navigation.Location
|
, location : Navigation.Location
|
||||||
, useGlobalTimeline : Bool
|
, useGlobalTimeline : Bool
|
||||||
|
, viewer : Maybe Viewer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -121,6 +134,7 @@ init flags location =
|
|||||||
, errors = []
|
, errors = []
|
||||||
, location = location
|
, location = location
|
||||||
, useGlobalTimeline = False
|
, useGlobalTimeline = False
|
||||||
|
, viewer = Nothing
|
||||||
}
|
}
|
||||||
! [ initCommands flags.registration flags.client authCode ]
|
! [ initCommands flags.registration flags.client authCode ]
|
||||||
|
|
||||||
@ -308,6 +322,16 @@ updateDraft draftMsg draft =
|
|||||||
{ draft | in_reply_to = Nothing } ! []
|
{ 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 -> ( Model, Cmd Msg )
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
case msg of
|
||||||
@ -427,6 +451,13 @@ update msg model =
|
|||||||
in
|
in
|
||||||
{ model | draft = draft } ! [ commands ]
|
{ model | draft = draft } ! [ commands ]
|
||||||
|
|
||||||
|
ViewerEvent viewerMsg ->
|
||||||
|
let
|
||||||
|
( viewer, commands ) =
|
||||||
|
updateViewer viewerMsg model.viewer
|
||||||
|
in
|
||||||
|
{ model | viewer = viewer } ! [ commands ]
|
||||||
|
|
||||||
SubmitDraft ->
|
SubmitDraft ->
|
||||||
model
|
model
|
||||||
! case model.client of
|
! case model.client of
|
||||||
|
65
src/View.elm
65
src/View.elm
@ -4,8 +4,9 @@ import Dict
|
|||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (..)
|
||||||
|
import List.Extra exposing (elemIndex, getAt)
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import Model exposing (Model, Draft, DraftMsg(..), Msg(..))
|
import Model exposing (Model, Draft, DraftMsg(..), Viewer, ViewerMsg(..), Msg(..))
|
||||||
import ViewHelper
|
import ViewHelper
|
||||||
|
|
||||||
|
|
||||||
@ -64,8 +65,8 @@ accountAvatarLink account =
|
|||||||
[ img [ class "avatar", src account.avatar ] [] ]
|
[ img [ class "avatar", src account.avatar ] [] ]
|
||||||
|
|
||||||
|
|
||||||
attachmentPreview : Maybe Bool -> Mastodon.Attachment -> Html Msg
|
attachmentPreview : Maybe Bool -> List Mastodon.Attachment -> Mastodon.Attachment -> Html Msg
|
||||||
attachmentPreview sensitive ({ url, preview_url } as attachment) =
|
attachmentPreview sensitive attachments ({ url, preview_url } as attachment) =
|
||||||
let
|
let
|
||||||
nsfw =
|
nsfw =
|
||||||
case sensitive of
|
case sensitive of
|
||||||
@ -82,7 +83,8 @@ attachmentPreview sensitive ({ url, preview_url } as attachment) =
|
|||||||
a
|
a
|
||||||
[ class "attachment-image"
|
[ class "attachment-image"
|
||||||
, href url
|
, href url
|
||||||
, target "_blank"
|
, ViewHelper.onClickWithPreventAndStop <|
|
||||||
|
ViewerEvent (OpenViewer attachments attachment)
|
||||||
, style
|
, style
|
||||||
[ ( "background"
|
[ ( "background"
|
||||||
, "url(" ++ preview_url ++ ") center center / cover no-repeat"
|
, "url(" ++ preview_url ++ ") center center / cover no-repeat"
|
||||||
@ -113,7 +115,8 @@ attachmentListView { media_attachments, sensitive } =
|
|||||||
text ""
|
text ""
|
||||||
|
|
||||||
attachments ->
|
attachments ->
|
||||||
ul [ class "attachments" ] <| List.map (attachmentPreview sensitive) attachments
|
ul [ class "attachments" ] <|
|
||||||
|
List.map (attachmentPreview sensitive attachments) attachments
|
||||||
|
|
||||||
|
|
||||||
statusContentView : Mastodon.Status -> Html Msg
|
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 -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
div [ class "container-fluid" ]
|
div [ class "container-fluid" ]
|
||||||
@ -605,4 +654,10 @@ view model =
|
|||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
authView model
|
authView model
|
||||||
|
, case model.viewer of
|
||||||
|
Just viewer ->
|
||||||
|
viewerView viewer
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
text ""
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user