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.
Todo list
{
"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"
}
<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>
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment