Add edit form.

This commit is contained in:
Dillon Kearns 2022-08-15 15:13:31 -07:00
parent ef0e421aea
commit 314f15dbf3
2 changed files with 148 additions and 128 deletions

View File

@ -188,6 +188,13 @@ action routeParams =
|> Maybe.withDefault Session.empty
in
case formResult of
Ok (EditItem itemId) ->
( okSessionThing
-- TODO implement
, Response.render {}
)
|> DataSource.succeed
Ok (DeleteItem itemId) ->
okSessionThing
|> Session.get "sessionId"
@ -406,14 +413,17 @@ view maybeUrl sharedModel model app =
, body =
[ div
[ class "todomvc-wrapper"
, style "visibility" "hidden"
]
[ section
[ class "todoapp" ]
[ newItemForm
|> Form.toDynamicFetcher "new-item"
|> Form.withOnSubmit (\_ -> ClearNewItemInput)
|> Form.renderHtml [] Nothing app ()
|> Form.renderHtml
[ class "create-form" ]
Nothing
app
()
, lazy3 viewEntries app app.data.visibility optimisticEntities
, lazy2 viewControls app.data.visibility optimisticEntities
]
@ -459,6 +469,7 @@ type Action
= CreateItem String
| DeleteItem String
| ToggleItem ( Bool, String )
| EditItem ( String, String )
completeItemForm : Form.HtmlForm String Action Todo Msg
@ -547,12 +558,16 @@ viewEntries app visibility entries =
[ class "main"
, style "visibility" cssVisibility
]
[ input
[ class "toggle-all"
, type_ "checkbox"
[ button
[ classList
[ ( "toggle-all", True )
, ( "checked"
, True
)
]
, name "toggle"
, checked allCompleted
--, checked allCompleted
--, onClick (CheckAll (not allCompleted))
]
[]
@ -590,10 +605,12 @@ viewEntry app todo =
Nothing
app
todo
, label
[--onDoubleClick (EditingEntry todo.id True)
]
[ text todo.description ]
, editItemForm
|> Form.toDynamicFetcher ("edit-" ++ uuidToString todo.id)
|> Form.renderHtml []
Nothing
app
todo
, if uuidToString todo.id == "" then
Html.text ""
@ -605,20 +622,39 @@ viewEntry app todo =
app
todo
]
, input
[ class "edit"
, value todo.description
, name "title"
, id ("todo-" ++ uuidToString todo.id)
--, onInput (UpdateEntry todo.id)
--, onBlur (EditingEntry todo.id False)
--, onEnter (EditingEntry todo.id False)
]
[]
]
editItemForm : Form.HtmlForm String Action Todo Msg
editItemForm =
Form.init
(\itemId description ->
{ combine =
Validation.succeed Tuple.pair
|> Validation.andMap itemId
|> Validation.andMap description
|> Validation.map EditItem
, view =
\formState ->
[ FieldView.input
[ class "edit-input"
, name "title"
, id ("todo-" ++ uuidToString formState.data.id)
]
description
, Html.button [ style "display" "none" ] [ Html.text "Edit" ]
]
}
)
|> Form.hiddenField "itemId" (Field.text |> Field.required "Must be present")
|> Form.field "description"
(Field.text
|> Field.required "Must be present"
|> Field.withInitialValue (.description >> Form.Value.string)
)
|> Form.hiddenKind ( "kind", "edit-item" ) "Expected kind"
uuidToString : Uuid -> String
uuidToString (Uuid uuid) =
uuid

View File

@ -1,13 +1,11 @@
/* Create to Kent C. Dodds for modified TodoMVC styles: https://github.com/kentcdodds/remix-todomvc/blob/97bbf6c548c71e1535ebe05b707b985f19caf953/app/routes/todos.css */
html,
body {
margin: 0;
padding: 0;
}
.todomvc-wrapper {
visibility: visible !important;
}
button {
margin: 0;
padding: 0;
@ -18,15 +16,12 @@ button {
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
@ -34,26 +29,15 @@ body {
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
button,
input[type="checkbox"] {
outline: none;
}
.hidden {
display: none;
}
.todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.todoapp input::-webkit-input-placeholder {
@ -88,7 +72,7 @@ input[type="checkbox"] {
}
.new-todo,
.edit {
.edit-input {
position: relative;
margin: 0;
width: 100%;
@ -96,23 +80,28 @@ input[type="checkbox"] {
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.edit-input {
border: none;
}
.edit-input:not(:focus) {
box-shadow: none;
}
.new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
@ -121,28 +110,27 @@ input[type="checkbox"] {
border-top: 1px solid #e6e6e6;
}
label[for='toggle-all'] {
display: none;
.main.no-todos {
border-top: none;
}
.main.no-todos .toggle-all {
visibility: hidden;
}
.toggle-all {
position: absolute;
top: -55px;
left: -12px;
width: 60px;
height: 34px;
text-align: center;
border: none; /* Mobile Safari */
}
.toggle-all:before {
content: '';
font-size: 22px;
position: absolute;
top: -52px;
left: 0;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked:before {
.toggle-all.checked {
color: #737373;
}
@ -170,7 +158,7 @@ label[for='toggle-all'] {
.todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
padding: 12px 16px;
margin: 0 0 0 43px;
}
@ -178,49 +166,40 @@ label[for='toggle-all'] {
display: none;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
.todo-list li button.toggle {
z-index: 1;
padding: 10px;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
appearance: none;
display: flex;
align-items: center;
}
.todo-list li .toggle:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
}
.todo-list li .toggle:checked:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
}
.todo-list li label {
white-space: pre-line;
.todo-list li input {
word-break: break-all;
padding: 15px 60px 15px 15px;
margin-left: 45px;
padding: 15px 15px 15px 60px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
.todo-list li.completed label {
.todo-list li.completed input {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
opacity: 0;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
/* this hack makes the "x" look centered */
bottom: -3px;
padding-bottom: 43px;
width: 40px;
height: 40px;
margin: auto 0;
@ -230,24 +209,18 @@ label[for='toggle-all'] {
transition: color 0.2s ease-out;
}
.todo-list li .destroy:hover {
.todo-list li .destroy:hover,
.todo-list li .destroy:focus {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: '×';
content: "×";
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
.todo-list li:hover .destroy,
.todo-list li .destroy:focus {
opacity: 1;
}
.footer {
@ -259,18 +232,16 @@ label[for='toggle-all'] {
}
.footer:before {
content: '';
content: "";
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
@ -304,7 +275,6 @@ label[for='toggle-all'] {
border-radius: 3px;
}
.filters li a.selected,
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
@ -320,7 +290,6 @@ html .clear-completed:active {
line-height: 20px;
text-decoration: none;
cursor: pointer;
position: relative;
}
.clear-completed:hover {
@ -349,28 +318,6 @@ html .clear-completed:active {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
.toggle-all {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
@ -379,4 +326,41 @@ html .clear-completed:active {
.filters {
bottom: 10px;
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.error {
color: rgb(185, 28, 28);
}
.create-form {
position: relative;
}
#new-todo-error {
position: absolute;
right: 4px;
bottom: 4px;
}
.update-form {
position: relative;
}
.todo-update-error {
font-size: 14px;
position: absolute;
right: 4px;
bottom: 4px;
}