1
Fork 0

elm(todolist): feat: basic todo operations

Signed-off-by: prescientmoon <git@moonythm.dev>
This commit is contained in:
Matei Adriel 2019-11-28 16:57:45 +02:00 committed by prescientmoon
parent 8cd06f56bd
commit 5278cf694d
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
3 changed files with 223 additions and 21 deletions

View file

@ -0,0 +1,6 @@
{
"checks": {
"ExposeAll": false,
"ImportAll": false
}
}

View file

@ -1,20 +1,36 @@
module Main exposing (..) module Main exposing (..)
import Browser import Browser
import Html exposing (Html, text, div, h1, img) import Html exposing (..)
import Html.Attributes exposing (src) import Html.Attributes exposing (..)
import Html.Events exposing (..)
-- HELPER TYPES
type alias Todo =
{ done : Bool
, text : String
, id : Int
}
---- MODEL ---- ---- MODEL ----
type alias Model = type alias Model =
{} { todos : List Todo
, lastId : Int
, nextTodoText : String
}
init : ( Model, Cmd Msg ) init : Model
init = init =
( {}, Cmd.none ) Model [] 0 ""
@ -22,12 +38,48 @@ init =
type Msg type Msg
= NoOp = AddTodo
| DeleteTodo Int
| ToggleTodoCompletion Int
| SetNextTodoText String
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> Model
update msg model = update message model =
( model, Cmd.none ) case message of
AddTodo ->
if model.nextTodoText == "" then
model
else
let
id =
model.lastId + 1
text =
model.nextTodoText
in
{ model | lastId = id, todos = Todo False text id :: model.todos }
DeleteTodo id ->
{ model | todos = List.filter ((/=) id << .id) model.todos }
ToggleTodoCompletion id ->
{ model
| todos =
List.map
(\todo ->
if todo.id == id then
{ todo | done = not todo.done }
else
todo
)
model.todos
}
SetNextTodoText text ->
{ model | nextTodoText = text }
@ -36,9 +88,69 @@ update msg model =
view : Model -> Html Msg view : Model -> Html Msg
view model = view model =
div [] div [ class "container" ]
[ img [ src "/logo.svg" ] [] [ header model
, h1 [] [ text "Your Elm App is working!" ] , div [ class "todos" ] <|
List.map
todoView
model.todos
]
-- HEADER
header : Model -> Html Msg
header _ =
div [ class "header" ]
[ button
[ class "btn"
, onClick AddTodo
]
[ text "add todo" ]
, input
[ placeholder "todo text"
, onInput SetNextTodoText
, class "todoTextInput"
]
[]
]
-- _TODO VIEW
todoClasses : Todo -> String
todoClasses todo =
"todo"
++ (if todo.done then
" completed"
else
""
)
todoView : Todo -> Html Msg
todoView todo =
div [ class <| todoClasses todo ]
[ div [ class "todoCompleted" ]
[ input
[ checked todo.done
, type_ "checkbox"
, class "todoCheckbox"
, onCheck <| \_ -> ToggleTodoCompletion todo.id
]
[]
]
, div [ class "todoText" ] [ text todo.text ]
, button
[ class "btn"
, onClick <| DeleteTodo todo.id
]
[ text "Delete todo" ]
] ]
@ -48,9 +160,8 @@ view model =
main : Program () Model Msg main : Program () Model Msg
main = main =
Browser.element Browser.sandbox
{ view = view { view = view
, init = \_ -> init , init = init
, update = update , update = update
, subscriptions = always Sub.none
} }

View file

@ -9,18 +9,103 @@
height: inherit; height: inherit;
} }
:root {
--secondary: #009fb7;
--primary: #1a213b;
--on-secondary: #eff1f4;
--disabled: #555555;
}
body { body {
font-family: 'Source Sans Pro', 'Trebuchet MS', 'Lucida Grande', 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif; font-family: "Source Sans Pro", "Trebuchet MS", "Lucida Grande",
"Bitstream Vera Sans", "Helvetica Neue", sans-serif;
margin: 0; margin: 0;
text-align: center; background: var(--primary);
color: #293c4b;
color: var(--on-secondary);
} }
h1 { h1 {
font-size: 30px; font-size: 30px;
} }
img { .header {
margin: 20px 0; display: flex;
max-width: 200px; }
.btn {
background-color: var(--secondary);
color: var(--on-secondary);
padding: 1rem;
margin: 1rem;
border: none;
}
input {
outline: none;
}
.todos {
display: flex;
flex-direction: column;
min-height: 67vh;
border: 1px solid var(--secondary);
}
.todo {
transition: filter 0.5s;
background: var(--primary);
display: flex;
}
.todo:hover {
filter: brightness(1.4);
}
.todo.completed {
color: var(--disabled);
text-decoration: line-through;
}
.todo.completed > .btn {
color: var(--disabled);
}
.todo > * {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.todoText {
justify-content: flex-start;
flex-direction: row;
flex-grow: 1;
}
.todoCompleted {
margin: 1rem;
}
.todoTextInput {
background: var(--primary);
border: 1px var(--secondary) solid;
margin: 1rem;
padding: 2px;
box-sizing: border-box;
color: var(--on-secondary);
font-size: 1.5rem;
transition: filter 0.5s;
}
.todoTextInput:focus {
filter: brightness(1.4);
}
.todoCheckbox {
width: 1rem;
height: 1rem;
background: var(--secondary);
} }