mirror of
https://github.com/ducky-labs/htmx-go-todo.git
synced 2026-02-04 06:31:00 +00:00
Delete task and toggle edit state
This commit is contained in:
36
handler.go
36
handler.go
@@ -70,3 +70,39 @@ func handleToggleTask(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
tmpl.ExecuteTemplate(w, "CompletedCount", map[string]any{"Count": completedCount, "SwapOOB": true})
|
tmpl.ExecuteTemplate(w, "CompletedCount", map[string]any{"Count": completedCount, "SwapOOB": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleDeleteTask(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id, err := strconv.Atoi(chi.URLParam(r, "id"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing id into int %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = deleteTask(r.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error deleting task %v", err)
|
||||||
|
}
|
||||||
|
count, err := fetchCount()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching count %v", err)
|
||||||
|
}
|
||||||
|
completedCount, err := fetchCompletedCount()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching completed count %v", err)
|
||||||
|
}
|
||||||
|
tmpl.ExecuteTemplate(w, "TotalCount", map[string]any{"Count": count, "SwapOOB": true})
|
||||||
|
tmpl.ExecuteTemplate(w, "CompletedCount", map[string]any{"Count": completedCount, "SwapOOB": true})
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleEditTask(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id, err := strconv.Atoi(chi.URLParam(r, "id"))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing id into int %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
task, err := fetchTask(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error fetching task with id %d %v", id, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tmpl.ExecuteTemplate(w, "Item", map[string]any{"Item": task, "Editing": true})
|
||||||
|
}
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -28,5 +28,7 @@ func main() {
|
|||||||
r.Get("/", handleGetTasks)
|
r.Get("/", handleGetTasks)
|
||||||
r.Post("/tasks", handleCreateTask)
|
r.Post("/tasks", handleCreateTask)
|
||||||
r.Put("/tasks/{id}/toggle", handleToggleTask)
|
r.Put("/tasks/{id}/toggle", handleToggleTask)
|
||||||
|
r.Delete("/tasks/{id}", handleDeleteTask)
|
||||||
|
r.Get("/tasks/{id}/edit", handleEditTask)
|
||||||
http.ListenAndServe("localhost:3000", r)
|
http.ListenAndServe("localhost:3000", r)
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
sqlite3.db
BIN
sqlite3.db
Binary file not shown.
@@ -534,6 +534,27 @@ video {
|
|||||||
--tw-backdrop-sepia: ;
|
--tw-backdrop-sepia: ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.absolute {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inset-y-0 {
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-2 {
|
||||||
|
right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-2\.5 {
|
||||||
|
right: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mx-auto {
|
.mx-auto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@@ -595,6 +616,10 @@ video {
|
|||||||
max-width: 768px;
|
max-width: 768px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1 1 0%;
|
||||||
|
}
|
||||||
|
|
||||||
.cursor-move {
|
.cursor-move {
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
@@ -696,6 +721,26 @@ video {
|
|||||||
padding-bottom: 0.625rem;
|
padding-bottom: 0.625rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.px-2 {
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-2\.5 {
|
||||||
|
padding-left: 0.625rem;
|
||||||
|
padding-right: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-1 {
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-1\.5 {
|
||||||
|
padding-top: 0.375rem;
|
||||||
|
padding-bottom: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,47 @@
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
{{ if .Editing }}
|
||||||
|
<form class="flex items-center justify-between flex-1">
|
||||||
|
<div class="relative">
|
||||||
|
<span class="absolute inset-y-0 right-2.5 flex items-center">
|
||||||
|
<button class="text-blue-500 hover:text-blue-700">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-6 h-6"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M4.5 12.75l6 6 9-13.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
name="title"
|
||||||
|
value="{{ .Item.Title }}"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full px-2.5 py-1.5"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{{ else }}
|
||||||
<p class="title">{{ .Item.Title }}</p>
|
<p class="title">{{ .Item.Title }}</p>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center space-x-2.5">
|
<div class="flex items-center space-x-2.5">
|
||||||
<button type="button" class="text-red-500 hover:text-red-700">
|
<button
|
||||||
|
hx-delete="/tasks/{{ .Item.ID }}"
|
||||||
|
hx-target="#task-{{ .Item.ID }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
type="button"
|
||||||
|
class="text-red-500 hover:text-red-700"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -60,7 +96,13 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="edit text-blue-500 hover:text-blue-700">
|
<button
|
||||||
|
hx-get="/tasks/{{ .Item.ID }}/edit"
|
||||||
|
hx-target="#task-{{ .Item.ID }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
type="button"
|
||||||
|
class="edit text-blue-500 hover:text-blue-700"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
fill="none"
|
fill="none"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<div id="items" class="space-y-2.5 mt-4">
|
<div id="items" class="space-y-2.5 mt-4">
|
||||||
{{ range .Items }}
|
{{ range .Items }}
|
||||||
{{ template "Item" dict "Item" . "SwapOOB" false }}
|
{{ template "Item" dict "Item" . "SwapOOB" false "Editing" false }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user