all repos

onasty @ 234f764

a one-time notes service

onasty/web/src/Components/Form.elm(view raw)

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
module Components.Form exposing (ButtonStyle(..), CanBeClicked, InputStyle(..), button, input, submitButton)

import Html as H exposing (Html)
import Html.Attributes as A
import Html.Events as E



-- INPUT


type InputStyle
    = Simple
    | Complex
        { prefix : String
        , helpText : String
        }


input :
    { id : String
    , field : field
    , type_ : String
    , value : String
    , label : String
    , placeholder : String
    , required : Bool
    , onInput : String -> msg
    , style : InputStyle
    , error : Maybe String
    }
    -> Html msg
input opts =
    let
        style =
            case opts.style of
                Simple ->
                    { prefix = H.text "", help = H.text "" }

                Complex complex ->
                    { prefix = H.span [ A.class "text-gray-500 text-md whitespace-nowrap" ] [ H.text complex.prefix ]
                    , help = H.p [ A.class "text-xs text-gray-500 mt-1" ] [ H.text complex.helpText ]
                    }

        error =
            case opts.error of
                Nothing ->
                    { element = H.text "", inputAdditionalClasses = "border-gray-300 focus:ring-black " }

                Just err ->
                    { element = H.p [ A.class "text-red-600 text-xs mt-1" ] [ H.text err ]
                    , inputAdditionalClasses = " border-red-400 focus:ring-red-500"
                    }
    in
    H.div [ A.class "space-y-2" ]
        [ H.label
            [ A.for opts.id
            , A.class "block text-sm font-medium text-gray-700"
            ]
            [ H.text opts.label ]
        , H.div [ A.class "flex items-center" ]
            [ style.prefix
            , H.input
                [ A.class ("w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:border-transparent transition-colors" ++ error.inputAdditionalClasses)
                , A.type_ opts.type_
                , A.value opts.value
                , A.id opts.id
                , A.placeholder opts.placeholder
                , A.required opts.required
                , E.onInput opts.onInput
                ]
                []
            ]
        , error.element
        , style.help
        ]



-- BUTTON


type alias CanBeClicked =
    Bool


type ButtonStyle
    = Primary CanBeClicked
    | Secondary CanBeClicked
    | SecondaryDisabled CanBeClicked
    | SecondaryDanger


button : { text : String, disabled : Bool, onClick : msg, style : ButtonStyle } -> Html msg
button opts =
    H.button
        [ A.type_ "button"
        , E.onClick opts.onClick
        , A.class (buttonStyleToClass opts.style "")
        , A.disabled opts.disabled
        ]
        [ H.text opts.text ]


submitButton : { text : String, disabled : Bool, class : String, style : ButtonStyle } -> Html msg
submitButton opts =
    H.button
        [ A.type_ "submit"
        , A.class (buttonStyleToClass opts.style opts.class)
        , A.disabled opts.disabled
        ]
        [ H.text opts.text ]


buttonStyleToClass : ButtonStyle -> String -> String
buttonStyleToClass style appendClasses =
    case style of
        Primary canBeClicked ->
            getButtonClasses canBeClicked
                appendClasses
                "px-6 py-2 bg-gray-300 text-gray-500 rounded-md cursor-not-allowed transition-colors"
                "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"

        SecondaryDanger ->
            "text-gray-600 hover:text-red-600 transition-colors"

        Secondary canBeClicked ->
            getButtonClasses canBeClicked
                appendClasses
                "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"
                "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"

        SecondaryDisabled canBeClicked ->
            getButtonClasses canBeClicked
                appendClasses
                "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"
                "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"


getButtonClasses : Bool -> String -> String -> String -> String
getButtonClasses cond extend whenTrue whenFalse =
    let
        cls =
            if String.isEmpty extend then
                ""

            else
                " " ++ extend
    in
    if cond then
        whenTrue ++ cls

    else
        whenFalse ++ cls