CSS styles in elm-reactor and pretty check boxes
2017-08-16 (Last updated on 2018-09-01)
Elm-reactor is a great tool to get started in elm.
It supports a time-traveling debugger, downloads the necessary packages and is generally nice to work with.
A problem though is that for styling you usually need to write inline-styles. This is sometimes fine, but if I want to concentrate on the elm code and add separate styles I usually pick another tool like create-elm-app.
But it is possible to add a style tag to the main view function and the css styles are applied to the document.
After the initial exploration, I can move the styles to a dedicated file.
This uses checkboxes I adapted from a really nice example by @valerypatorius on codepen.
The trick
Render a style node and specify the content as a multiline string.
module Main exposing (main)
import Html exposing (Html, div, h1, text)
import Html.Attributes exposing (class)
main =
div []
[ Html.node "style" [] [ text css ]
, h1 [] [ text "Example" ]
]
css =
"""/* injected css */
html {
background-color: #f0c;
color: #fff!important;
}
"""
The code was updated for Elm 0.19, the code for Elm 0.18 is still available here.
module Main exposing (main)
{-| Inspired by an animation I saw once and a talk by Evan Czaplicki
<https://www.youtube.com/watch?v=2ihTgEYiKpI&list=PLdgiYNRAzk2wtuTK3zaEvE1upwZY9uxBC&index=5>
Styling of the checkbox is adapted from <https://codepen.io/valerypatorius/pen/oXGMGL>
-}
import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
type Model
= None
| One String
| Two String String
main : Program () Model Msg
main =
Browser.sandbox
{ init = One "Quality"
, view = view
, update = update
}
view : Model -> Html Msg
view model =
div [ class "container" ]
[ addCssStyles
, h1 [] [ text "Choose wisely" ]
, ul []
[ viewCheckbox "Quality" model
, viewCheckbox "Fast" model
, viewCheckbox "Cheap" model
]
]
viewCheckbox : String -> Model -> Html Msg
viewCheckbox which model =
let
id_ =
"switch-" ++ which
in
li []
[ input
[ type_ "checkbox"
, id id_
, checked <| isChecked which model
, onClick <| Toggle which
]
[]
, label [ for id_ ] [ text which ]
]
isChecked : String -> Model -> Bool
isChecked which model =
case model of
None ->
False
One a ->
a == which
Two a b ->
which == a || which == b
type Msg
= Toggle String
update : Msg -> Model -> Model
update msg model =
case msg of
Toggle str ->
case model of
None ->
One str
One a ->
if a /= str then
Two a str
else
None
Two a b ->
if str == a then
One b
else if str == b then
One a
else
Two b str
addCssStyles : Html msg
addCssStyles =
Html.node "style" [] [ text css ]
css : String
css =
"""/* injected css */
html {
height: 100%;
margin: 0;
}
body {
height: 100%;
margin: 0;
display: flex;
align-items: center;
}
.container {
font-family: sans-serif;
font-size: 8vmin;
height: 8em;
margin: auto;
}
h1 { font-size: 120%;
margin-bottom: .5em;
}
ul {
list-style-type: none;
padding-left: 1em;
margin-top: 0;
}
li {
margin: .5em 0;
}
input[type="checkbox"] { display: none; }
input[type="checkbox"] + label {
display: block;
position: relative;
padding-left: 1.6em;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
input[type="checkbox"] + label:before {
content: '';
display: block;
width: 1em;
height: 1em;
border: .1em solid #000;
position: absolute;
left: 0;
top: 0;
opacity: .6;
-webkit-transition: all .12s, border-color .08s;
transition: all .12s, border-color .08s;
}
input[type="checkbox"]:checked + label:before {
width: .5em;
top: -.3em;
left: .4em;
border-radius: 0;
border-width: .15em;
opacity: 1;
border-color: #199045;
border-top-color: transparent;
border-left-color: transparent;
-webkit-transform: rotate(35deg);
transform: rotate(35deg);
border-radius: .1em;
}
"""