summaryrefslogtreecommitdiff
path: root/elm3/Lib/Html.elm
blob: b811f9fdc0150b8cfbe22e8a56b54e87cb933e23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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" ] []