Skip to content

Instantly share code, notes, and snippets.

Created July 4, 2017 13:28
Show Gist options
  • Save anonymous/6e1df73bd0cc16443d87c58647eead17 to your computer and use it in GitHub Desktop.
Save anonymous/6e1df73bd0cc16443d87c58647eead17 to your computer and use it in GitHub Desktop.

Revisions

  1. @invalid-email-address Anonymous created this gist Jul 4, 2017.
    194 changes: 194 additions & 0 deletions Main.elm
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,194 @@
    module Main exposing (..)

    import Html exposing (Html, Attribute, div, ul, label, span, li, a, input, text)
    import Html.Attributes exposing (..)
    import Html.Events exposing (on, onInput, onClick, keyCode)
    import Tuple exposing (first, second)
    import Json.Decode as Json


    main =
    Html.beginnerProgram
    { model = model
    , view = view
    , update = update
    }



    -- MODEL


    type alias Task =
    { id : Int
    , description : String
    , isComplete : Bool
    }


    type alias Model =
    { uid : Int
    , description : String
    , tasks : List Task
    , visibilityFilter : String
    }


    model : Model
    model =
    Model 3 "" initStartTasks "all"


    initStartTasks : List Task
    initStartTasks =
    List.map mapTask startingTasks


    startingTasks : List ( Int, String )
    startingTasks =
    [ ( 0, "Buy milk" )
    , ( 1, "Read paper" )
    , ( 2, "Post letter" )
    ]


    mapTask : ( Int, String ) -> Task
    mapTask obj =
    taskInit (first obj) (second obj)


    taskInit : Int -> String -> Task
    taskInit id description =
    { id = id
    , description = description
    , isComplete = False
    }



    -- UPDATE


    type Msg
    = DescriptionChange String
    | Add
    | ApplyFilter String
    | ToggleStatus Int Bool


    update : Msg -> Model -> Model
    update msg model =
    case msg of
    DescriptionChange newContent ->
    { model | description = newContent }

    Add ->
    { model
    | uid = model.uid + 1
    , description = ""
    , tasks =
    if String.isEmpty model.description then
    model.tasks
    else
    model.tasks ++ [ taskInit model.uid model.description ]
    }

    ApplyFilter filter ->
    { model | visibilityFilter = filter }

    ToggleStatus id isCompleted ->
    let
    updateEntry t =
    if t.id == id then
    { t | isComplete = isCompleted }
    else
    t
    in
    { model | tasks = List.map updateEntry model.tasks }


    -- VIEW


    view : Model -> Html Msg
    view model =
    div [ id "root" ]
    [ viewInputBox model
    , div [] [ viewTasks model ]
    , div [] [ viewFilters model.visibilityFilter ]
    ]


    viewInputBox : Model -> Html Msg
    viewInputBox model =
    div [ class "has-float-label" ]
    [ input [ type_ "text", placeholder " ", value model.description, onInput DescriptionChange, onEnter Add ] []
    , label [] [ text "What do you need to do?" ]
    ]


    viewTasks : Model -> Html Msg
    viewTasks model =
    let
    liItems =
    List.map viewTaskItem (List.filter (taskFilter model.visibilityFilter) model.tasks)
    in
    ul [ id "task-list" ]
    ([] ++ liItems)


    taskFilter filter =
    filterTasks filter

    filterTasks : String -> Task -> Bool
    filterTasks filter task =
    case filter of
    "active" ->
    not task.isComplete

    "complete" ->
    task.isComplete

    _ ->
    True

    viewTaskItem : Task -> Html Msg
    viewTaskItem task =
    li [ class "list-item", id ("task-" ++ toString task.id) ]
    [ label [ class "list-item__checkbox tickbox" ]
    [ input [ type_ "checkbox", checked task.isComplete, onClick (ToggleStatus task.id (not task.isComplete)) ] []
    , span [] [ text task.description ]
    ]
    ]


    viewFilters : String -> Html Msg
    viewFilters filter =
    div [ class "filters" ]
    [ visibilityFilter "all" filter
    , text " "
    , visibilityFilter "active" filter
    , text " "
    , visibilityFilter "complete" filter
    ]

    visibilityFilter: String -> String -> Html Msg
    visibilityFilter filter activeFilter =
    a [ href ("#/" ++ filter), classList [("selected", filter == activeFilter)], onClick (ApplyFilter filter) ]
    [ text (capitalise filter) ]


    capitalise: String -> String
    capitalise str =
    (String.toUpper (String.left 1 str)) ++ String.slice 1 (String.length str) str

    onEnter : Msg -> Attribute Msg
    onEnter msg =
    let
    isEnter code =
    if code == 13 then
    Json.succeed msg
    else
    Json.fail "not ENTER"
    in
    on "keydown" (Json.andThen isEnter keyCode)
    15 changes: 15 additions & 0 deletions elm-package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    {
    "version": "1.0.0",
    "summary": "Attempt to write own version of todo list (WiP)\n",
    "repository": "https://github.com/user/project.git",
    "license": "BSD3",
    "source-directories": [
    "."
    ],
    "exposed-modules": [],
    "dependencies": {
    "elm-lang/core": "5.1.1 <= v < 5.1.1",
    "elm-lang/html": "2.0.0 <= v < 2.0.0"
    },
    "elm-version": "0.18.0 <= v < 0.19.0"
    }
    168 changes: 168 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,168 @@
    <html>
    <head>
    <style>
    body {
    background: #fff;
    font-size: 16px;
    font-family: Consolas, "monospace";
    }
    </style>
    <style id="has-float-label">
    .has-float-label {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    position: relative;
    }
    .has-float-label label, .has-float-label > span {
    position: absolute;
    left: 5px;
    top: 1px;
    cursor: text;
    font-size: .75em;
    opacity: 1;
    -webkit-transition: all .2s;
    transition: all .2s;
    }
    .has-float-label select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    }
    .has-float-label input, .has-float-label select {
    font-size: inherit;
    padding: 0 .5em;
    padding-top: 1em;
    margin-bottom: 2px;
    border: 0;
    border-radius: 0;
    border-bottom: 2px solid rgba(0, 0, 0, 0.1);
    }
    .has-float-label input::-webkit-input-placeholder, .has-float-label select::-webkit-input-placeholder {
    opacity: 1;
    -webkit-transition: all .2s;
    transition: all .2s;
    }
    .has-float-label input:placeholder-shown:not(:focus)::-webkit-input-placeholder, .has-float-label select:placeholder-shown:not(:focus)::-webkit-input-placeholder {
    opacity: 0;
    }
    .has-float-label input:placeholder-shown:not(:focus) + *:not(.input-has-content), .has-float-label select:placeholder-shown:not(:focus) + *:not(.input-has-content) {
    font-size: 1.3em;
    opacity: .5;
    pointer-events: none;
    top: .25em;
    left: .5em;
    }
    .has-float-label input:focus, .has-float-label select:focus {
    outline: none;
    border-color: rgba(0, 0, 0, 0.5);
    }
    .has-float-label.input-list-container input {
    padding-bottom: 0.3em;
    }
    .has-float-label.input-list-container input:placeholder-shown:not(:focus) + *:not(.input-has-content) {
    font-size: 1.3em;
    opacity: .5;
    pointer-events: none;
    top: 1em;
    }
    .has-float-label.select-container::after {
    content: "\2335";
    position: absolute;
    top: 50%;
    right: 5px;
    -webkit-transform: translateY(-50%);
    transform: translateY(-50%);
    font-weight: bold;
    pointer-events: none;
    }
    </style>
    <style>

    .tickbox {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: start;
    -ms-flex-pack: start;
    justify-content: flex-start;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    padding: 2px;
    cursor: pointer;
    }
    .tickbox input[type="checkbox"] {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    -webkit-transition: all 0.3s;
    transition: all 0.3s;
    position: relative;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    width: 20px;
    height: 20px;
    margin: 0 5px;
    }

    .tickbox input:before,
    .tickbox input:checked:before {
    color: #000;
    -webkit-transition: all 0.3s;
    transition: all 0.3s;
    cursor: pointer;
    z-index: 1;
    }

    .tickbox input:before {
    content: "\2610";
    font-size: 2em;
    }

    .tickbox input:disabled:before {
    content: "\274c";
    font-size: 1em;
    color: #444;
    }

    .tickbox input:checked:before {
    content: "\2611";
    color: #0f0;
    }
    </style>
    <style>
    ul {
    list-style-type: none;
    padding: 5px;
    margin: 5px 0;
    }
    </style>
    <style>
    input[type="text"] {
    width: 300px;
    max-width: 100%;
    }

    input[type="checkbox"]:checked + span {
    text-decoration: line-through;
    }

    .filters > .selected {
    color: #ccc;
    }
    </style>
    </head>
    <body>
    <script>
    var app = Elm.Main.fullscreen()
    </script>
    </body>
    </html>