diff --git a/containers/elm/.devcontainer/Dockerfile b/containers/elm/.devcontainer/Dockerfile new file mode 100644 index 0000000000..655901a789 --- /dev/null +++ b/containers/elm/.devcontainer/Dockerfile @@ -0,0 +1,32 @@ +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +FROM debian:9 + +# Avoid warnings by switching to noninteractive +ENV DEBIAN_FRONTEND=noninteractive + +# Configuring Elm version +ARG ELM_VERSION=0.19.0 + + +# Configure apt and install packages +RUN apt-get update \ + && apt-get -y install --no-install-recommends apt-utils 2>&1 \ + # + # Verify git and needed tools are installed + && apt-get install -y git procps \ + && apt-get install -y wget \ + # + # Install elm globally + && wget -O - https://github.com/elm/compiler/releases/download/${ELM_VERSION}/binary-for-linux-64-bit.gz | gunzip -c > /usr/local/bin/elm && chmod +x /usr/local/bin/elm \ + # + # Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +# Switch back to dialog for any ad-hoc use of apt-get +ENV DEBIAN_FRONTEND=dialog diff --git a/containers/elm/.devcontainer/devcontainer.json b/containers/elm/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..03e781e425 --- /dev/null +++ b/containers/elm/.devcontainer/devcontainer.json @@ -0,0 +1,18 @@ +{ + "name": "Elm", + "dockerFile": "Dockerfile", + + // Uncomment the next line if you want to publish any ports. + // 8000 is the default port used for the `elm reactor` command + //"appPort": [8000], + + // Uncomment the next line if you want to add in default container specific settings.json values + // "settings": { "workbench.colorTheme": "Quiet Light" }, + + // Uncomment the next line to run commands after the container is created. + // "postCreateCommand": "elm make", + + "extensions": [ + "sbrink.elm" + ] +} diff --git a/containers/elm/.npmignore b/containers/elm/.npmignore new file mode 100644 index 0000000000..1d72d293eb --- /dev/null +++ b/containers/elm/.npmignore @@ -0,0 +1,4 @@ +README.md +test-project +.vscode +.npmignore diff --git a/containers/elm/README.md b/containers/elm/README.md new file mode 100644 index 0000000000..0ed264bd81 --- /dev/null +++ b/containers/elm/README.md @@ -0,0 +1,51 @@ +# Elm + +## Summary + +*Develop Elm based applications. Includes the elm extension & binary + +| Metadata | Value | +|----------|-------| +| *Contributors* | xWiiLLz | +| *Definition type* | Dockerfile | +| *Languages, platforms* | Elm | + +## Using this definition with an existing folder + +This definition does not require any special steps to use. Just follow these steps: + +1. If this is your first time using a development container, please follow the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started) to set up your machine. + +2. To use VS Code's copy of this definition: + 1. Start VS Code and open your project folder. + 2. Press F1 select and **Remote-Containers: Add Development Container Configuration Files...** from the command palette. + 3. Select the **Elm** definition. + +3. To use latest-and-greatest copy of this definition from the repository: + 1. Clone this repository. + 2. Copy the contents of `containers/elm/.devcontainer` to the root of your project folder. + 3. Start VS Code and open your project folder. + +4. After following step 2 or 3, the contents of the `.devcontainer` folder in your project can be adapted to meet your needs. + +5. Finally, press F1 and run **Remote-Containers: Reopen Folder in Container** to start using the definition. + +## Testing the definition + +This definition includes some test code that will help you verify it is working as expected on your system. Follow these steps: + +1. If this is your first time using a development container, please follow the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started) to set up your machine. +2. Clone this repository. +3. Start VS Code, press F1, and select **Remote-Containers: Open Folder in Container...** +4. Select the `containers/elm` folder. +5. After the folder has opened in the container, open a terminal in the `test-project` folder (`cd test-project/`) and run the following command: `elm reactor` +6. Once the project is running, press F1 and select **Remote-Containers: Forward Port from Container...** +7. Select port 8000 and click the "Open Browser" button in the notification that appears. +8. You should see the Elm startup page. +9. From here, you can browse any of the files in the `examples` folder to see them compiled and ran in your browser 😊 + +## License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. See [LICENSE](https://github.com/Microsoft/vscode-dev-containers/blob/master/LICENSE). \ No newline at end of file diff --git a/containers/elm/test-project/.gitignore b/containers/elm/test-project/.gitignore new file mode 100644 index 0000000000..d86ae43c0e --- /dev/null +++ b/containers/elm/test-project/.gitignore @@ -0,0 +1,2 @@ +elm-stuff +elm.js \ No newline at end of file diff --git a/containers/elm/test-project/LICENSE b/containers/elm/test-project/LICENSE new file mode 100644 index 0000000000..2377b9c65f --- /dev/null +++ b/containers/elm/test-project/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014-2016, Evan Czaplicki +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/containers/elm/test-project/README.md b/containers/elm/test-project/README.md new file mode 100644 index 0000000000..53ea50e4e4 --- /dev/null +++ b/containers/elm/test-project/README.md @@ -0,0 +1,28 @@ +# Elm + +[Elm](https://elm-lang.org/) is a programming language that compiles to JavaScript. It is known for its friendly error messages, helping you find issues quickly and refactor large projects with confidence. Elm is also [very fast](https://elm-lang.org/blog/blazing-fast-html-round-two) and [very small](https://elm-lang.org/blog/small-assets-without-the-headache) when compared with React, Angular, Ember, etc. + +This repo focuses on **The Elm Architecture**, an architecture pattern you see in all Elm programs. It has influenced projects like Redux that borrow core concepts but add many JS-focused ideas. + + +## The Elm Architecture + +The Elm Architecture is a simple pattern for architecting webapps. The core idea is that your code is built around a `Model` of your application state, a way to `update` your model, and a way to `view` your model. + +To learn more about this, read the [the official guide][guide] and check out [this section][arch] which is all about The Elm Architecture. This repo is a collection of all the examples in that section, so you can follow along and compile things on your computer as you read through. + +[guide]: https://guide.elm-lang.org/ +[arch]: https://guide.elm-lang.org/architecture/ + + +## Run The Examples + +After you [install](https://guide.elm-lang.org/install.html), run the following commands in your terminal to download this repo and start a server that compiles Elm for you: + +```bash +git clone https://github.com/evancz/elm-architecture-tutorial.git +cd elm-architecture-tutorial +elm reactor +``` + +Now go to [http://localhost:8000/](http://localhost:8000/) and start looking at the `examples/` directory. When you edit an Elm file, just refresh the corresponding page in your browser and it will recompile! diff --git a/containers/elm/test-project/elm.json b/containers/elm/test-project/elm.json new file mode 100644 index 0000000000..11db8563b1 --- /dev/null +++ b/containers/elm/test-project/elm.json @@ -0,0 +1,28 @@ +{ + "type": "application", + "source-directories": [ + "examples" + ], + "elm-version": "0.19.0", + "dependencies": { + "direct": { + "elm/browser": "1.0.0", + "elm/core": "1.0.2", + "elm/html": "1.0.0", + "elm/http": "2.0.0", + "elm/json": "1.1.1", + "elm/random": "1.0.0", + "elm/time": "1.0.0", + "elm/url": "1.0.0" + }, + "indirect": { + "elm/bytes": "1.0.3", + "elm/file": "1.0.1", + "elm/virtual-dom": "1.0.0" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} \ No newline at end of file diff --git a/containers/elm/test-project/examples/01-button.elm b/containers/elm/test-project/examples/01-button.elm new file mode 100644 index 0000000000..2599444620 --- /dev/null +++ b/containers/elm/test-project/examples/01-button.elm @@ -0,0 +1,41 @@ +import Browser +import Html exposing (Html, button, div, text) +import Html.Events exposing (onClick) + + +main = + Browser.sandbox { init = init, update = update, view = view } + + +-- MODEL + +type alias Model = Int + +init : Model +init = + 0 + + +-- UPDATE + +type Msg = Increment | Decrement + +update : Msg -> Model -> Model +update msg model = + case msg of + Increment -> + model + 1 + + Decrement -> + model - 1 + + +-- VIEW + +view : Model -> Html Msg +view model = + div [] + [ button [ onClick Decrement ] [ text "-" ] + , div [] [ text (String.fromInt model) ] + , button [ onClick Increment ] [ text "+" ] + ] \ No newline at end of file diff --git a/containers/elm/test-project/examples/02-field.elm b/containers/elm/test-project/examples/02-field.elm new file mode 100644 index 0000000000..3041f29fbc --- /dev/null +++ b/containers/elm/test-project/examples/02-field.elm @@ -0,0 +1,53 @@ +import Browser +import Html exposing (Html, Attribute, div, input, text) +import Html.Attributes exposing (..) +import Html.Events exposing (onInput) + + + +-- MAIN + + +main = + Browser.sandbox { init = init, update = update, view = view } + + + +-- MODEL + + +type alias Model = + { content : String + } + + +init : Model +init = + { content = "" } + + + +-- UPDATE + + +type Msg + = Change String + + +update : Msg -> Model -> Model +update msg model = + case msg of + Change newContent -> + { model | content = newContent } + + + +-- VIEW + + +view : Model -> Html Msg +view model = + div [] + [ input [ placeholder "Text to reverse", value model.content, onInput Change ] [] + , div [] [ text (String.reverse model.content) ] + ] diff --git a/containers/elm/test-project/examples/03-form.elm b/containers/elm/test-project/examples/03-form.elm new file mode 100644 index 0000000000..3126715620 --- /dev/null +++ b/containers/elm/test-project/examples/03-form.elm @@ -0,0 +1,78 @@ +import Browser +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onInput) + + + +-- MAIN + + +main = + Browser.sandbox { init = init, update = update, view = view } + + + +-- MODEL + + +type alias Model = + { name : String + , password : String + , passwordAgain : String + } + + +init : Model +init = + Model "" "" "" + + + +-- UPDATE + + +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 + + +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 ] [] + + +viewValidation : Model -> Html msg +viewValidation model = + if model.password == model.passwordAgain then + div [ style "color" "green" ] [ text "OK" ] + else + div [ style "color" "red" ] [ text "Passwords do not match!" ] diff --git a/containers/elm/test-project/examples/04-maybe.elm b/containers/elm/test-project/examples/04-maybe.elm new file mode 100644 index 0000000000..fd41c74d75 --- /dev/null +++ b/containers/elm/test-project/examples/04-maybe.elm @@ -0,0 +1,65 @@ +import Browser +import Html exposing (Html, Attribute, span, input, text) +import Html.Attributes exposing (..) +import Html.Events exposing (onInput) + + + +-- MAIN + + +main = + Browser.sandbox { init = init, update = update, view = view } + + + +-- MODEL + + +type alias Model = + { input : String + } + + +init : Model +init = + { input = "" } + + + +-- UPDATE + + +type Msg + = Change String + + +update : Msg -> Model -> Model +update msg model = + case msg of + Change newInput -> + { model | input = newInput } + + + +-- VIEW + + +view : Model -> Html Msg +view model = + case String.toFloat model.input of + Just celsius -> + viewConverter model.input "blue" (String.fromFloat (celsius * 1.8 + 32)) + + Nothing -> + viewConverter model.input "red" "???" + + +viewConverter : String -> String -> String -> Html Msg +viewConverter userInput color equivalentTemp = + span [] + [ input [ value userInput, onInput Change, style "width" "40px" ] [] + , text "°C = " + , span [ style "color" color ] [ text equivalentTemp ] + , text "°F" + ] diff --git a/containers/elm/test-project/examples/05-http.elm b/containers/elm/test-project/examples/05-http.elm new file mode 100644 index 0000000000..1483834eba --- /dev/null +++ b/containers/elm/test-project/examples/05-http.elm @@ -0,0 +1,82 @@ +import Browser +import Html exposing (Html, text, pre) +import Http + + + +-- MAIN + + +main = + Browser.element + { init = init + , update = update + , subscriptions = subscriptions + , view = view + } + + + +-- MODEL + + +type Model + = Failure + | Loading + | Success String + + +init : () -> (Model, Cmd Msg) +init _ = + ( Loading + , Http.get + { url = "https://elm-lang.org/assets/public-opinion.txt" + , expect = Http.expectString GotText + } + ) + + + +-- UPDATE + + +type Msg + = GotText (Result Http.Error String) + + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = + case msg of + GotText result -> + case result of + Ok fullText -> + (Success fullText, Cmd.none) + + Err _ -> + (Failure, Cmd.none) + + + +-- SUBSCRIPTIONS + + +subscriptions : Model -> Sub Msg +subscriptions model = + Sub.none + + + +-- VIEW + + +view : Model -> Html Msg +view model = + case model of + Failure -> + text "I was unable to load your book." + + Loading -> + text "Loading..." + + Success fullText -> + pre [] [ text fullText ] diff --git a/containers/elm/test-project/examples/06-json.elm b/containers/elm/test-project/examples/06-json.elm new file mode 100644 index 0000000000..d4824865b8 --- /dev/null +++ b/containers/elm/test-project/examples/06-json.elm @@ -0,0 +1,115 @@ +import Browser +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Http +import Json.Decode exposing (Decoder, field, string) + + + +-- MAIN + + +main = + Browser.element + { init = init + , update = update + , subscriptions = subscriptions + , view = view + } + + + +-- MODEL + + +type Model + = Failure + | Loading + | Success String + + +init : () -> (Model, Cmd Msg) +init _ = + (Loading, getRandomCatGif) + + + +-- UPDATE + + +type Msg + = MorePlease + | GotGif (Result Http.Error String) + + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = + case msg of + MorePlease -> + (Loading, getRandomCatGif) + + GotGif result -> + case result of + Ok url -> + (Success url, Cmd.none) + + Err _ -> + (Failure, Cmd.none) + + + +-- SUBSCRIPTIONS + + +subscriptions : Model -> Sub Msg +subscriptions model = + Sub.none + + + +-- VIEW + + +view : Model -> Html Msg +view model = + div [] + [ h2 [] [ text "Random Cats" ] + , viewGif model + ] + + +viewGif : Model -> Html Msg +viewGif model = + case model of + Failure -> + div [] + [ text "I could not load a random cat for some reason. " + , button [ onClick MorePlease ] [ text "Try Again!" ] + ] + + Loading -> + text "Loading..." + + Success url -> + div [] + [ button [ onClick MorePlease, style "display" "block" ] [ text "More Please!" ] + , img [ src url ] [] + ] + + + +-- HTTP + + +getRandomCatGif : Cmd Msg +getRandomCatGif = + Http.get + { url = "https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cat" + , expect = Http.expectJson GotGif gifDecoder + } + + +gifDecoder : Decoder String +gifDecoder = + field "data" (field "image_url" string) diff --git a/containers/elm/test-project/examples/07-random.elm b/containers/elm/test-project/examples/07-random.elm new file mode 100644 index 0000000000..b11f637685 --- /dev/null +++ b/containers/elm/test-project/examples/07-random.elm @@ -0,0 +1,77 @@ +import Browser +import Html exposing (..) +import Html.Events exposing (..) +import Random + + + +-- MAIN + + +main = + Browser.element + { init = init + , update = update + , subscriptions = subscriptions + , view = view + } + + + +-- MODEL + + +type alias Model = + { dieFace : Int + } + + +init : () -> (Model, Cmd Msg) +init _ = + ( Model 1 + , Cmd.none + ) + + + +-- UPDATE + + +type Msg + = Roll + | NewFace Int + + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = + case msg of + Roll -> + ( model + , Random.generate NewFace (Random.int 1 6) + ) + + NewFace newFace -> + ( Model newFace + , Cmd.none + ) + + + +-- SUBSCRIPTIONS + + +subscriptions : Model -> Sub Msg +subscriptions model = + Sub.none + + + +-- VIEW + + +view : Model -> Html Msg +view model = + div [] + [ h1 [] [ text (String.fromInt model.dieFace) ] + , button [ onClick Roll ] [ text "Roll" ] + ] \ No newline at end of file diff --git a/containers/elm/test-project/examples/08-time.elm b/containers/elm/test-project/examples/08-time.elm new file mode 100644 index 0000000000..9f6ed6bad5 --- /dev/null +++ b/containers/elm/test-project/examples/08-time.elm @@ -0,0 +1,81 @@ +import Browser +import Html exposing (..) +import Task +import Time + + + +-- MAIN + + +main = + Browser.element + { init = init + , view = view + , update = update + , subscriptions = subscriptions + } + + + +-- MODEL + + +type alias Model = + { zone : Time.Zone + , time : Time.Posix + } + + +init : () -> (Model, Cmd Msg) +init _ = + ( Model Time.utc (Time.millisToPosix 0) + , Task.perform AdjustTimeZone Time.here + ) + + + +-- UPDATE + + +type Msg + = Tick Time.Posix + | AdjustTimeZone Time.Zone + + + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = + case msg of + Tick newTime -> + ( { model | time = newTime } + , Cmd.none + ) + + AdjustTimeZone newZone -> + ( { model | zone = newZone } + , Cmd.none + ) + + + +-- SUBSCRIPTIONS + + +subscriptions : Model -> Sub Msg +subscriptions model = + Time.every 1000 Tick + + + +-- VIEW + + +view : Model -> Html Msg +view model = + let + hour = String.fromInt (Time.toHour model.zone model.time) + minute = String.fromInt (Time.toMinute model.zone model.time) + second = String.fromInt (Time.toSecond model.zone model.time) + in + h1 [] [ text (hour ++ ":" ++ minute ++ ":" ++ second) ] \ No newline at end of file