onasty/web/src/Components/Form.elm (view raw)
Olexandr Smirnov
Olexandr Smirnov
ss2316544@gmail.com web: button component; improve code consistency (#168)..., 10 months ago
ss2316544@gmail.com web: button component; improve code consistency (#168)..., 10 months ago
| 1 | module Components.Form exposing (ButtonStyle(..), CanBeClicked, button, input, submitButton) |
| 2 | |
| 3 | import Html as H exposing (Html) |
| 4 | import Html.Attributes as A |
| 5 | import Html.Events as E |
| 6 | |
| 7 | |
| 8 | |
| 9 | -- INPUT |
| 10 | |
| 11 | |
| 12 | input : |
| 13 | -- TODO: add `error : Maybe String`, to show that field is not correct and message |
| 14 | { id : String |
| 15 | , field : field |
| 16 | , label : String |
| 17 | , type_ : String |
| 18 | , value : String |
| 19 | , placeholder : String |
| 20 | , required : Bool |
| 21 | , helpText : Maybe String |
| 22 | , prefix : Maybe String |
| 23 | , onInput : String -> msg |
| 24 | } |
| 25 | -> Html msg |
| 26 | input opts = |
| 27 | H.div [ A.class "space-y-2" ] |
| 28 | [ H.label |
| 29 | [ A.for opts.id |
| 30 | , A.class "block text-sm font-medium text-gray-700" |
| 31 | ] |
| 32 | [ H.text opts.label ] |
| 33 | , H.div |
| 34 | [ A.class |
| 35 | (if opts.prefix /= Nothing then |
| 36 | "flex items-center" |
| 37 | |
| 38 | else |
| 39 | "" |
| 40 | ) |
| 41 | ] |
| 42 | [ case opts.prefix of |
| 43 | Just prefix -> |
| 44 | H.span [ A.class "text-gray-500 text-md mr-2 whitespace-nowrap" ] [ H.text prefix ] |
| 45 | |
| 46 | Nothing -> |
| 47 | H.text "" |
| 48 | , H.input |
| 49 | [ A.class "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-black focus:border-transparent" |
| 50 | , A.type_ opts.type_ |
| 51 | , A.value opts.value |
| 52 | , A.id opts.id |
| 53 | , A.placeholder opts.placeholder |
| 54 | , A.required opts.required |
| 55 | , E.onInput opts.onInput |
| 56 | ] |
| 57 | [] |
| 58 | ] |
| 59 | , case opts.helpText of |
| 60 | Just help -> |
| 61 | H.p [ A.class "text-xs text-gray-500 mt-1" ] [ H.text help ] |
| 62 | |
| 63 | Nothing -> |
| 64 | H.text "" |
| 65 | ] |
| 66 | |
| 67 | |
| 68 | |
| 69 | -- BUTTON |
| 70 | |
| 71 | |
| 72 | type alias CanBeClicked = |
| 73 | Bool |
| 74 | |
| 75 | |
| 76 | type ButtonStyle |
| 77 | = Primary CanBeClicked |
| 78 | | Secondary CanBeClicked |
| 79 | | SecondaryDisabled CanBeClicked |
| 80 | | SecondaryDanger |
| 81 | |
| 82 | |
| 83 | button : { text : String, disabled : Bool, onClick : msg, style : ButtonStyle } -> Html msg |
| 84 | button opts = |
| 85 | H.button |
| 86 | [ A.type_ "button" |
| 87 | , E.onClick opts.onClick |
| 88 | , A.class (buttonStyleToClass opts.style "") |
| 89 | , A.disabled opts.disabled |
| 90 | ] |
| 91 | [ H.text opts.text ] |
| 92 | |
| 93 | |
| 94 | submitButton : { text : String, disabled : Bool, class : String, style : ButtonStyle } -> Html msg |
| 95 | submitButton opts = |
| 96 | H.button |
| 97 | [ A.type_ "submit" |
| 98 | , A.class (buttonStyleToClass opts.style opts.class) |
| 99 | , A.disabled opts.disabled |
| 100 | ] |
| 101 | [ H.text opts.text ] |
| 102 | |
| 103 | |
| 104 | buttonStyleToClass : ButtonStyle -> String -> String |
| 105 | buttonStyleToClass style appendClasses = |
| 106 | case style of |
| 107 | Primary canBeClicked -> |
| 108 | getButtonClasses canBeClicked |
| 109 | appendClasses |
| 110 | "px-6 py-2 bg-gray-300 text-gray-500 rounded-md cursor-not-allowed transition-colors" |
| 111 | "px-6 py-2 bg-black text-white rounded-md hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 transition-colors" |
| 112 | |
| 113 | SecondaryDanger -> |
| 114 | "text-gray-600 hover:text-red-600 transition-colors" |
| 115 | |
| 116 | Secondary canBeClicked -> |
| 117 | getButtonClasses canBeClicked |
| 118 | appendClasses |
| 119 | "px-4 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 transition-colors bg-green-100 border-green-300 text-green-700" |
| 120 | "px-4 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 transition-colors border-gray-300 text-gray-700 hover:bg-gray-50" |
| 121 | |
| 122 | SecondaryDisabled canBeClicked -> |
| 123 | getButtonClasses canBeClicked |
| 124 | appendClasses |
| 125 | "w-full px-4 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 transition-colors mt-3 border border-gray-300 text-gray-400 cursor-not-allowed" |
| 126 | "w-full px-4 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 transition-colors mt-3 border border-gray-300 text-gray-700 hover:bg-gray-50" |
| 127 | |
| 128 | |
| 129 | getButtonClasses : Bool -> String -> String -> String -> String |
| 130 | getButtonClasses cond extend whenTrue whenFalse = |
| 131 | let |
| 132 | cls = |
| 133 | if String.isEmpty extend then |
| 134 | "" |
| 135 | |
| 136 | else |
| 137 | " " ++ extend |
| 138 | in |
| 139 | if cond then |
| 140 | whenTrue ++ cls |
| 141 | |
| 142 | else |
| 143 | whenFalse ++ cls |