elm(todolist): feat: basic todo operations
Signed-off-by: prescientmoon <git@moonythm.dev>
This commit is contained in:
parent
8cd06f56bd
commit
5278cf694d
6
elm/todolist/elm-analyse.json
Normal file
6
elm/todolist/elm-analyse.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"checks": {
|
||||
"ExposeAll": false,
|
||||
"ImportAll": false
|
||||
}
|
||||
}
|
|
@ -1,20 +1,36 @@
|
|||
module Main exposing (..)
|
||||
|
||||
import Browser
|
||||
import Html exposing (Html, text, div, h1, img)
|
||||
import Html.Attributes exposing (src)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (..)
|
||||
|
||||
|
||||
|
||||
-- HELPER TYPES
|
||||
|
||||
|
||||
type alias Todo =
|
||||
{ done : Bool
|
||||
, text : String
|
||||
, id : Int
|
||||
}
|
||||
|
||||
|
||||
|
||||
---- MODEL ----
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
{ todos : List Todo
|
||||
, lastId : Int
|
||||
, nextTodoText : String
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init : Model
|
||||
init =
|
||||
( {}, Cmd.none )
|
||||
Model [] 0 ""
|
||||
|
||||
|
||||
|
||||
|
@ -22,12 +38,48 @@ init =
|
|||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
= AddTodo
|
||||
| DeleteTodo Int
|
||||
| ToggleTodoCompletion Int
|
||||
| SetNextTodoText String
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
( model, Cmd.none )
|
||||
update : Msg -> Model -> Model
|
||||
update message model =
|
||||
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 =
|
||||
div []
|
||||
[ img [ src "/logo.svg" ] []
|
||||
, h1 [] [ text "Your Elm App is working!" ]
|
||||
div [ class "container" ]
|
||||
[ header model
|
||||
, 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 =
|
||||
Browser.element
|
||||
Browser.sandbox
|
||||
{ view = view
|
||||
, init = \_ -> init
|
||||
, init = init
|
||||
, update = update
|
||||
, subscriptions = always Sub.none
|
||||
}
|
||||
|
|
|
@ -9,18 +9,103 @@
|
|||
height: inherit;
|
||||
}
|
||||
|
||||
:root {
|
||||
--secondary: #009fb7;
|
||||
--primary: #1a213b;
|
||||
--on-secondary: #eff1f4;
|
||||
--disabled: #555555;
|
||||
}
|
||||
|
||||
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;
|
||||
text-align: center;
|
||||
color: #293c4b;
|
||||
background: var(--primary);
|
||||
|
||||
color: var(--on-secondary);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
img {
|
||||
margin: 20px 0;
|
||||
max-width: 200px;
|
||||
.header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue