diff --git a/Makefile b/Makefile index e66ec59..e6d72a6 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ prod-build: upload: prod-build mc cp public/index.html $(REMOTE)/$(BUCKET)/$(BASE_PATH)/index.html mc cp public/application.js $(REMOTE)/$(BUCKET)/$(BASE_PATH)/application.js + mc cp public/application.css $(REMOTE)/$(BUCKET)/$(BASE_PATH)/application.css .PHONY: gen-videos-json gen-videos-json: diff --git a/index.html b/index.html new file mode 100644 index 0000000..0161654 --- /dev/null +++ b/index.html @@ -0,0 +1,6497 @@ + + + + + Main + + + + + +

+
+
+
+
+
\ No newline at end of file
diff --git a/public/application.css b/public/application.css
new file mode 100644
index 0000000..a66851e
--- /dev/null
+++ b/public/application.css
@@ -0,0 +1,75 @@
+html {
+  margin: 0;
+  padding: 0;
+  background-color: #161616;
+  color: #ccc;
+}
+
+video {
+  margin-left: auto;
+  margin-right: auto;
+  display: block;
+  margin-top: 1em;
+}
+
+select,
+footer,
+.downloadList {
+  margin-left: auto;
+  margin-right: auto;
+  margin-top: 1em;
+  margin-bottom: 1em;
+  display: block;
+  width: 960px;
+}
+
+footer {
+  text-align: center;
+}
+
+select {
+  background-color: #333;
+  color: #ccc;
+  border: 1px solid #555;
+  padding: 0.2em;
+}
+
+footer > a {
+  font-size: 0.8em;
+  margin-left: 1em;
+  padding: 0.1em 0.8em;
+  background-color: #60b5cc;
+  color: #333;
+  border-radius: 3px;
+  text-decoration: none;
+}
+
+footer > a:hover {
+  background-color: #cc60b6;
+  color: #ccc;
+}
+
+.downloadList:before {
+  content: "Direct Download";
+  font-weight: bold;
+  text-decoration: underline;
+  margin-bottom: 1em;
+  display: block;
+}
+
+.downloadList {
+  margin-top: 2em;
+  width: 500px;
+  margin-bottom: 2em;
+}
+
+.downloadList > a {
+  color: #60b5cc;
+  display: list-item;
+  margin-top: 0.2em;
+  text-decoration: none;
+}
+
+.downloadList > a:hover {
+  color: #ccc;
+}
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 70f95e9..ab968c2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -3,83 +3,7 @@
 
   
   Minimalistic WebPlayer
-  
+  
   
 
 
@@ -93,22 +17,19 @@
   
 
 
diff --git a/src/Dropdown.elm b/src/Dropdown.elm
new file mode 100644
index 0000000..4170040
--- /dev/null
+++ b/src/Dropdown.elm
@@ -0,0 +1,27 @@
+module Dropdown exposing (..)
+
+import Html
+import Html.Attributes
+import Html.Events as Events
+
+type alias Option =
+  { value : String
+  , display : String
+  }
+
+type alias Config msg =
+  { options : List Option
+  , default : Option
+  , selectEvent : String -> msg
+  }
+
+view : Config msg -> Html.Html msg
+view config = Html.select [ Events.onInput config.selectEvent ] <|
+                makeOption config.default
+                    :: List.map makeOption config.options
+
+makeOption : Option -> Html.Html msg
+makeOption option =
+    Html.option
+        [ Html.Attributes.value option.value ]
+        [ Html.text option.display ]
\ No newline at end of file
diff --git a/src/Flags.elm b/src/Flags.elm
new file mode 100644
index 0000000..ee2b434
--- /dev/null
+++ b/src/Flags.elm
@@ -0,0 +1,19 @@
+module Flags exposing (..)
+
+import Video
+
+type alias Flags =
+    { debug : Bool
+    , withDownload : Bool
+    , extentions : List Video.FileFormat
+    }
+
+
+debugEnabled : Flags -> Bool
+debugEnabled flags =
+    flags.debug
+
+
+withDownload : Flags -> Bool
+withDownload flags =
+    flags.withDownload
diff --git a/src/Main.elm b/src/Main.elm
index beb8fc9..c812b4b 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -3,12 +3,13 @@ module Main exposing (..)
 import Browser
 import Msg
 import Request
-import Types
+import Model exposing (Model)
 import Update
 import View
+import Flags exposing (Flags)
 
 
-main : Program Types.Flags Types.Model Msg.Msg
+main : Program Flags Model Msg.Msg
 main =
     Browser.application
         { init = init
@@ -20,15 +21,6 @@ main =
         }
 
 
-init : Types.Flags -> a -> b -> ( Types.Model, Cmd Msg.Msg )
+init : Flags -> a -> b -> ( Model, Cmd Msg.Msg )
 init flags _ _ =
-    ( initialState flags, Request.videoList )
-
-
-initialState : Types.Flags -> Types.Model
-initialState flags =
-    { selected = Nothing
-    , videos = []
-    , extensions = flags.extentions
-    , withDownload = Types.withDownload flags
-    }
+    ( Model.initialState flags, Request.videoList )
diff --git a/src/Model.elm b/src/Model.elm
new file mode 100644
index 0000000..d8e2da9
--- /dev/null
+++ b/src/Model.elm
@@ -0,0 +1,21 @@
+module Model exposing (..)
+
+import Flags exposing (Flags, withDownload)
+import Video
+
+
+type alias Model =
+    { selected : Maybe String
+    , videos : List Video.Video
+    , extensions : List Video.FileFormat
+    , withDownload : Bool
+    }
+
+
+initialState : Flags -> Model
+initialState flags =
+    { selected = Nothing
+    , videos = []
+    , extensions = flags.extentions
+    , withDownload = withDownload flags
+    }
diff --git a/src/Types.elm b/src/Types.elm
deleted file mode 100644
index 38fd71f..0000000
--- a/src/Types.elm
+++ /dev/null
@@ -1,37 +0,0 @@
-module Types exposing (..)
-
-import Video
-
-
-type alias Flags =
-    { debug : Bool
-    , extentions : List Video.FileFormat
-    }
-
-
-type alias Model =
-    { selected : Maybe String
-    , videos : List Video.Video
-    , extensions : List Video.FileFormat
-    , withDownload : Bool
-    }
-
-
-videos : Model -> List Video.Video
-videos model =
-    model.videos
-
-
-
--- These functions may seem useless, but that way it's easier to swap out
--- from flags without changing the init function.
-
-
-debugEnabled : Flags -> Bool
-debugEnabled flags =
-    flags.debug
-
-
-withDownload : Flags -> Bool
-withDownload flags =
-    flags.debug
diff --git a/src/Update.elm b/src/Update.elm
index 3b489b5..119a982 100644
--- a/src/Update.elm
+++ b/src/Update.elm
@@ -1,12 +1,14 @@
 port module Update exposing (..)
 
 import Msg
-import Types
+import Model exposing (Model)
 
 
-update : Msg.Msg -> Types.Model -> ( Types.Model, Cmd Msg.Msg )
+update : Msg.Msg -> Model -> ( Model, Cmd Msg.Msg )
 update msg model =
     case msg of
+        Msg.VideoSelected "" ->
+            ( { model | selected = Nothing }, reloadVideoSource () )
         Msg.VideoSelected path ->
             ( { model | selected = Just path }, reloadVideoSource () )
 
diff --git a/src/Video.elm b/src/Video.elm
index f8109de..4647ebb 100644
--- a/src/Video.elm
+++ b/src/Video.elm
@@ -50,3 +50,38 @@ downloadLink path format =
 filename : String -> FileFormat -> String
 filename path format =
     (Maybe.withDefault "unknown" <| List.head <| List.drop 1 <| String.split "/" path) ++ "." ++ format.extention
+
+
+type alias ListConfig msg =
+    { selected : Maybe String
+    , extensions : List FileFormat
+    , attrs : List (Html.Attribute msg)
+    }
+
+
+downloadList : ListConfig msg -> Html.Html msg
+downloadList config =
+    case config.selected of
+        Nothing ->
+            Html.div [] []
+
+        Just path ->
+            Html.div config.attrs <|
+                List.map (\e -> downloadLink path e) config.extensions
+
+
+type alias PlayerConfig msg =
+    { path : Maybe String
+    , extensions : List FileFormat
+    , attrs : List (Html.Attribute msg)
+    }
+
+
+makePlayer : PlayerConfig msg -> Html.Html msg
+makePlayer config =
+    case config.path of
+        Nothing ->
+            Html.div [] []
+
+        Just path ->
+            Html.video config.attrs (List.map (htmlSourceElem path) config.extensions)
diff --git a/src/View.elm b/src/View.elm
index b37b509..5fb633d 100644
--- a/src/View.elm
+++ b/src/View.elm
@@ -1,21 +1,21 @@
 module View exposing (..)
 
 import Browser exposing (Document)
+import Dropdown
 import Html
 import Html.Attributes
-import Html.Events as Events
 import Msg
-import Types
+import Model exposing (Model)
 import Video
 
 
-view : Types.Model -> Document Msg.Msg
+view : Model -> Document Msg.Msg
 view model =
     { title = "Minimal WebPlayer"
     , body =
-        [ makeDropDown model.videos
-        , makePlayer model
-        , downloadList model
+        [ dropdown model.videos
+        , player model
+        , download model
         , Html.footer []
             [ Html.text "Handmade with love (and Vim and elm) ;)"
             , Html.a
@@ -28,59 +28,41 @@ view model =
     }
 
 
-empty : Html.Html Msg.Msg
-empty =
-    Html.div [] []
-
-
-makeDropDown : List Video.Video -> Html.Html Msg.Msg
-makeDropDown videos =
+dropdown : List Video.Video -> Html.Html Msg.Msg
+dropdown videos =
     if List.isEmpty videos then
-        empty
+        Html.div [] [ Html.text "Please wait..." ]
 
     else
-        Html.select [ Events.onInput Msg.VideoSelected ] <|
-            makeOption { title = "Select one please ;)", path = "" }
-                :: List.map makeOption videos
-
-
-makeOption : Video.Video -> Html.Html Msg.Msg
-makeOption video =
-    Html.option
-        [ Html.Attributes.value video.path ]
-        [ Html.text video.title ]
-
-
-makePlayer : Types.Model -> Html.Html Msg.Msg
-makePlayer model =
-    case model.selected of
-        Nothing ->
-            empty
-
-        Just path ->
-            Html.video
-                [ Html.Attributes.width 960
-                , Html.Attributes.height 650
-                , Html.Attributes.controls True
-                ]
-            <|
-                List.map (Video.htmlSourceElem path) model.extensions
+        Dropdown.view
+            { options = List.map (\v -> { value = v.path, display = v.title }) videos
+            , selectEvent = Msg.VideoSelected
+            , default = { value = "", display = "Select one please ;)" }
+            }
+
+
+player : Model -> Html.Html Msg.Msg
+player model =
+    Video.makePlayer
+        { path = model.selected
+        , extensions = model.extensions
+        , attrs =
+            [ Html.Attributes.width 960
+            , Html.Attributes.height 650
+            , Html.Attributes.controls True
+            ]
+        }
 
 
-downloadList : Types.Model -> Html.Html Msg.Msg
-downloadList model =
-    let
-        selected =
+download : Model -> Html.Html Msg.Msg
+download model =
+    Video.downloadList
+        { selected =
             if not model.withDownload then
                 Nothing
 
             else
                 model.selected
-    in
-    case selected of
-        Nothing ->
-            empty
-
-        Just path ->
-            Html.div [ Html.Attributes.class "downloadList" ] <|
-                List.map (\e -> Video.downloadLink path e) model.extensions
+        , extensions = model.extensions
+        , attrs = [ Html.Attributes.class "downloadList" ]
+        }