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})
|
||||
}
|
||||
|
||||
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.Post("/tasks", handleCreateTask)
|
||||
r.Put("/tasks/{id}/toggle", handleToggleTask)
|
||||
r.Delete("/tasks/{id}", handleDeleteTask)
|
||||
r.Get("/tasks/{id}/edit", handleEditTask)
|
||||
http.ListenAndServe("localhost:3000", r)
|
||||
}
|
||||
|
||||
BIN
sqlite3.db
BIN
sqlite3.db
Binary file not shown.
@@ -534,6 +534,27 @@ video {
|
||||
--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 {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
@@ -595,6 +616,10 @@ video {
|
||||
max-width: 768px;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1 1 0%;
|
||||
}
|
||||
|
||||
.cursor-move {
|
||||
cursor: move;
|
||||
}
|
||||
@@ -696,6 +721,26 @@ video {
|
||||
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-align: center;
|
||||
}
|
||||
|
||||
@@ -39,11 +39,47 @@
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<p class="title">{{ .Item.Title }}</p>
|
||||
{{ 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>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<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
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
@@ -60,7 +96,13 @@
|
||||
</svg>
|
||||
</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
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<div id="items" class="space-y-2.5 mt-4">
|
||||
{{ range .Items }}
|
||||
{{ template "Item" dict "Item" . "SwapOOB" false }}
|
||||
{{ template "Item" dict "Item" . "SwapOOB" false "Editing" false }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user