diff --git a/pkg/web/assets/js/board-drag-drop.js b/pkg/web/assets/js/board-drag-drop.js new file mode 100644 index 0000000..fba3bad --- /dev/null +++ b/pkg/web/assets/js/board-drag-drop.js @@ -0,0 +1,68 @@ +/** + * Drag and drop for board view - allows moving issue cards between status columns + */ +(function () { + document.addEventListener("dragstart", function (e) { + if (e.target.closest("button") || e.target.closest("a")) return; + const card = e.target.closest(".board-card"); + if (!card) return; + e.dataTransfer.setData("text/plain", card.dataset.issueId); + e.dataTransfer.effectAllowed = "move"; + card.classList.add("opacity-50"); + }); + + document.addEventListener("dragend", function (e) { + const card = e.target.closest(".board-card"); + if (card) card.classList.remove("opacity-50"); + }); + + document.addEventListener("dragover", function (e) { + const zone = e.target.closest(".column-drop-zone"); + if (!zone) return; + e.preventDefault(); + e.dataTransfer.dropEffect = "move"; + zone.classList.add("ring-2", "ring-primary", "ring-inset"); + }); + + document.addEventListener("dragleave", function (e) { + const zone = e.target.closest(".column-drop-zone"); + if (!zone || zone.contains(e.relatedTarget)) return; + zone.classList.remove("ring-2", "ring-primary", "ring-inset"); + }); + + document.addEventListener("drop", function (e) { + const zone = e.target.closest(".column-drop-zone"); + if (!zone) return; + e.preventDefault(); + zone.classList.remove("ring-2", "ring-primary", "ring-inset"); + const issueId = e.dataTransfer.getData("text/plain"); + const newStatus = zone.dataset.status; + if (!issueId || !newStatus) return; + + const formData = new URLSearchParams(); + formData.append("status", newStatus); + + fetch("/issues/" + issueId + "?from=board", { + method: "PATCH", + body: formData, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "HX-Request": "true", + }, + }).then(function (r) { + if (r.ok) { + var redirect = r.headers.get("HX-Redirect"); + if (redirect) { + window.location.href = redirect; + } else if (typeof htmx !== "undefined") { + htmx.ajax("GET", "/?board=true", { + target: "main", + swap: "innerHTML", + }); + } else { + window.location.href = "/?board=true"; + } + } + }); + }); +})(); diff --git a/pkg/web/components/issue_detail_templ.go b/pkg/web/components/issue_detail_templ.go index 77a3b9b..b9443b2 100644 --- a/pkg/web/components/issue_detail_templ.go +++ b/pkg/web/components/issue_detail_templ.go @@ -148,7 +148,7 @@ func IssueDetail(props IssueDetailProps) templ.Component { return templ_7745c5c3_Err } if props.Issue.Assignee == "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "Unassigned (click to assign)") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "Unassigned (click to assign) ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/pkg/web/routes/boardview.templ b/pkg/web/routes/boardview.templ index 363577b..13927dc 100644 --- a/pkg/web/routes/boardview.templ +++ b/pkg/web/routes/boardview.templ @@ -75,22 +75,22 @@ templ BoardColumns(issues []*models.Issue) { } } }} -
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var15 string - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Description) + var templ_7745c5c3_Var18 string + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Description) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/boardview.templ`, Line: 139, Col: 81} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/boardview.templ`, Line: 143, Col: 81} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "