module Lib.Html exposing (..) import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) import List import Lib.Api as Api import Lib.Gen exposing (urlStatic) import Lib.Ffi as Ffi import Json.Encode as JE import String exposing (padLeft) -- Quick short-hand way of creating a form that can be disabled. -- Usage: -- form Submit_msg (state == Disabled) [contents] form_ : msg -> Bool -> List (Html msg) -> Html msg form_ sub dis cont = Html.form [ onSubmit sub ] [ fieldset [disabled dis] cont ] -- Submit button with loading indicator and error message display -- TODO: This use of pull-right is ugly. submitButton : String -> Api.State -> Bool -> Bool -> Html m submitButton val state valid load = div [] [ input [ type_ "submit", class "btn pull-right", tabindex 10, value val, disabled (state == Api.Loading || not valid || load) ] [] , case state of Api.Error r -> div [class "invalid-feedback pull-right" ] [ text <| Api.showResponse r ] _ -> if valid then text "" else div [class "invalid-feedback pull-right" ] [ text "The form contains errors, please fix these before submitting. " ] , if state == Api.Loading || load then div [ class "spinner spinner--md pull-right" ] [] else text "" ] inputSelect : List (Attribute m) -> String -> List (String, String) -> Html m inputSelect attrs sel lst = let opt (id, name) = option [ value id, selected (id == sel) ] [ text name ] in select ([class "form-control", tabindex 10] ++ attrs) <| List.map opt lst inputText : String -> String -> (String -> m) -> List (Attribute m) -> Html m inputText nam val onch attrs = input ( [ type_ "text" , class "form-control" , tabindex 10 , value val , onInput onch ] ++ attrs ++ (if nam == "" then [] else [ id nam, name nam ]) ) [] inputTextArea : String -> String -> (String -> m) -> List (Attribute m) -> Html m inputTextArea nam val onch attrs = textarea ( [ class "form-control" , tabindex 10 , onInput onch ] ++ attrs ++ (if nam == "" then [] else [ id nam, name nam ]) ) [ text val ] inputCheck : String -> Bool -> (Bool -> m) -> Html m inputCheck nam val onch = input ( [ type_ "checkbox" , tabindex 10 , onCheck onch , checked val ] ++ (if nam == "" then [] else [ id nam, name nam ]) ) [] inputRadio : String -> Bool -> (Bool -> m) -> Html m inputRadio nam val onch = input ( [ type_ "radio" , tabindex 10 , onCheck onch , checked val ] ++ (if nam == "" then [] else [ name nam ]) ) [] -- Generate a card with: Id, Title, [Header stuff], [Sections] -- TODO: Also abstract "small-card"s (many of the User/ things) into this card : String -> String -> List (Html m) -> List (Html m) -> Html m card i t h sections = div ([class "card"] ++ if i == "" then [] else [id i]) <| [ div [class "card__header"] ([ div [class "card__title"] [text t] ] ++ h) ] ++ List.map (\c -> div [class "card__section"] [c]) sections -- Card without header card_ : List (Html m) -> Html m card_ c = div [class "card"] [ div [class "card__body"] c ] -- Generate a 2-column row for use within a card section: Title, Subtitle, Content cardRow : String -> Maybe String -> List (Html m) -> Html m cardRow t s c = div [class "row"] [ div [class "col-md col-md--1 card__form-section-left"] [ div [class "card__form-section-title"] [text t] , case s of Just n -> div [class "card__form-section-subtitle"] [text n] Nothing -> text "" ] , div [class "col-md col-md--2"] c ] formGroup : List (Html m) -> List (Html m) formGroup c = [div [class "form-group"] c] formGroups : List (List (Html m)) -> List (Html m) formGroups groups = List.map (\c -> div [class "form-group"] c) groups removeButton : m -> Html m removeButton cmd = button [type_ "button", class "btn", tabindex 10, onClick cmd] [ span [class "d-none d-sm-inline"] [text "x"] , span [class "d-sm-none"] [text "Remove"] ] editList : List (Html m) -> List (Html m) editList ct = if List.isEmpty ct then [] else [ div [class "editable-list editable-list--sm"] ct ] editListRow : String -> List (Html m) -> Html m editListRow cl ct = div [class ("editable-list__row row row--compact " ++ cl)] ct editListField : Int -> String -> List (Html m) -> Html m editListField sm cl ct = div [ classList <| [ ("editable-list__field", True) , ("col-sm", True ) , ("col-sm--auto", sm == 0) , ("col-sm--1", sm == 1) , ("col-sm--2", sm == 2) , ("col-sm--3", sm == 3) , (cl, cl /= "") ] ] ct -- Special arguments, -- id == -1 -> spinner -- id == 0 -> camera-alt.svg dbImg : String -> Int -> List (Attribute m) -> Maybe { id: String, width: Int, height: Int } -> Html m dbImg dir id attrs full = if id == 0 then div (class "vn-image-placeholder img--rounded" :: attrs) [ div [ class "vn-image-placeholder__icon" ] [ img [ src (urlStatic ++ "/v3/camera-alt.svg"), class "svg-icon" ] [] ] ] else if id == -1 then div (class "vn-image-placeholder img--rounded" :: attrs) [ div [ class "vn-image-placeholder__icon" ] [ div [ class "spinner spinner--md" ] [] ] ] else let url d = urlStatic ++ "/" ++ d ++ "/" ++ (padLeft 2 '0' (String.fromInt (modBy 100 id))) ++ "/" ++ (String.fromInt id) ++ ".jpg" i = img [src (url dir), class "img--fit img--rounded" ] [] fdir = if dir == "st" then "sf" else dir in case full of Nothing -> i Just f -> a [ href (url fdir) , Ffi.openLightbox , attribute "data-lightbox-id" f.id , attribute "data-lightbox-nfo" <| JE.encode 0 <| JE.object [("width", JE.int f.width), ("height", JE.int f.height)] ] [ i ] iconLanguage : String -> Html msg iconLanguage lang = span [ class "lang-badge" ] [ text lang ] iconPlatform : String -> Html msg iconPlatform plat = img [ class "svg-icon", src (urlStatic ++ "/v3/windows.svg"), title "Windows" ] []