Going through Elm guide and doing exercises.
Converter.elm
-- https://ellie-app.com/3P9hcDhdsc5a1 | |
module Main exposing (Model, Msg(..), init, main, update, view, viewConverter) | |
import Browser | |
import Html exposing (Attribute, Html, div, input, span, text) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (onInput) | |
-- MAIN | |
main = | |
Browser.sandbox { init = init, update = update, view = view } | |
-- MODEL | |
type alias Model = | |
{ celsius : String | |
, fahrenheit : String | |
, inches : String | |
} | |
init : Model | |
init = | |
{ celsius = "", fahrenheit = "", inches = "" } | |
-- UPDATE | |
type Msg | |
= ChangeCelsius String | |
| ChangeFahrenheit String | |
| ChangeInches String | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
ChangeCelsius newInput -> | |
{ model | celsius = newInput } | |
ChangeFahrenheit newInput -> | |
{ model | fahrenheit = newInput } | |
ChangeInches newInput -> | |
{ model | inches = newInput } | |
-- VIEW | |
view : Model -> Html Msg | |
view model = | |
div [ style "display" "flex", style "flex-direction" "column" ] | |
[ viewCelsius model | |
, viewFahrenheit model | |
, viewInches model | |
] | |
viewCelsius : Model -> Html Msg | |
viewCelsius model = | |
case String.toFloat model.celsius of | |
Just celsius -> | |
viewConverter model.celsius ChangeCelsius "°C" "°F" "blue" (celsiusToFahrenheit celsius) | |
Nothing -> | |
viewConverter model.celsius ChangeCelsius "°C" "°F" "red" "???" | |
viewFahrenheit : Model -> Html Msg | |
viewFahrenheit model = | |
case String.toFloat model.fahrenheit of | |
Just fahrenheit -> | |
viewConverter model.fahrenheit ChangeFahrenheit "°F" "°C" "blue" (fahrenheitToCelsius fahrenheit) | |
Nothing -> | |
viewConverter model.fahrenheit ChangeFahrenheit "°F" "°C" "red" "???" | |
viewInches : Model -> Html Msg | |
viewInches model = | |
case String.toFloat model.inches of | |
Just inches -> | |
viewConverter model.inches ChangeInches "in" "m" "blue" (inchesToMeters inches) | |
Nothing -> | |
viewConverter model.inches ChangeInches "in" "m" "red" "???" | |
celsiusToFahrenheit : Float -> String | |
celsiusToFahrenheit celsius = | |
String.fromFloat (celsius * 1.8 + 32) | |
fahrenheitToCelsius : Float -> String | |
fahrenheitToCelsius fahrenheit = | |
String.fromFloat (fahrenheit / 1.8 - 32) | |
inchesToMeters : Float -> String | |
inchesToMeters inches = | |
String.fromFloat (inches * 0.0254) | |
viewConverter : String -> (String -> Msg) -> String -> String -> String -> String -> Html Msg | |
viewConverter userInput convert convertFrom convertTo color equivalentTemp = | |
span [] | |
[ input [ value userInput, onInput convert, style "width" "40px", style "border" ("1px solid " ++ color) ] [] | |
, text (convertFrom ++ " = ") | |
, span [ style "color" color ] [ text equivalentTemp ] | |
, text convertTo | |
] |
module Main exposing (Model, Msg(..), init, main, update, view, viewInput, viewValidation) | |
import Browser | |
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.Events exposing (onInput) | |
main = | |
Browser.sandbox { init = init, update = update, view = view } | |
type alias Model = | |
{ name : String | |
, password : String | |
, passwordAgain : String | |
} | |
init : Model | |
init = | |
Model "" "" "" | |
type Msg | |
= Name String | |
| Password String | |
| PasswordAgain String | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
Name name -> | |
{ model | name = name } | |
Password password -> | |
{ model | password = password } | |
PasswordAgain password -> | |
{ model | passwordAgain = password } | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ viewInput "text" "Name" model.name Name | |
, viewInput "password" "Password" model.password Password | |
, viewInput "password" "Re-enter Password" model.passwordAgain PasswordAgain | |
, viewValidation model | |
] | |
viewInput : String -> String -> String -> (String -> msg) -> Html msg | |
viewInput t p v toMsg = | |
input [ type_ t, placeholder p, value v, onInput toMsg ] [] | |
type ValidationResult | |
= ShortPassword | |
| NoDigitsInPassword | |
| NoUppercaseCharacters | |
| NoLowercaseCharacters | |
| PasswordsNotMatch | |
| Valid | |
viewValidation : Model -> Html msg | |
viewValidation model = | |
case validate model of | |
ShortPassword -> | |
viewValidationError "Password should be longer than 8 characters" | |
NoDigitsInPassword -> | |
viewValidationError "Password should contain one numeric character" | |
NoUppercaseCharacters -> | |
viewValidationError "Password should contain one upper case character" | |
NoLowercaseCharacters -> | |
viewValidationError "Password should contain one lower case character" | |
PasswordsNotMatch -> | |
viewValidationError "Passwords do not match!" | |
Valid -> | |
div [ style "color" "green" ] [ text "OK" ] | |
viewValidationError : String -> Html msg | |
viewValidationError errorMessage = | |
div [ style "color" "red" ] [ text errorMessage ] | |
validate : Model -> ValidationResult | |
validate model = | |
if String.length model.password < 8 then | |
ShortPassword | |
else if not (String.any Char.isDigit model.password) then | |
NoDigitsInPassword | |
else if not (String.any Char.isUpper model.password) then | |
NoUppercaseCharacters | |
else if not (String.any Char.isLower model.password) then | |
NoLowercaseCharacters | |
else if model.password /= model.passwordAgain then | |
PasswordsNotMatch | |
else | |
Valid |
import Browser | |
import Html exposing (Html, button, div, text, input) | |
import Html.Events exposing (onClick, onInput) | |
import Html.Attributes exposing (..) | |
main = | |
Browser.sandbox { init = init, update = update, view = view } | |
type alias Model = | |
{ counter : Int | |
} | |
init : Model | |
init = | |
Model 10 | |
type Msg = Reset | Change String | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
Reset -> | |
init | |
Change newCounter -> | |
{ model | counter = Maybe.withDefault model.counter (String.toInt newCounter) } | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ div [] [ text (String.fromInt model.counter) ] | |
, input [ type_ "range", placeholder "Type counter", value (String.fromInt model.counter), onInput Change ] [] | |
, viewButton "Reset" Reset | |
, viewSnowman model | |
] | |
viewButton : String -> msg -> Html msg | |
viewButton t toMsg = | |
button [ onClick toMsg ] [ text t ] | |
viewSnowman : Model -> Html msg | |
viewSnowman model = | |
div | |
[ style "display" "flex" | |
, style "flex-direction" "column" | |
, style "align-items" "center" | |
, style "width" "50%" | |
] | |
[ viewShape model 1 | |
, viewShape model 2 | |
, viewShape model 3 | |
] | |
viewShape : Model -> Int -> Html msg | |
viewShape model position = | |
div | |
[ style "width" ((String.fromInt (model.counter * position)) ++ "px") | |
, style "height" ((String.fromInt (model.counter * position)) ++ "px") | |
, style "background-color" (getColor model.counter) | |
, style "border-radius" "50%" | |
, style "transition" "background-color 300ms linear" | |
] | |
[] | |
getColor : Int -> String | |
getColor counter = | |
if counter <= 50 then | |
"green" | |
else | |
"red" |