2022-01-03 21:04:42 +03:00
|
|
|
module Page.TailwindForm exposing (Data, Model, Msg, page)
|
|
|
|
|
|
|
|
import Css
|
|
|
|
import Css.Global
|
|
|
|
import DataSource exposing (DataSource)
|
2022-01-04 08:17:07 +03:00
|
|
|
import Date exposing (Date)
|
2022-01-03 21:04:42 +03:00
|
|
|
import Dict exposing (Dict)
|
|
|
|
import Form exposing (Form)
|
|
|
|
import Head
|
|
|
|
import Head.Seo as Seo
|
2022-01-05 03:20:44 +03:00
|
|
|
import Html as CoreHtml
|
2022-01-08 02:08:43 +03:00
|
|
|
import Html.Events
|
2022-01-03 21:04:42 +03:00
|
|
|
import Html.Styled as Html exposing (Html)
|
|
|
|
import Html.Styled.Attributes as Attr exposing (css)
|
2022-01-08 02:08:43 +03:00
|
|
|
import Http
|
2022-01-03 21:04:42 +03:00
|
|
|
import Icon
|
|
|
|
import Page exposing (Page, PageWithState, StaticPayload)
|
|
|
|
import PageServerResponse exposing (PageServerResponse)
|
|
|
|
import Pages.PageUrl exposing (PageUrl)
|
|
|
|
import Pages.Url
|
|
|
|
import Server.Request as Request exposing (Request)
|
|
|
|
import Shared
|
|
|
|
import Tailwind.Breakpoints as Bp
|
|
|
|
import Tailwind.Utilities as Tw
|
2022-01-04 08:17:07 +03:00
|
|
|
import Time
|
2022-01-03 21:04:42 +03:00
|
|
|
import View exposing (View)
|
|
|
|
|
|
|
|
|
|
|
|
type alias Model =
|
2022-01-06 02:12:58 +03:00
|
|
|
{ form : Form.Model
|
|
|
|
}
|
2022-01-03 21:04:42 +03:00
|
|
|
|
|
|
|
|
2022-01-06 02:12:58 +03:00
|
|
|
type Msg
|
|
|
|
= FormMsg Form.Msg
|
2022-01-08 02:08:43 +03:00
|
|
|
| GotFormResponse (Result Http.Error Form.Model)
|
2022-01-03 21:04:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
type alias RouteParams =
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
type alias User =
|
|
|
|
{ first : String
|
|
|
|
, last : String
|
|
|
|
, username : String
|
|
|
|
, email : String
|
2022-01-04 08:17:07 +03:00
|
|
|
, birthDay : Date
|
2022-01-05 22:40:35 +03:00
|
|
|
, rating : Int
|
2022-01-05 02:28:16 +03:00
|
|
|
, notificationPreferences : NotificationPreferences
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type alias NotificationPreferences =
|
|
|
|
{ comments : Bool
|
|
|
|
, candidates : Bool
|
|
|
|
, offers : Bool
|
2022-01-05 04:55:37 +03:00
|
|
|
, pushNotificationsSetting : Maybe PushNotificationsSetting
|
2022-01-03 21:04:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
defaultUser : User
|
|
|
|
defaultUser =
|
|
|
|
{ first = "Jane"
|
|
|
|
, last = "Doe"
|
|
|
|
, username = "janedoe"
|
|
|
|
, email = "janedoe@example.com"
|
2022-01-04 08:17:07 +03:00
|
|
|
, birthDay = Date.fromCalendarDate 1969 Time.Jul 20
|
2022-01-05 22:40:35 +03:00
|
|
|
, rating = 5
|
2022-01-05 02:28:16 +03:00
|
|
|
, notificationPreferences =
|
|
|
|
{ comments = False
|
|
|
|
, candidates = False
|
|
|
|
, offers = False
|
2022-01-05 04:55:37 +03:00
|
|
|
, pushNotificationsSetting = Nothing
|
2022-01-05 02:28:16 +03:00
|
|
|
}
|
2022-01-03 21:04:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
styleAttrs attrs =
|
|
|
|
List.map Attr.fromUnstyled attrs
|
|
|
|
|
|
|
|
|
|
|
|
usernameInput { toInput, toLabel, errors } =
|
|
|
|
Html.div []
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Bp.sm
|
|
|
|
[ Tw.grid
|
|
|
|
, Tw.grid_cols_3
|
|
|
|
, Tw.gap_4
|
|
|
|
, Tw.items_start
|
|
|
|
, Tw.border_t
|
|
|
|
, Tw.border_gray_200
|
|
|
|
, Tw.pt_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.label
|
|
|
|
(styleAttrs toInput
|
|
|
|
++ [ Attr.for "username"
|
|
|
|
, css
|
|
|
|
[ Tw.block
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_700
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_px
|
|
|
|
, Tw.pt_2
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[ Html.text "Username" ]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_1
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_0
|
|
|
|
, Tw.col_span_2
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.max_w_lg
|
|
|
|
, Tw.flex
|
|
|
|
, Tw.rounded_md
|
|
|
|
, Tw.shadow_sm
|
|
|
|
, Tw.relative
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.span
|
|
|
|
[ css
|
|
|
|
[ Tw.inline_flex
|
|
|
|
, Tw.items_center
|
|
|
|
, Tw.px_3
|
|
|
|
, Tw.rounded_l_md
|
|
|
|
, Tw.border
|
|
|
|
, Tw.border_r_0
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Tw.bg_gray_50
|
|
|
|
, Tw.text_gray_500
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.text_sm
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "workcation.com/" ]
|
|
|
|
, Html.input
|
|
|
|
(styleAttrs toInput
|
|
|
|
++ [ Attr.type_ "text"
|
|
|
|
, Attr.name "username"
|
|
|
|
, Attr.id "username"
|
|
|
|
, Attr.attribute "autocomplete" "username"
|
|
|
|
, css
|
|
|
|
[ Tw.flex_1
|
|
|
|
, Tw.block
|
|
|
|
, Tw.w_full
|
|
|
|
, Tw.min_w_0
|
|
|
|
, Tw.rounded_none
|
|
|
|
, Tw.rounded_r_md
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.ring_indigo_500
|
|
|
|
, Tw.border_indigo_500
|
|
|
|
]
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.text_sm
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.absolute
|
|
|
|
, Tw.inset_y_0
|
|
|
|
, Tw.right_0
|
|
|
|
, Tw.pr_3
|
|
|
|
, Tw.flex
|
|
|
|
, Tw.items_center
|
|
|
|
, Tw.pointer_events_none
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ if errors |> List.isEmpty then
|
|
|
|
Html.text ""
|
|
|
|
|
|
|
|
else
|
|
|
|
Icon.error
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
, Html.p
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_2
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.text_red_600
|
2022-01-03 21:04:42 +03:00
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
[ errors |> String.join "\n" |> Html.text ]
|
2022-01-03 21:04:42 +03:00
|
|
|
]
|
|
|
|
|
|
|
|
|
2022-01-06 22:01:53 +03:00
|
|
|
validateCapitalized : String -> Result String String
|
|
|
|
validateCapitalized string =
|
|
|
|
if string |> String.toList |> List.head |> Maybe.withDefault 'a' |> Char.isUpper then
|
|
|
|
Ok string
|
|
|
|
|
|
|
|
else
|
|
|
|
Err "Needs to be capitalized"
|
|
|
|
|
|
|
|
|
2022-01-06 01:09:37 +03:00
|
|
|
form : User -> Form User (Html Form.Msg)
|
2022-01-03 21:04:42 +03:00
|
|
|
form user =
|
|
|
|
Form.succeed User
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 22:23:39 +03:00
|
|
|
(Form.text
|
2022-01-03 21:04:42 +03:00
|
|
|
"first"
|
2022-01-03 22:14:39 +03:00
|
|
|
(textInput "First name")
|
2022-01-03 21:04:42 +03:00
|
|
|
|> Form.withInitialValue user.first
|
2022-01-06 22:01:53 +03:00
|
|
|
|> Form.withClientValidation validateCapitalized
|
2022-01-05 22:23:08 +03:00
|
|
|
|> Form.required
|
2022-01-03 21:04:42 +03:00
|
|
|
)
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 22:23:39 +03:00
|
|
|
(Form.text
|
2022-01-03 21:04:42 +03:00
|
|
|
"last"
|
2022-01-03 22:14:39 +03:00
|
|
|
(textInput "Last name")
|
2022-01-03 21:04:42 +03:00
|
|
|
|> Form.withInitialValue user.last
|
2022-01-06 22:01:53 +03:00
|
|
|
|> Form.withClientValidation validateCapitalized
|
2022-01-05 22:23:08 +03:00
|
|
|
|> Form.required
|
2022-01-03 21:04:42 +03:00
|
|
|
)
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 22:23:39 +03:00
|
|
|
(Form.text "username" usernameInput
|
2022-01-03 21:04:42 +03:00
|
|
|
|> Form.withInitialValue user.username
|
|
|
|
|> Form.withServerValidation
|
|
|
|
(\username ->
|
|
|
|
if username == "asdf" then
|
|
|
|
DataSource.succeed [ "username is taken" ]
|
|
|
|
|
|
|
|
else
|
|
|
|
DataSource.succeed []
|
|
|
|
)
|
|
|
|
)
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 22:23:39 +03:00
|
|
|
(Form.text
|
2022-01-03 21:04:42 +03:00
|
|
|
"email"
|
2022-01-03 22:14:39 +03:00
|
|
|
(textInput "Email address")
|
2022-01-03 21:04:42 +03:00
|
|
|
|> Form.withInitialValue user.email
|
2022-01-05 20:27:18 +03:00
|
|
|
|> Form.email
|
2022-01-05 22:23:08 +03:00
|
|
|
|> Form.required
|
2022-01-03 21:04:42 +03:00
|
|
|
)
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-03 21:04:42 +03:00
|
|
|
(Form.date
|
|
|
|
"dob"
|
2022-01-03 22:14:39 +03:00
|
|
|
(textInput "Date of Birth")
|
2022-01-04 08:17:07 +03:00
|
|
|
|> Form.withInitialValue (user.birthDay |> Date.toIsoString)
|
2022-01-05 22:48:33 +03:00
|
|
|
|> Form.withMinDate (Date.fromCalendarDate 1900 Time.Jan 1)
|
|
|
|
|> Form.withMaxDate (Date.fromCalendarDate 2022 Time.Jan 1)
|
2022-01-04 08:17:07 +03:00
|
|
|
|> Form.withServerValidation
|
|
|
|
(\birthDate ->
|
|
|
|
let
|
|
|
|
_ =
|
2022-01-05 03:20:44 +03:00
|
|
|
birthDate |> Date.toIsoString
|
2022-01-04 08:17:07 +03:00
|
|
|
in
|
2022-01-05 03:20:44 +03:00
|
|
|
if birthDate == Date.fromCalendarDate 1969 Time.Jul 20 then
|
2022-01-04 08:17:07 +03:00
|
|
|
DataSource.succeed [ "No way, that's when the moon landing happened!" ]
|
|
|
|
|
|
|
|
else
|
|
|
|
DataSource.succeed []
|
|
|
|
)
|
2022-01-03 21:04:42 +03:00
|
|
|
)
|
2022-01-05 22:40:35 +03:00
|
|
|
|> Form.with
|
|
|
|
(Form.requiredNumber
|
|
|
|
"rating"
|
|
|
|
(textInput "Rating")
|
|
|
|
|> Form.withMin 1
|
|
|
|
|> Form.withMax 5
|
|
|
|
|> Form.range
|
|
|
|
)
|
2022-01-04 08:17:07 +03:00
|
|
|
|> Form.wrap wrapSection
|
2022-01-05 02:28:16 +03:00
|
|
|
|> Form.appendForm (|>)
|
2022-01-05 03:20:44 +03:00
|
|
|
((Form.succeed NotificationPreferences
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 02:28:16 +03:00
|
|
|
(Form.checkbox
|
|
|
|
"comments"
|
|
|
|
--user.checkbox
|
|
|
|
False
|
|
|
|
(checkboxInput { name = "Comments", description = "Get notified when someones posts a comment on a posting." })
|
|
|
|
)
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 02:28:16 +03:00
|
|
|
(Form.checkbox
|
|
|
|
"candidates"
|
|
|
|
--user.checkbox
|
|
|
|
False
|
|
|
|
(checkboxInput { name = "Candidates", description = "Get notified when a candidate applies for a job." })
|
|
|
|
)
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 02:28:16 +03:00
|
|
|
(Form.checkbox
|
|
|
|
"offers"
|
|
|
|
--user.checkbox
|
|
|
|
False
|
|
|
|
(checkboxInput { name = "Offers", description = "Get notified when a candidate accepts or rejects an offer." })
|
|
|
|
)
|
2022-01-05 03:20:44 +03:00
|
|
|
|> Form.wrap wrapEmailSection
|
2022-01-05 04:55:37 +03:00
|
|
|
|> Form.appendForm (|>)
|
|
|
|
(Form.succeed identity
|
2022-01-05 22:21:43 +03:00
|
|
|
|> Form.with
|
2022-01-05 04:55:37 +03:00
|
|
|
(Form.radio
|
2022-01-05 05:14:29 +03:00
|
|
|
"push-notifications"
|
|
|
|
( ( "PushAll", PushAll )
|
|
|
|
, [ ( "PushEmail", PushEmail )
|
|
|
|
, ( "PushNone", PushNone )
|
|
|
|
]
|
|
|
|
)
|
2022-01-05 04:55:37 +03:00
|
|
|
radioInput
|
|
|
|
wrapPushNotificationsSection
|
|
|
|
)
|
2022-01-05 03:20:44 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|> Form.wrap wrapNotificationsSections
|
2022-01-05 02:28:16 +03:00
|
|
|
)
|
2022-01-03 21:04:42 +03:00
|
|
|
|> Form.append
|
|
|
|
(Form.submit
|
2022-01-06 22:42:49 +03:00
|
|
|
(\{ attrs, formHasErrors } ->
|
2022-01-03 22:14:39 +03:00
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.pt_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.flex
|
|
|
|
, Tw.justify_end
|
|
|
|
]
|
|
|
|
]
|
2022-01-04 01:26:04 +03:00
|
|
|
[ cancelButton
|
2022-01-06 22:42:49 +03:00
|
|
|
, saveButton formHasErrors attrs
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
]
|
2022-01-03 21:04:42 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-01-05 04:55:37 +03:00
|
|
|
type PushNotificationsSetting
|
|
|
|
= PushAll
|
|
|
|
| PushEmail
|
|
|
|
| PushNone
|
|
|
|
|
|
|
|
|
2022-01-06 22:42:49 +03:00
|
|
|
saveButton formHasErrors formAttrs =
|
2022-01-04 01:26:04 +03:00
|
|
|
Html.button
|
|
|
|
(styleAttrs formAttrs
|
|
|
|
++ [ css
|
|
|
|
[ Tw.ml_3
|
|
|
|
, Tw.inline_flex
|
|
|
|
, Tw.justify_center
|
|
|
|
, Tw.py_2
|
|
|
|
, Tw.px_4
|
|
|
|
, Tw.border
|
|
|
|
, Tw.border_transparent
|
|
|
|
, Tw.shadow_sm
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.rounded_md
|
|
|
|
, Tw.text_white
|
|
|
|
, Tw.bg_indigo_600
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.outline_none
|
|
|
|
, Tw.ring_2
|
|
|
|
, Tw.ring_offset_2
|
|
|
|
, Tw.ring_indigo_500
|
|
|
|
]
|
2022-01-06 22:42:49 +03:00
|
|
|
, if formHasErrors then
|
|
|
|
Css.batch
|
|
|
|
[ Tw.text_gray_200
|
|
|
|
, Tw.bg_indigo_500
|
|
|
|
, Tw.cursor_default
|
|
|
|
]
|
|
|
|
|
|
|
|
else
|
|
|
|
Css.hover
|
|
|
|
[ Tw.bg_indigo_700
|
|
|
|
]
|
2022-01-04 01:26:04 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[ Html.text "Save" ]
|
|
|
|
|
|
|
|
|
|
|
|
cancelButton : Html msg
|
|
|
|
cancelButton =
|
|
|
|
Html.button
|
|
|
|
[ Attr.type_ "button"
|
|
|
|
, css
|
|
|
|
[ Tw.bg_white
|
|
|
|
, Tw.py_2
|
|
|
|
, Tw.px_4
|
|
|
|
, Tw.border
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Tw.rounded_md
|
|
|
|
, Tw.shadow_sm
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_700
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.outline_none
|
|
|
|
, Tw.ring_2
|
|
|
|
, Tw.ring_offset_2
|
|
|
|
, Tw.ring_indigo_500
|
|
|
|
]
|
|
|
|
, Css.hover
|
|
|
|
[ Tw.bg_gray_50
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "Cancel" ]
|
|
|
|
|
|
|
|
|
2022-01-06 02:12:58 +03:00
|
|
|
page : PageWithState RouteParams Data Model Msg
|
2022-01-03 21:04:42 +03:00
|
|
|
page =
|
|
|
|
Page.serverRender
|
|
|
|
{ head = head
|
|
|
|
, data = data
|
|
|
|
}
|
2022-01-06 02:12:58 +03:00
|
|
|
|> Page.buildWithLocalState
|
|
|
|
{ view = view
|
|
|
|
, update = update
|
|
|
|
, init = init
|
|
|
|
, subscriptions = \_ _ _ _ _ -> Sub.none
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
update _ _ _ _ msg model =
|
|
|
|
case msg of
|
|
|
|
FormMsg formMsg ->
|
2022-01-08 02:08:43 +03:00
|
|
|
case formMsg of
|
|
|
|
Form.SubmitForm ->
|
|
|
|
( model, Form.http "/tailwind-form" (form defaultUser) model.form |> Cmd.map GotFormResponse )
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
( { model | form = model.form |> Form.update (form defaultUser) formMsg }, Cmd.none )
|
|
|
|
|
|
|
|
GotFormResponse result ->
|
|
|
|
case result of
|
|
|
|
Ok updatedFormModel ->
|
|
|
|
( { model | form = updatedFormModel }, Cmd.none )
|
|
|
|
|
|
|
|
Err _ ->
|
|
|
|
( model, Cmd.none )
|
2022-01-06 02:12:58 +03:00
|
|
|
|
|
|
|
|
2022-01-06 03:11:15 +03:00
|
|
|
init _ _ static =
|
|
|
|
( { form = static.data.errors |> Maybe.withDefault Form.init }, Cmd.none )
|
2022-01-03 21:04:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
type alias Data =
|
2022-01-06 18:57:16 +03:00
|
|
|
{ user : Maybe (Result String User)
|
2022-01-04 22:47:57 +03:00
|
|
|
, errors : Maybe (Dict String { raw : Maybe String, errors : List String })
|
2022-01-03 21:04:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
data : RouteParams -> Request (DataSource (PageServerResponse Data))
|
|
|
|
data routeParams =
|
|
|
|
Request.oneOf
|
2022-01-08 02:08:43 +03:00
|
|
|
[ Form.apiHandler (form defaultUser)
|
|
|
|
, Form.toRequest2 (form defaultUser)
|
2022-01-03 21:04:42 +03:00
|
|
|
|> Request.map
|
|
|
|
(\userOrErrors ->
|
|
|
|
userOrErrors
|
|
|
|
|> DataSource.map
|
|
|
|
(\result ->
|
|
|
|
(case result of
|
|
|
|
Ok ( user, errors ) ->
|
|
|
|
{ user = Just user
|
|
|
|
, errors = Just errors
|
|
|
|
}
|
|
|
|
|
|
|
|
Err errors ->
|
|
|
|
{ user = Nothing
|
|
|
|
, errors = Just errors
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|> PageServerResponse.RenderPage
|
|
|
|
)
|
|
|
|
)
|
|
|
|
, PageServerResponse.RenderPage
|
|
|
|
{ user = Nothing
|
|
|
|
, errors = Nothing
|
|
|
|
}
|
|
|
|
|> DataSource.succeed
|
|
|
|
|> Request.succeed
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
head :
|
|
|
|
StaticPayload Data RouteParams
|
|
|
|
-> List Head.Tag
|
|
|
|
head static =
|
|
|
|
Seo.summary
|
|
|
|
{ canonicalUrlOverride = Nothing
|
|
|
|
, siteName = "elm-pages"
|
|
|
|
, image =
|
|
|
|
{ url = Pages.Url.external "TODO"
|
|
|
|
, alt = "elm-pages logo"
|
|
|
|
, dimensions = Nothing
|
|
|
|
, mimeType = Nothing
|
|
|
|
}
|
|
|
|
, description = "TODO"
|
|
|
|
, locale = Nothing
|
|
|
|
, title = "TODO title" -- metadata.title -- TODO
|
|
|
|
}
|
|
|
|
|> Seo.website
|
|
|
|
|
|
|
|
|
2022-01-04 01:07:36 +03:00
|
|
|
wrapSection : List (Html msg) -> Html msg
|
|
|
|
wrapSection children =
|
2022-01-03 22:55:45 +03:00
|
|
|
Html.div []
|
|
|
|
[ Html.div []
|
|
|
|
[ Html.h3
|
|
|
|
[ css
|
|
|
|
[ Tw.text_lg
|
|
|
|
, Tw.leading_6
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_900
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "Profile" ]
|
|
|
|
, Html.p
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_1
|
|
|
|
, Tw.max_w_2xl
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.text_gray_500
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "This information will be displayed publicly so be careful what you share." ]
|
|
|
|
]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_6
|
|
|
|
, Tw.space_y_6
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_5
|
|
|
|
, Tw.space_y_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
2022-01-04 01:07:36 +03:00
|
|
|
children
|
2022-01-03 22:55:45 +03:00
|
|
|
]
|
|
|
|
|
|
|
|
|
2022-01-06 02:12:58 +03:00
|
|
|
formModelView formModel =
|
|
|
|
formModel
|
|
|
|
|> Debug.toString
|
|
|
|
|> Html.text
|
|
|
|
|> List.singleton
|
|
|
|
|> Html.pre []
|
|
|
|
|
|
|
|
|
2022-01-03 21:04:42 +03:00
|
|
|
view :
|
|
|
|
Maybe PageUrl
|
|
|
|
-> Shared.Model
|
2022-01-06 02:12:58 +03:00
|
|
|
-> Model
|
2022-01-03 21:04:42 +03:00
|
|
|
-> StaticPayload Data RouteParams
|
|
|
|
-> View Msg
|
2022-01-06 02:12:58 +03:00
|
|
|
view maybeUrl sharedModel model static =
|
2022-01-03 21:04:42 +03:00
|
|
|
let
|
|
|
|
user : User
|
|
|
|
user =
|
|
|
|
static.data.user
|
2022-01-06 18:57:16 +03:00
|
|
|
|> Maybe.withDefault (Ok defaultUser)
|
|
|
|
|> Result.withDefault defaultUser
|
2022-01-03 21:04:42 +03:00
|
|
|
in
|
|
|
|
{ title = "Form Example"
|
|
|
|
, body =
|
2022-01-06 03:11:15 +03:00
|
|
|
[ Html.div
|
2022-01-03 21:04:42 +03:00
|
|
|
[]
|
|
|
|
[ Css.Global.global Tw.globalStyles
|
2022-01-06 02:12:58 +03:00
|
|
|
, formModelView model.form
|
2022-01-03 21:04:42 +03:00
|
|
|
, static.data.user
|
|
|
|
|> Maybe.map
|
2022-01-06 20:48:06 +03:00
|
|
|
(\result ->
|
|
|
|
case result of
|
|
|
|
Ok user_ ->
|
|
|
|
Html.p
|
|
|
|
[ css
|
|
|
|
[ Css.backgroundColor (Css.rgb 163 251 163)
|
|
|
|
, Tw.p_4
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text <| "Successfully received user " ++ user_.first ++ " " ++ user_.last
|
|
|
|
]
|
|
|
|
|
|
|
|
Err clientValidationError ->
|
|
|
|
Html.p
|
|
|
|
[ css
|
|
|
|
[ Css.backgroundColor (Css.rgb 251 163 163)
|
|
|
|
, Tw.p_4
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text <| "Something went wrong: " ++ clientValidationError
|
2022-01-06 18:57:16 +03:00
|
|
|
]
|
2022-01-03 21:04:42 +03:00
|
|
|
)
|
2022-01-06 20:48:06 +03:00
|
|
|
|> Maybe.withDefault (Html.p [] [])
|
2022-01-03 22:14:39 +03:00
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.flex
|
|
|
|
, Tw.flex_col
|
|
|
|
, Tw.items_center
|
|
|
|
, Tw.mt_8
|
|
|
|
, Tw.border_gray_700
|
|
|
|
, Tw.rounded_lg
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
[ form user
|
2022-01-08 02:08:43 +03:00
|
|
|
|> Form.toHtml { pageReloadSubmit = True }
|
2022-01-03 22:14:39 +03:00
|
|
|
(\attrs children -> Html.form (List.map Attr.fromUnstyled attrs) children)
|
2022-01-06 03:11:15 +03:00
|
|
|
model.form
|
2022-01-06 02:12:58 +03:00
|
|
|
|> Html.map FormMsg
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
2022-01-03 21:04:42 +03:00
|
|
|
]
|
|
|
|
|> Html.toUnstyled
|
|
|
|
]
|
|
|
|
}
|
2022-01-03 21:47:12 +03:00
|
|
|
|
2022-01-03 22:14:39 +03:00
|
|
|
|
|
|
|
textInput labelText { toInput, toLabel, errors } =
|
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Bp.sm
|
|
|
|
[ Tw.grid
|
|
|
|
, Tw.grid_cols_3
|
|
|
|
, Tw.gap_4
|
|
|
|
, Tw.items_start
|
|
|
|
, Tw.border_t
|
|
|
|
, Tw.border_gray_200
|
|
|
|
, Tw.pt_5
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
[ Html.label
|
|
|
|
([ css
|
|
|
|
[ Tw.block
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_700
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_px
|
|
|
|
, Tw.pt_2
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
++ styleAttrs toLabel
|
|
|
|
)
|
|
|
|
[ Html.text labelText ]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_1
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_0
|
|
|
|
, Tw.col_span_2
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.input
|
|
|
|
(styleAttrs toInput
|
|
|
|
++ [ --Attr.attribute "autocomplete" "given-name",
|
|
|
|
css
|
|
|
|
[ Tw.max_w_lg
|
|
|
|
, Tw.block
|
|
|
|
, Tw.w_full
|
|
|
|
, Tw.shadow_sm
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Tw.rounded_md
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.ring_indigo_500
|
|
|
|
, Tw.border_indigo_500
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
|
|
|
, Bp.sm
|
2022-01-03 22:14:39 +03:00
|
|
|
[ Tw.max_w_xs
|
2022-01-03 21:47:12 +03:00
|
|
|
, Tw.text_sm
|
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
)
|
|
|
|
[]
|
|
|
|
]
|
2022-01-04 08:17:07 +03:00
|
|
|
, Html.p
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_2
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.text_red_600
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ errors |> String.join "\n" |> Html.text ]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
textInput2 =
|
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Bp.sm
|
|
|
|
[ Tw.grid
|
|
|
|
, Tw.grid_cols_3
|
|
|
|
, Tw.gap_4
|
|
|
|
, Tw.items_start
|
|
|
|
, Tw.border_t
|
|
|
|
, Tw.border_gray_200
|
|
|
|
, Tw.pt_5
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.label
|
|
|
|
[ Attr.for "first-name"
|
|
|
|
, css
|
|
|
|
[ Tw.block
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_700
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_px
|
|
|
|
, Tw.pt_2
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
[ Html.text "First name" ]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_1
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_0
|
|
|
|
, Tw.col_span_2
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.input
|
|
|
|
[ Attr.type_ "text"
|
|
|
|
, Attr.name "first-name"
|
|
|
|
, Attr.id "first-name"
|
|
|
|
, Attr.attribute "autocomplete" "given-name"
|
|
|
|
, css
|
|
|
|
[ Tw.max_w_lg
|
|
|
|
, Tw.block
|
|
|
|
, Tw.w_full
|
|
|
|
, Tw.shadow_sm
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Tw.rounded_md
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.ring_indigo_500
|
|
|
|
, Tw.border_indigo_500
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
, Bp.sm
|
|
|
|
[ Tw.max_w_xs
|
|
|
|
, Tw.text_sm
|
2022-01-03 21:47:12 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
[]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2022-01-05 02:28:16 +03:00
|
|
|
checkboxInput { name, description } { toLabel, toInput, errors } =
|
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.max_w_lg
|
|
|
|
, Tw.space_y_4
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.relative
|
|
|
|
, Tw.flex
|
|
|
|
, Tw.items_start
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.flex
|
|
|
|
, Tw.items_center
|
|
|
|
, Tw.h_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.input
|
|
|
|
(styleAttrs toInput
|
|
|
|
++ [ css
|
|
|
|
[ Tw.h_4
|
|
|
|
, Tw.w_4
|
|
|
|
, Tw.text_indigo_600
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Tw.rounded
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.ring_indigo_500
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[]
|
|
|
|
]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.ml_3
|
|
|
|
, Tw.text_sm
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.label
|
|
|
|
(styleAttrs toLabel
|
|
|
|
++ [ css
|
|
|
|
[ Tw.font_medium
|
|
|
|
, Tw.text_gray_700
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[ Html.text name ]
|
|
|
|
, Html.p
|
|
|
|
[ css
|
|
|
|
[ Tw.text_gray_500
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text description ]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
2022-01-03 22:14:39 +03:00
|
|
|
|
2022-01-05 03:20:44 +03:00
|
|
|
|
|
|
|
wrapNotificationsSections children =
|
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.divide_y
|
|
|
|
, Tw.divide_gray_200
|
|
|
|
, Tw.pt_8
|
|
|
|
, Tw.space_y_6
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.pt_10
|
|
|
|
, Tw.space_y_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div []
|
|
|
|
[ Html.h3
|
|
|
|
[ css
|
|
|
|
[ Tw.text_lg
|
|
|
|
, Tw.leading_6
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_900
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "Notifications" ]
|
|
|
|
, Html.p
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_1
|
|
|
|
, Tw.max_w_2xl
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.text_gray_500
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "We'll always let you know about important changes, but you pick what else you want to hear about." ]
|
|
|
|
]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.space_y_6
|
|
|
|
, Tw.divide_y
|
|
|
|
, Tw.divide_gray_200
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.space_y_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
children
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
wrapEmailSection children =
|
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.pt_6
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.pt_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ Attr.attribute "role" "group"
|
|
|
|
, Attr.attribute "aria-labelledby" "label-email"
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Bp.sm
|
|
|
|
[ Tw.grid
|
|
|
|
, Tw.grid_cols_3
|
|
|
|
, Tw.gap_4
|
|
|
|
, Tw.items_baseline
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div []
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.text_base
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_900
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.text_sm
|
|
|
|
, Tw.text_gray_700
|
|
|
|
]
|
|
|
|
]
|
|
|
|
, Attr.id "label-email"
|
|
|
|
]
|
|
|
|
[ Html.text "By Email" ]
|
|
|
|
]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_4
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.mt_0
|
|
|
|
, Tw.col_span_2
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.max_w_lg
|
|
|
|
, Tw.space_y_4
|
|
|
|
]
|
|
|
|
]
|
|
|
|
children
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2022-01-05 04:55:37 +03:00
|
|
|
radioInput item { toLabel, toInput, errors } =
|
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.flex
|
|
|
|
, Tw.items_center
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.input
|
|
|
|
(styleAttrs toInput
|
2022-01-05 19:08:55 +03:00
|
|
|
++ [ css
|
2022-01-05 04:55:37 +03:00
|
|
|
[ Tw.h_4
|
|
|
|
, Tw.w_4
|
|
|
|
, Tw.text_indigo_600
|
|
|
|
, Tw.border_gray_300
|
|
|
|
, Css.focus
|
|
|
|
[ Tw.ring_indigo_500
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[]
|
|
|
|
, Html.label
|
|
|
|
(styleAttrs toLabel
|
2022-01-05 19:08:55 +03:00
|
|
|
++ [ css
|
2022-01-05 04:55:37 +03:00
|
|
|
[ Tw.ml_3
|
|
|
|
, Tw.block
|
|
|
|
, Tw.text_sm
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_700
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
[ (case item of
|
|
|
|
PushAll ->
|
|
|
|
"Everything"
|
|
|
|
|
|
|
|
PushEmail ->
|
|
|
|
"Same as email"
|
|
|
|
|
|
|
|
PushNone ->
|
|
|
|
"No push notifications"
|
|
|
|
)
|
|
|
|
|> Html.text
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
wrapPushNotificationsSection children =
|
2022-01-05 03:20:44 +03:00
|
|
|
Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.pt_6
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.pt_5
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ Attr.attribute "role" "group"
|
|
|
|
, Attr.attribute "aria-labelledby" "label-notifications"
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Bp.sm
|
|
|
|
[ Tw.grid
|
|
|
|
, Tw.grid_cols_3
|
|
|
|
, Tw.gap_4
|
|
|
|
, Tw.items_baseline
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div []
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.text_base
|
|
|
|
, Tw.font_medium
|
|
|
|
, Tw.text_gray_900
|
|
|
|
, Bp.sm
|
|
|
|
[ Tw.text_sm
|
|
|
|
, Tw.text_gray_700
|
|
|
|
]
|
|
|
|
]
|
|
|
|
, Attr.id "label-notifications"
|
|
|
|
]
|
|
|
|
[ Html.text "Push Notifications" ]
|
|
|
|
]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Bp.sm
|
|
|
|
[ Tw.col_span_2
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.max_w_lg
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.p
|
|
|
|
[ css
|
|
|
|
[ Tw.text_sm
|
|
|
|
, Tw.text_gray_500
|
|
|
|
]
|
|
|
|
]
|
|
|
|
[ Html.text "These are delivered via SMS to your mobile phone." ]
|
|
|
|
, Html.div
|
|
|
|
[ css
|
|
|
|
[ Tw.mt_4
|
|
|
|
, Tw.space_y_4
|
|
|
|
]
|
|
|
|
]
|
2022-01-05 04:55:37 +03:00
|
|
|
children
|
2022-01-05 03:20:44 +03:00
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|