Commits: 3

Make sliders stepped in Transformations example

Also other minor tweaks.

index 744c43a..0d66cf5 100644
--- a/src/Transformations.elm
+++ b/src/Transformations.elm
@@ -51,7 +51,11 @@ type Msg
=
=init : Flags -> ( Model, Cmd Msg )
=init () =
-    ( Array.empty
+    ( Array.fromList
+        [ Translate 0 0
+        , Rotate 0
+        , Scale 1 1
+        ]
=    , Cmd.none
=    )
=
@@ -69,9 +73,17 @@ view model =
=                , Element.spacing 20
=                ]
=                [ Element.el
-                    [ Element.width Element.fill ]
+                    [ Element.width Element.fill
+                    ]
=                    (Element.html element)
-                , transformationsUI transformations
+                , Element.row [ Element.width Element.fill ]
+                    [ Element.el
+                        [ Background.color (Element.rgb 1 0.8 0.8)
+                        , Element.padding 10
+                        , Element.width Element.fill
+                        ]
+                        (transformationsUI transformations)
+                    ]
=                ]
=
=        shape =
@@ -111,7 +123,8 @@ transformationsUI : List Transformation -> Element Msg
=transformationsUI transformations =
=    let
=        addButtons =
-            [ Input.button []
+            [ Element.text "Add transformation: "
+            , Input.button []
=                { onPress = Just (AddTransformation (Translate 0 0))
=                , label = Element.text "Translate"
=                }
@@ -176,7 +189,7 @@ transformationUI index transformation =
=                        , max = 10
=                        , value = horizontal
=                        , thumb = Input.defaultThumb
-                        , step = Nothing
+                        , step = Just 0.1
=                        }
=                    , Input.slider
=                        [ Element.behindContent sliderBackground
@@ -189,7 +202,7 @@ transformationUI index transformation =
=                        , max = 10
=                        , value = vertical
=                        , thumb = Input.defaultThumb
-                        , step = Nothing
+                        , step = Just 0.1
=                        }
=                    ]
=
@@ -205,7 +218,7 @@ transformationUI index transformation =
=                        , max = 100
=                        , value = x
=                        , thumb = Input.defaultThumb
-                        , step = Nothing
+                        , step = Just 1
=                        }
=                    , Input.slider
=                        [ Element.behindContent sliderBackground
@@ -218,7 +231,7 @@ transformationUI index transformation =
=                        , max = 100
=                        , value = y
=                        , thumb = Input.defaultThumb
-                        , step = Nothing
+                        , step = Just 1
=                        }
=                    ]
=
@@ -234,13 +247,14 @@ transformationUI index transformation =
=                        , max = 360
=                        , value = angle
=                        , thumb = Input.defaultThumb
-                        , step = Nothing
+                        , step = Just 1
=                        }
=                    ]
=    in
=    Element.column
=        [ Element.width Element.fill
-        , Background.color (Element.rgb 0.9 0.9 0.9)
+        , Border.color (Element.rgb 0.9 0.9 0.9)
+        , Border.width 3
=        , Element.padding 5
=        , Element.spacing 20
=        ]

Implement NestedTransformations example

index d17943a..6cfda8a 100644
--- a/elm.json
+++ b/elm.json
@@ -11,11 +11,13 @@
=            "elm/html": "1.0.0",
=            "elm/json": "1.0.0",
=            "elm/svg": "1.0.1",
+            "elm-community/basics-extra": "4.0.0",
=            "elm-community/list-extra": "8.1.0",
=            "elm-explorations/markdown": "1.0.0",
=            "ianmackenzie/elm-geometry": "1.2.1",
=            "ianmackenzie/elm-geometry-svg": "1.0.2",
-            "mdgriffith/elm-ui": "1.1.0"
+            "mdgriffith/elm-ui": "1.1.0",
+            "turboMaCk/any-dict": "1.0.1"
=        },
=        "indirect": {
=            "elm/time": "1.0.0",
new file mode 100644
index 0000000..30da4f4
--- /dev/null
+++ b/src/NestedTransformations.elm
@@ -0,0 +1,437 @@
+module Transformations exposing (main)
+
+import Array exposing (Array)
+import Basics.Extra exposing (..)
+import Browser
+import Browser.Events
+import CartesianPlane
+import Dict.Any as Dict exposing (AnyDict)
+import Element exposing (Element)
+import Element.Background as Background
+import Element.Border as Border
+import Element.Input as Input
+import Geometry.Svg
+import Html exposing (Html)
+import Json.Decode exposing (Decoder)
+import LineSegment2d
+import List.Extra as List
+import Point2d
+import Svg exposing (..)
+import Svg.Attributes exposing (..)
+
+
+main =
+    Browser.element
+        { init = init
+        , view = view
+        , update = update
+        , subscriptions = subscriptions
+        }
+
+
+type alias Flags =
+    ()
+
+
+type alias Model =
+    AnyDict String Group (Array Transformation)
+
+
+type Transformation
+    = Identity
+    | Scale Float Float
+    | Translate Float Float
+    | Rotate Float
+
+
+type Group
+    = Pink
+    | Green
+
+
+type Msg
+    = Msg Group GroupMsg
+
+
+type GroupMsg
+    = AddTransformation Transformation
+    | DeleteTransformation Int
+    | SetTransformation Int Transformation
+
+
+init : Flags -> ( Model, Cmd Msg )
+init () =
+    ( Dict.empty Debug.toString
+        |> Dict.insert Pink
+            (Array.fromList
+                [ Translate 0 0
+                , Rotate 0
+                , Scale 1 1
+                ]
+            )
+        |> Dict.insert Green
+            (Array.fromList
+                [ Translate 0 0
+                , Rotate 0
+                , Scale 1 1
+                ]
+            )
+    , Cmd.none
+    )
+
+
+view : Model -> Html Msg
+view model =
+    let
+        wrapper element =
+            Element.column
+                [ Element.width (Element.maximum 600 Element.fill)
+                , Element.centerX
+                , Element.spacing 20
+                ]
+                [ Element.el
+                    [ Element.width Element.fill
+                    ]
+                    (Element.html element)
+                , Element.row [ Element.width Element.fill ]
+                    (model
+                        |> Dict.toList
+                        |> List.map (uncurry controls)
+                    )
+                ]
+
+        controls : Group -> Array Transformation -> Element Msg
+        controls group transformations =
+            Element.el
+                [ Background.color (toColor group)
+                , Element.padding 10
+                , Element.width Element.fill
+                ]
+                (transformations
+                    |> Array.toList
+                    |> transformationsUI
+                    |> Element.map (Msg group)
+                )
+
+        shape =
+            Dict.foldr
+                nestTransformationsGroup
+                (g [] [])
+                model
+
+        nestTransformationsGroup : Group -> Array Transformation -> Svg Msg -> Svg Msg
+        nestTransformationsGroup group transformations item =
+            let
+                transformation =
+                    transformations |> Array.toList |> apply
+
+                color =
+                    group
+                        |> Debug.toString
+                        |> String.toLower
+            in
+            g [ transform transformation ]
+                [ line
+                    [ x1 "0"
+                    , x2 "100"
+                    , y1 "0"
+                    , y2 "0"
+                    , stroke color
+                    , strokeWidth "1"
+                    ]
+                    []
+                , circle [ cx "0", cy "0", r "2", fill color ] []
+                , item
+                ]
+    in
+    shape
+        |> List.singleton
+        |> CartesianPlane.graph 300
+        |> wrapper
+        |> Element.layout
+            [ Element.height Element.fill
+            , Element.width Element.fill
+            ]
+
+
+transformationsUI : List Transformation -> Element GroupMsg
+transformationsUI transformations =
+    let
+        addButtons =
+            [ Element.text "Add transformation: "
+            , Input.button []
+                { onPress = Just (AddTransformation (Translate 0 0))
+                , label = Element.text "Translate"
+                }
+            , Input.button []
+                { onPress = Just (AddTransformation (Scale 1 1))
+                , label = Element.text "Scale"
+                }
+            , Input.button []
+                { onPress = Just (AddTransformation (Rotate 0))
+                , label = Element.text "Rotate"
+                }
+            ]
+
+        currentTrasformations =
+            transformations
+                |> List.indexedMap transformationUI
+    in
+    Element.column
+        [ Element.width Element.fill
+        , Element.spacing 10
+        ]
+        [ Element.row
+            [ Element.width Element.fill
+            , Element.spacing 10
+            ]
+            addButtons
+        , Element.column
+            [ Element.width Element.fill
+            , Element.spacing 10
+            ]
+            currentTrasformations
+        ]
+
+
+transformationUI : Int -> Transformation -> Element GroupMsg
+transformationUI index transformation =
+    let
+        sliderBackground =
+            Element.el
+                [ Element.width Element.fill
+                , Element.height (Element.px 2)
+                , Element.centerY
+                , Background.color <| Element.rgb 0.7 0.7 0.7
+                , Border.rounded 2
+                ]
+                Element.none
+
+        controls =
+            case transformation of
+                Identity ->
+                    [ Element.text <| Debug.toString transformation ]
+
+                Scale horizontal vertical ->
+                    [ Input.slider
+                        [ Element.behindContent sliderBackground
+                        ]
+                        { onChange =
+                            \x ->
+                                SetTransformation index (Scale x vertical)
+                        , label = Input.labelLeft [] (Element.text "horizontal")
+                        , min = 0
+                        , max = 10
+                        , value = horizontal
+                        , thumb = Input.defaultThumb
+                        , step = Just 0.1
+                        }
+                    , Input.slider
+                        [ Element.behindContent sliderBackground
+                        ]
+                        { onChange =
+                            \y ->
+                                SetTransformation index (Scale horizontal y)
+                        , label = Input.labelLeft [] (Element.text "vertical")
+                        , min = 0
+                        , max = 10
+                        , value = vertical
+                        , thumb = Input.defaultThumb
+                        , step = Just 0.1
+                        }
+                    ]
+
+                Translate x y ->
+                    [ Input.slider
+                        [ Element.behindContent sliderBackground
+                        ]
+                        { onChange =
+                            \value ->
+                                SetTransformation index (Translate value y)
+                        , label = Input.labelLeft [] (Element.text "x")
+                        , min = -100
+                        , max = 100
+                        , value = x
+                        , thumb = Input.defaultThumb
+                        , step = Just 1
+                        }
+                    , Input.slider
+                        [ Element.behindContent sliderBackground
+                        ]
+                        { onChange =
+                            \value ->
+                                SetTransformation index (Translate x value)
+                        , label = Input.labelLeft [] (Element.text "y")
+                        , min = -100
+                        , max = 100
+                        , value = y
+                        , thumb = Input.defaultThumb
+                        , step = Just 1
+                        }
+                    ]
+
+                Rotate angle ->
+                    [ Input.slider
+                        [ Element.behindContent sliderBackground
+                        ]
+                        { onChange =
+                            \value ->
+                                SetTransformation index (Rotate value)
+                        , label = Input.labelLeft [] (Element.text "angle")
+                        , min = -360
+                        , max = 360
+                        , value = angle
+                        , thumb = Input.defaultThumb
+                        , step = Just 1
+                        }
+                    ]
+    in
+    Element.column
+        [ Element.width Element.fill
+        , Border.color (Element.rgb 0.9 0.9 0.9)
+        , Border.width 3
+        , Element.padding 5
+        , Element.spacing 20
+        ]
+        [ Element.row [ Element.width Element.fill ]
+            [ transformation
+                |> List.singleton
+                |> apply
+                |> Element.text
+                |> Element.el [ Element.width Element.fill ]
+            , Input.button []
+                { onPress = Just (DeleteTransformation index)
+                , label = Element.text "X"
+                }
+            ]
+        , Element.column
+            [ Element.width Element.fill
+            , Element.spacing 20
+            ]
+            controls
+        ]
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update (Msg group msg) model =
+    let
+        transformations =
+            model
+                |> Dict.get group
+                |> Maybe.withDefault Array.empty
+                |> (\current ->
+                        case msg of
+                            AddTransformation transformation ->
+                                Array.push transformation current
+
+                            DeleteTransformation index ->
+                                arrayDelete index current
+
+                            SetTransformation index transformation ->
+                                Array.set index transformation current
+                   )
+
+        arrayDelete index array =
+            let
+                end =
+                    Array.length array
+
+                front =
+                    Array.slice 0 index array
+
+                back =
+                    Array.slice (index + 1) end array
+            in
+            Array.append front back
+    in
+    ( Dict.insert group transformations model
+    , Cmd.none
+    )
+
+
+subscriptions : Model -> Sub Msg
+subscriptions model =
+    Sub.none
+
+
+apply : List Transformation -> String
+apply transformations =
+    let
+        toString : Transformation -> String
+        toString transformation =
+            case transformation of
+                Identity ->
+                    ""
+
+                Scale x y ->
+                    "scale("
+                        ++ String.fromFloat x
+                        ++ ", "
+                        ++ String.fromFloat y
+                        ++ ")"
+
+                Translate x y ->
+                    "translate("
+                        ++ String.fromFloat x
+                        ++ ", "
+                        ++ String.fromFloat y
+                        ++ ")"
+
+                Rotate angle ->
+                    "rotate("
+                        ++ String.fromFloat angle
+                        ++ ")"
+    in
+    transformations
+        |> List.map toString
+        |> String.join " "
+
+
+toColor : Group -> Element.Color
+toColor group =
+    case group of
+        Pink ->
+            Element.rgb 1 0.73 0.8
+
+        Green ->
+            Element.rgb 0.0 0.5 0.0
+
+
+grid : List (Svg.Attribute msg) -> Float -> Float -> Svg msg
+grid attributes unit size =
+    let
+        positiveValues =
+            size
+                / 2
+                |> floor
+                |> List.range 1
+                |> List.map toFloat
+                |> List.map ((*) unit)
+
+        negativeValues =
+            positiveValues
+                |> List.map negate
+
+        max =
+            unit * size / 2
+
+        min =
+            negate max
+    in
+    ((positiveValues ++ negativeValues)
+        |> List.map
+            (\value ->
+                [ ( Point2d.fromCoordinates ( value, min )
+                  , Point2d.fromCoordinates ( value, max )
+                  )
+                , ( Point2d.fromCoordinates ( min, value )
+                  , Point2d.fromCoordinates ( max, value )
+                  )
+                ]
+            )
+        |> List.concat
+        |> List.map LineSegment2d.fromEndpoints
+        |> List.map (Geometry.Svg.lineSegment2d attributes)
+    )
+        |> (::) (CartesianPlane.axes attributes (size * unit))
+        |> g []

Reimplement Main with Elm Markup, nest a simple counter program

The idea is that Main will be our website and all the example programs will be nested in it.

index 6cfda8a..d305cfa 100644
--- a/elm.json
+++ b/elm.json
@@ -13,13 +13,16 @@
=            "elm/svg": "1.0.1",
=            "elm-community/basics-extra": "4.0.0",
=            "elm-community/list-extra": "8.1.0",
+            "elm-community/result-extra": "2.2.1",
=            "elm-explorations/markdown": "1.0.0",
=            "ianmackenzie/elm-geometry": "1.2.1",
=            "ianmackenzie/elm-geometry-svg": "1.0.2",
+            "mdgriffith/elm-markup": "1.0.0",
=            "mdgriffith/elm-ui": "1.1.0",
=            "turboMaCk/any-dict": "1.0.1"
=        },
=        "indirect": {
+            "elm/parser": "1.1.0",
=            "elm/time": "1.0.0",
=            "elm/url": "1.0.0",
=            "elm/virtual-dom": "1.0.2",
new file mode 100644
index 0000000..0f0689c
--- /dev/null
+++ b/src/Counter.elm
@@ -0,0 +1,71 @@
+module Counter exposing
+    ( Model
+    , Msg
+    , init
+    , main
+    , ui
+    , update
+    )
+
+import Browser
+import Element exposing (Element)
+import Element.Border as Border
+import Element.Input as Input
+import Html exposing (Html)
+
+
+main =
+    Browser.sandbox
+        { init = init
+        , view = view
+        , update = update
+        }
+
+
+type alias Model =
+    Int
+
+
+type Msg
+    = Increment
+    | Decrement
+
+
+init =
+    0
+
+
+view : Model -> Html Msg
+view model =
+    model
+        |> ui
+        |> Element.layout []
+
+
+ui : Model -> Element Msg
+ui model =
+    Element.row
+        [ Element.padding 10
+        , Element.spacing 10
+        ]
+        [ Input.button []
+            { onPress = Just Decrement
+            , label = Element.text "-"
+            }
+        , model
+            |> String.fromInt
+            |> Element.text
+        , Input.button []
+            { onPress = Just Increment
+            , label = Element.text "+"
+            }
+        ]
+
+
+update msg model =
+    case msg of
+        Increment ->
+            model + 1
+
+        Decrement ->
+            model - 1
index f18bc73..d1066f3 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,578 +1,134 @@
=module Main exposing (main)
=
-import Browser exposing (Document)
-import Browser.Events
-import CartesianCoordinates
-import Dict
-import Element
-import Element.Font as Font
-import Element.Keyed
-import Html
-import Html.Attributes
-import Json.Decode as Decode exposing (Decoder)
-import PolarCoordinates
-import Presentation exposing (Slide, markdown)
+import Browser
+import Counter
+import Element exposing (Element)
+import Element.Border as Border
+import Element.Input as Input
+import Html exposing (Html)
+import Mark
+import Mark.Custom
+import Result.Extra as Result
=
=
=main =
-    Browser.document
+    Browser.sandbox
=        { init = init
=        , view = view
=        , update = update
-        , subscriptions = subscriptions
=        }
=
=
-type alias Flags =
-    ()
-
-
=type alias Model =
-    { currentSlide : Int
-
-    -- Nested programs
-    , cartesianCoordinates : CartesianCoordinates.Model
-    , polarCoordinates : PolarCoordinates.Model
-    }
+    { counter : Counter.Model }
=
=
=type Msg
-    = Next
-    | Previous
-      -- Nested programs
-    | CartesianCoordinatesMsg CartesianCoordinates.Msg
-    | PolarCoordinatesMsg PolarCoordinates.Msg
+    = CounterMsg Counter.Msg
=
=
-init : Flags -> ( Model, Cmd Msg )
-init flags =
-    let
-        ( cartesianCoordinatesModel, cartesianCoordinatesCmd ) =
-            CartesianCoordinates.init ()
+init =
+    { counter = Counter.init
+    }
=
-        ( polarCoordinatesModel, polarCoordinatesCmd ) =
-            PolarCoordinates.init ()
-    in
-    ( { currentSlide = 0
-      , cartesianCoordinates = cartesianCoordinatesModel
-      , polarCoordinates = polarCoordinatesModel
-      }
-    , Cmd.batch
-        [ Cmd.map CartesianCoordinatesMsg cartesianCoordinatesCmd
-        , Cmd.map PolarCoordinatesMsg polarCoordinatesCmd
-        ]
-    )
-
-
-view : Model -> Document Msg
+
+view : Model -> Html Msg
=view model =
-    { title = "FP-Art!"
-    , body =
-        [ Element.layout
-            [ Element.width Element.fill
-            , Element.height Element.fill
-            ]
-          <|
-            Element.column
-                [ Element.centerX
-                , Font.center
-                , Element.height Element.fill
-                , Element.width (Element.maximum 800 Element.fill)
-                ]
-                [ slides model
-                    |> Dict.get model.currentSlide
-                    |> Maybe.map
-                        (Element.column
-                            [ Element.width Element.fill
-                            , Element.centerY
-                            ]
-                        )
-                    |> Maybe.withDefault (Element.text "404: Slide not found")
-                ]
-        ]
-    }
+    content
+        |> Mark.parseWith options
+        |> Result.mapError Debug.toString
+        |> Result.map (\fn -> fn model)
+        |> Result.extract Element.text
+        |> Element.layout []
=
=
-update : Msg -> Model -> ( Model, Cmd Msg )
=update msg model =
=    case msg of
-        Next ->
-            ( { model
-                | currentSlide =
-                    min (Dict.size (slides model) - 1) (model.currentSlide + 1)
-              }
-            , Cmd.none
-            )
-
-        Previous ->
-            ( { model
-                | currentSlide =
-                    max 0 (model.currentSlide - 1)
-              }
-            , Cmd.none
-            )
-
-        -- Nested programs
-        CartesianCoordinatesMsg msg_ ->
-            let
-                ( model_, cmd_ ) =
-                    CartesianCoordinates.update msg_ model.cartesianCoordinates
-            in
-            ( { model | cartesianCoordinates = model_ }
-            , Cmd.map CartesianCoordinatesMsg cmd_
-            )
-
-        PolarCoordinatesMsg msg_ ->
-            let
-                ( model_, cmd_ ) =
-                    PolarCoordinates.update msg_ model.polarCoordinates
-            in
-            ( { model | polarCoordinates = model_ }
-            , Cmd.map PolarCoordinatesMsg cmd_
-            )
-
-
-subscriptions model =
-    let
-        handleKeyPress : Decoder Msg
-        handleKeyPress =
-            Decode.field "key" Decode.string
-                |> Decode.andThen
-                    (\key ->
-                        case Debug.log "Key" key of
-                            "ArrowLeft" ->
-                                Decode.succeed Previous
-
-                            "ArrowRight" ->
-                                Decode.succeed Next
-
-                            "a" ->
-                                Decode.succeed Previous
-
-                            "d" ->
-                                Decode.succeed Next
-
-                            _ ->
-                                Decode.fail "Unsupported key"
-                    )
-    in
-    Browser.Events.onKeyPress handleKeyPress
-
-
-slides model =
-    Dict.fromList <|
-        List.indexedMap Tuple.pair <|
-            [ markdown """
-                # Software Garden
-                ## A functional programming workshop
-                ### for non-programmers
-              """
-            ]
-                :: [ markdown """
-                        ## Setup
-                     """
-                   ]
-                :: [ markdown """
-                        > This setup instructions are based on an assumption that you are using a Mac.
-                        >
-                        > If you are using Linux or BSD, then you probably know how to install stuff.
-                        >
-                        > If you are using anything else, then... well, good luck.
-                        >
-                        > The rest of the instructions should work with any platform.
-
-                     """ ]
-                :: [ markdown """
-
-                        We will need:
-
-                        - a text editor (I use [Atom][])
-                        - and the [Elm programming language][]
-
-                        [Atom]: https://atom.io/
-                        [Elm programming language]: https://elm-lang.org/
-
-                     """
-                   ]
-                :: [ markdown """
-                        ### Elm Installation
-                     """
-                   ]
-                :: [ markdown """
-                        To install the Elm programming language, go to the [website][Elm] and follow the installation instructions.
-
-                        [Elm]: http://elm-lang.org/
-                     """
-                   ]
-                :: [ markdown """
-                        Some of the tools we use with Elm require Node.js.
-
-                        Go to the [Node.js website][Node.js] and install the current version (the green button on the right).
-
-                        [Node.js]: https://nodejs.org/en/
-                     """
-                   ]
-                :: [ markdown """
-                        We will need to use the terminal a little bit.
-
-                        # :fa-terminal:
-
-                        Don't be scared. It's easy :)
-
-                        <!-- slide data-background-image="images/mac-launchpad-terminal.png" data-background-size="cover" data-background-position="top center"-->
-
-                        > <p style="color: white">In Launchpad find a program called <code>terminal</code> and start it.</p>
-
-                     """
-                   ]
-                :: [ markdown """
-                        You should see a window like this
-                     """
-                   , Html.img
-                        [ Html.Attributes.alt "Mac Terminal app window"
-                        , Html.Attributes.src "../assets/mac-terminal-window.png"
-                        ]
-                        []
-                        |> Element.html
-                        |> Element.el
-                            [ Element.height Element.fill
-                            , Element.width Element.fill
-                            ]
-                   , markdown """
-                        Here is some more markdown.
-                     """
-                   ]
-                :: [ markdown """
-
-                        Now we are going to install few things.
-
-                        - Homebrew (to install other things)
-                        - Elm programming language
-                        - Atom editor
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        ### Install Homebrew
-
-                        Follow instructions on the [Homebrew website](https://brew.sh/) by typing the following in the terminal (you probably want to copy and paste it):
-
-                        ```sh
-                        /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
-                        ```
-
-                        <small>
-                        Make sure that the command is exactly like the one above, including the `/` character at the beginning, the quotes and parentheses.
-
-                        It will ask you to confirm several actions and ask for your password. It may take few minutes to finish, so get your coffee
-                        </small>
-
-                        :fa-coffee:
-
-                        Once it's done you should see a command prompt like that:
-
-                        ```
-                        ~ your-name$
-                        ```
-
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        ### Install the Elm programming language
-
-                        <small>Once we have Homebrew installed, we can use it to install the language.</small>
-
-                        Type the following in the terminal.
-
-                        ```sh
-                        brew install node elm
-                        ```
-
-                        and check if it works by typing:
-
-                        ```
-                        elm repl
-                        ```
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        Note that the command line changes. You should see something like that
-
-                        ```
-                        ---- Elm 0.19.0 ----------------------------------------------------------------
-                        Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
-                        --------------------------------------------------------------------------------
-                        >
-                        ```
-
-                        It's the Elm REPL
-
-                        <small>Read - Evaluate - Print Loop</small>
-
-                        *[REPL]: Read - Evaluate - Print Loop.
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        Inside the REPL type
-
-                        ```
-                        2 + 2
-                        ```
-
-                        And expect to see
-
-                        ```
-                        ---- Elm 0.19.0 ----------------------------------------------------------------
-                        Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
-                        --------------------------------------------------------------------------------
-                        > 2 + 2
-                        4 : number
-                        >
-                        ```
-
-                        Easy, huh?
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        We will learn more about REPL later. For now type `:exit` to close it.
+        CounterMsg m ->
+            { model | counter = Counter.update m model.counter }
=
-                        The command line should look like before again.
=
-                     """
-                   ]
-                :: [ markdown """
+type alias Styling =
+    Mark.Styling Msg
=
-                        ### Install Atom text editor
=
-                        Computer programs are represented as text, so the text editor is the most fundamental tool of a programmer. There is a lot of good text editors, but to get you started, we will use [Atom] here.
+type alias Options =
+    Mark.Options Model Styling Msg
=
-                    """
-                   ]
-                :: [ markdown """
=
-                        Type following in the terminal:
-
-                        ```
-                        brew cask install atom
-                        ```
-
-                        And start it with:
-
-                        ```sh
-                        atom
-                        ```
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        One last thing we need is Elm support for Atom editor. You can install it by typing in the terminal:
-
-                        ```
-                        apm install language-elm
-                        ```
-
-                        <small>APM is the Atom Package Manager, but don't pay much attention to it. We won't be using it again.</small>
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        **We are all set!**
-
-                        :smile:
-
-                    """
-                   ]
-                :: [ markdown """
-
-
-                        # First program!
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        As mentioned before, programs are represented as text (called *the source code*).
-
-                        The source code is stored in files
-
-                        :fa-file:
-
-                        and files are organized in directories
-
-                        :fa-folder:
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        So the first step is to create a directory for our new program. Let's call it `fpart`.
-
-                        In the terminal type
-
-                        ```sh
-                        mkdir fpart/
-                        ```
-
-                        and then
-
-                        ```
-                        cd fpart/
-                        ```
-
-                        <small>This creates a new directory and makes it the current one. Again, don't worry about the details.</small>
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        To easily create a new program, we can type
-
-                        ```
-                        elm init
-                        ```
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        Then to create a file with source code, type
-
-                        ```
-                        atom src/Main.elm
-                        ```
-
-                        <small>This command should open a new Atom window with empty text file.</small>
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        ### `main.elm`
-
-                        ```elm
-                        module Main exposing (main)
-
-                        import Html
-
-
-                        main =
-                            Html.text "Hello, Tree!"
-                        ```
-
-                        <small>Type the above in the editor and save the file</small>
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        To see the program running type following in the terminal
-
-                        ```sh
-                        elm reactor
-                        ```
-
-                        <small>This command starts the Elm reactor, which will let you run your program in the web browser. Note that it won't give you the command line back - it will run as long as you don't stop it.</small>
-
-                     """
-                   ]
-                :: [ markdown """
-
-                        # Voila!
-
-                        <small>Open following address in the web browser</small>
-
-                        http://localhost:8000/src/Main.elm
+options : Options
+options =
+    let
+        default =
+            Mark.default
+
+        counterBlock : Mark.Custom.Block Model Styling Msg
+        counterBlock =
+            Mark.Custom.block "counter" counterView
+
+        counterView : Styling -> Model -> Element Msg
+        counterView style model =
+            model.counter
+                |> Counter.ui
+                |> Element.el
+                    [ Element.centerX
+                    ]
+                |> Element.el
+                    [ Element.centerX
+                    , Border.color (Element.rgb 1 0.6 0.6)
+                    , Border.rounded 5
+                    , Border.width 2
+                    ]
+                |> Element.map CounterMsg
+    in
+    { default
+        | blocks =
+            counterBlock :: Mark.defaultBlocks
+    }
=
-                        <small>Note that the same address was printed by Elm reactor</small>
=
-                     """
-                   ]
-                :: [ markdown """
+content =
+    """
+| header
+    To do:
=
-                        # Let's make a dot!
-                        # :fa-circle:
+Steps to reproduce the tree:
=
-                     """
-                   ]
-                :: [ markdown """
+Make a dot
=
-                        We are going to use a technology called SVG
+  Centered (Elm UI, viewBox, cartesian coordinates)
=
-                        <small>Scalable Vector Graphics</small>
+Make a line
=
+  Play with transformations (union types)
=
-                        *[SVG]: Scalable Vector Graphics
+Gradients
=
-                     """
-                   ]
-                :: [ markdown """
+Multiple lines
=
-                        Let's install an Elm package to help us work with SVG.
+  Rosettes (different kinds)
=
-                        Stop the Reactor running in terminal by pressing
+Groups and transformations
=
-                        `CTRL-C`
+  Spiral (recursion)
=
-                        and type the following
+Tree
=
-                        ```
-                        elm install elm/svg
-                        ```
=
-                        Then start the reactor again
+| header
+    Before the course begins
=
-                        ```
-                        elm reactor
-                        ```
+Setup the development environment
=
-                        <small>you can press up arrow :fa-arrow-up: on the keyboard to get to previous commands</small>
+| list
+    - Elm
+    - Node.js
=
-                     """
-                   ]
-                :: [ markdown """
=
-                        <iframe id="cartesian" data-src="./CartesianCoordinates.html" class="stretch">
-                        </iframe>
+| counter
=
-                     """
-                   ]
-                :: [ markdown """
-                        Move sliders to change the `x` and `y` coordinates of the dot. It's like moving a thing on a table by telling how far left, right, up or down should it go.
-                     """
-                   , model.cartesianCoordinates
-                        |> CartesianCoordinates.ui
-                        |> Element.map CartesianCoordinatesMsg
-                        |> Element.el
-                            [ Element.centerX
-                            , Element.width (Element.maximum 600 Element.fill)
-                            ]
-                   ]
-                :: [ markdown """
-                        Move sliders to change the `angle` and `length` properties of the line connecting the dot and origin. The x and y coordinates will be calculated like this:
+Last sentence
=
-                        ```
-                        x = cos(angle) * length
+| counter
=
-                        y = sin(angle) * length
-                        ```
-                     """
-                   , model.polarCoordinates
-                        |> PolarCoordinates.ui
-                        |> Element.map PolarCoordinatesMsg
-                        |> Element.el
-                            [ Element.centerX
-                            , Element.width (Element.maximum 600 Element.fill)
-                            ]
-                   ]
-                :: []
+"""