Commits: 4

Gitignore .swp files

index 9114974..0c19f1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
=/elm-stuff
=/**/.DS_Store
+*.swp

Begin reconstructing the 'fpart' presentation as an Elm program

We can render markdown and html elements

Next todo: scaling images to fit on slide

index 988c3a5..67b87e4 100644
--- a/elm.json
+++ b/elm.json
@@ -10,6 +10,8 @@
=            "elm/core": "1.0.0",
=            "elm/html": "1.0.0",
=            "elm/svg": "1.0.1",
+            "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"
new file mode 100644
index 0000000..88cb6e2
--- /dev/null
+++ b/src/Main.elm
@@ -0,0 +1,400 @@
+module Main exposing (main)
+
+import Dict
+import Element
+import Html exposing (Html)
+import Html.Attributes as Html
+import Presentation exposing (Slide, markdown)
+
+
+currentSlide =
+    5
+
+
+main =
+    let
+        slide =
+            slides
+                |> Dict.get currentSlide
+
+        notFound =
+            Element.text "404: Slide not found"
+    in
+    Element.layout [ Element.width Element.fill, Element.height Element.fill ] <|
+        Element.row
+            [ Element.centerX, Element.centerY ]
+            [ slide
+                |> Maybe.map (Element.column [])
+                |> Maybe.withDefault notFound
+            ]
+
+
+slides =
+    Dict.fromList <|
+        List.indexedMap Tuple.pair <|
+            [ markdown """
+        # FP-Art!
+        ## A functional programming workshop
+        ### for non-programmers
+    """
+            , markdown """
+        # Stuff
+    """
+            ]
+                :: [ markdown """
+               ## Setup
+           """
+                   , markdown """
+               # Stuff
+           """
+                   ]
+                :: [ 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 [Elm programming language][]
+
+        [Atom]: https://atom.io/
+        [Elm programming language]: https://elm-lang.org/
+
+      """
+                   ]
+                :: [ markdown """
+
+        We will 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
+                """
+                   , Element.el [ Element.height Element.fill, Element.width Element.fill ] <| Element.html <| Html.img [ Html.class "plain", Html.alt "Mac Terminal app window", Html.src "../assets/mac-terminal-window.png" ] []
+                   , 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.
+
+The command line should look like before again.
+
+"""
+                   ]
+                :: [ markdown """
+
+### 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.
+
+"""
+                   ]
+                :: [ 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
+
+<small>Note that the same address was printed by Elm reactor</small>
+
+"""
+                   ]
+                :: [ markdown """
+
+# Let's make a dot!
+# :fa-circle:
+
+"""
+                   ]
+                :: [ markdown """
+
+We are going to use a technology called SVG
+
+<small>Scalable Vector Graphics</small>
+
+
+*[SVG]: Scalable Vector Graphics
+
+"""
+                   ]
+                :: [ markdown """
+
+Let's install an Elm package to help us work with SVG.
+
+Stop the Reactor running in terminal by pressing
+
+`CTRL-C`
+
+and type the following
+
+```
+elm install elm/svg
+```
+
+Then start the reactor again
+
+```
+elm reactor
+```
+
+<small>you can press up arrow :fa-arrow-up: on the keyboard to get to previous commands</small>
+
+"""
+                   ]
+                :: [ markdown """
+
+<iframe id="cartesian" data-src="./CartesianCoordinates.html" class="stretch">
+</iframe>
+
+"""
+                   ]
+                :: []
new file mode 100644
index 0000000..c017bb5
--- /dev/null
+++ b/src/Presentation.elm
@@ -0,0 +1,41 @@
+module Presentation exposing (Slide, markdown)
+
+import Element exposing (Element)
+import List.Extra as List
+import Markdown
+
+
+type alias Slide msg =
+    List (Element msg)
+
+
+markdown : String -> Element msg
+markdown string =
+    let
+        dedentedString =
+            string
+                |> String.lines
+                |> List.map dedent
+                |> String.join "\n"
+
+        dedent line =
+            line
+                |> String.toList
+                |> List.indexedMap Tuple.pair
+                |> List.dropWhile (\( index, character ) -> index < indentation && character == ' ')
+                |> List.map Tuple.second
+                |> String.fromList
+
+        indentation =
+            string
+                |> String.lines
+                |> List.filter (\line -> String.trim line /= "")
+                |> List.head
+                |> Maybe.withDefault ""
+                |> String.toList
+                |> List.findIndex ((/=) ' ')
+                |> Maybe.withDefault 0
+    in
+    Markdown.toHtml [] dedentedString
+        |> Element.html
+        |> Element.el [ Element.centerX ]

Evolve program to Browser.sandobx, center text on slides

index 88cb6e2..50a8c46 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,45 +1,71 @@
=module Main exposing (main)
=
+import Browser
=import Dict
=import Element
+import Element.Font as Font
=import Html exposing (Html)
=import Html.Attributes as Html
=import Presentation exposing (Slide, markdown)
=
=
-currentSlide =
-    5
+main =
+    Browser.sandbox
+        { init = init
+        , view = view
+        , update = update
+        }
=
=
-main =
-    let
-        slide =
-            slides
-                |> Dict.get currentSlide
-
-        notFound =
-            Element.text "404: Slide not found"
-    in
-    Element.layout [ Element.width Element.fill, Element.height Element.fill ] <|
+type alias Model =
+    { currentSlide : Int
+    }
+
+
+type Msg
+    = Next
+    | Previous
+
+
+init : Model
+init =
+    { currentSlide = 0 }
+
+
+view : Model -> Html Msg
+view model =
+    Element.layout
+        [ Element.width Element.fill
+        , Element.height Element.fill
+        ]
+    <|
=        Element.row
-            [ Element.centerX, Element.centerY ]
-            [ slide
+            [ Element.centerX, Element.centerY, Font.center ]
+            [ slides
+                |> Dict.get model.currentSlide
=                |> Maybe.map (Element.column [])
-                |> Maybe.withDefault notFound
+                |> Maybe.withDefault (Element.text "404: Slide not found")
=            ]
=
=
+update : Msg -> Model -> Model
+update msg model =
+    case msg of
+        Next ->
+            { model | currentSlide = model.currentSlide + 1 }
+
+        Previous ->
+            { model | currentSlide = model.currentSlide - 1 }
+
+
=slides =
=    Dict.fromList <|
=        List.indexedMap Tuple.pair <|
=            [ markdown """
-        # FP-Art!
-        ## A functional programming workshop
-        ### for non-programmers
-    """
-            , markdown """
-        # Stuff
-    """
+                # FP-Art!
+                ## A functional programming workshop
+                ### for non-programmers
+            """
=            ]
=                :: [ markdown """
=               ## Setup

Implement keyboard navigation

index 67b87e4..d17943a 100644
--- a/elm.json
+++ b/elm.json
@@ -9,6 +9,7 @@
=            "elm/browser": "1.0.0",
=            "elm/core": "1.0.0",
=            "elm/html": "1.0.0",
+            "elm/json": "1.0.0",
=            "elm/svg": "1.0.1",
=            "elm-community/list-extra": "8.1.0",
=            "elm-explorations/markdown": "1.0.0",
@@ -17,7 +18,6 @@
=            "mdgriffith/elm-ui": "1.1.0"
=        },
=        "indirect": {
-            "elm/json": "1.0.0",
=            "elm/time": "1.0.0",
=            "elm/url": "1.0.0",
=            "elm/virtual-dom": "1.0.2",
index 50a8c46..0e51aaa 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,22 +1,29 @@
=module Main exposing (main)
=
-import Browser
+import Browser exposing (Document)
+import Browser.Events
=import Dict
=import Element
=import Element.Font as Font
=import Html exposing (Html)
=import Html.Attributes as Html
+import Json.Decode as Decode exposing (Decoder)
=import Presentation exposing (Slide, markdown)
=
=
=main =
-    Browser.sandbox
+    Browser.document
=        { init = init
=        , view = view
=        , update = update
+        , subscriptions = subscriptions
=        }
=
=
+type alias Flags =
+    ()
+
+
=type alias Model =
=    { currentSlide : Int
=    }
@@ -27,35 +34,72 @@ type Msg
=    | Previous
=
=
-init : Model
-init =
-    { currentSlide = 0 }
+init : Flags -> ( Model, Cmd Msg )
+init flags =
+    ( { currentSlide = 0 }
+    , Cmd.none
+    )
=
=
-view : Model -> Html Msg
+view : Model -> Document Msg
=view model =
-    Element.layout
-        [ Element.width Element.fill
-        , Element.height Element.fill
-        ]
-    <|
-        Element.row
-            [ Element.centerX, Element.centerY, Font.center ]
-            [ slides
-                |> Dict.get model.currentSlide
-                |> Maybe.map (Element.column [])
-                |> Maybe.withDefault (Element.text "404: Slide not found")
+    { title = "FP-Art!"
+    , body =
+        [ Element.layout
+            [ Element.width Element.fill
+            , Element.height Element.fill
=            ]
+          <|
+            Element.column
+                [ Element.centerX, Element.centerY, Font.center ]
+                [ slides
+                    |> Dict.get model.currentSlide
+                    |> Maybe.map (Element.column [ Element.height Element.fill ])
+                    |> Maybe.withDefault (Element.text "404: Slide not found")
+                ]
+        ]
+    }
=
=
-update : Msg -> Model -> Model
+update : Msg -> Model -> ( Model, Cmd Msg )
=update msg model =
=    case msg of
=        Next ->
-            { model | currentSlide = model.currentSlide + 1 }
+            ( { model
+                | currentSlide =
+                    min (Dict.size slides - 1) (model.currentSlide + 1)
+              }
+            , Cmd.none
+            )
=
=        Previous ->
-            { model | currentSlide = model.currentSlide - 1 }
+            ( { model
+                | currentSlide =
+                    max 0 (model.currentSlide - 1)
+              }
+            , Cmd.none
+            )
+
+
+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
+
+                            _ ->
+                                Decode.fail "Unsupported key"
+                    )
+    in
+    Browser.Events.onKeyPress handleKeyPress
=
=
=slides =