Merge pull request #60 from LazyBachelor/LPM-121

adding double-click edit for issues on web
This commit is contained in:
Robin Olsen
2026-03-16 02:13:43 -07:00
committed by GitHub
5 changed files with 37 additions and 36 deletions

View File

@@ -0,0 +1,19 @@
/**
* Open edit-issue modal when double-clicking a row in the issue list (list view).
* Uses event delegation and preventDefault so double-click doesn't select text.
*/
(function () {
document.addEventListener("dblclick", function (e) {
var row = e.target.closest("tr[data-issue-id]");
if (!row) return;
e.preventDefault();
var id = row.getAttribute("data-issue-id");
if (!id) return;
if (typeof htmx !== "undefined") {
htmx.ajax("GET", "/issues/" + id + "/edit", {
target: "#modal-container",
swap: "innerHTML",
});
}
});
})();

View File

@@ -135,20 +135,13 @@ templ DashboardIssueRows(issues []*models.Issue, selectedID string) {
}} }}
<tr <tr
hx-get="/" hx-get="/"
class={ "hover cursor-pointer min-h-full w-full", active } hx-trigger="click delay:400ms cancel:dblclick"
class={ "hover cursor-pointer min-h-full w-full select-none", active }
hx-target="main" hx-target="main"
hx-vals={ `{"selected-issue": "` + issue.ID + `"}` } hx-vals={ `{"selected-issue": "` + issue.ID + `"}` }
hx-swap="innerHTML" hx-swap="innerHTML"
data-issue-id={ issue.ID } data-issue-id={ issue.ID }
> >
<button
type="button"
class="hidden"
hx-get={ "/issues/" + issue.ID + "/edit" }
hx-target="#modal-container"
hx-swap="innerHTML"
hx-trigger="dblclick from:closest tr"
></button>
<td class="min-w-20 truncate">{ issue.ID }</td> <td class="min-w-20 truncate">{ issue.ID }</td>
<td class="truncate max-w-60">{ issue.Title }</td> <td class="truncate max-w-60">{ issue.Title }</td>
<td> <td>

View File

@@ -278,12 +278,12 @@ func DashboardIssueRows(issues []*models.Issue, selectedID string) templ.Compone
if selectedID == issue.ID { if selectedID == issue.ID {
active = "bg-primary/10" active = "bg-primary/10"
} }
var templ_7745c5c3_Var9 = []any{"hover cursor-pointer min-h-full w-full", active} var templ_7745c5c3_Var9 = []any{"hover cursor-pointer min-h-full w-full select-none", active}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...) templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<tr hx-get=\"/\" class=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<tr hx-get=\"/\" hx-trigger=\"click delay:400ms cancel:dblclick\" class=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -303,7 +303,7 @@ func DashboardIssueRows(issues []*models.Issue, selectedID string) templ.Compone
var templ_7745c5c3_Var11 string var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(`{"selected-issue": "` + issue.ID + `"}`) templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(`{"selected-issue": "` + issue.ID + `"}`)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 140, Col: 53} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 141, Col: 53}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@@ -316,52 +316,39 @@ func DashboardIssueRows(issues []*models.Issue, selectedID string) templ.Compone
var templ_7745c5c3_Var12 string var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID) templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 142, Col: 27} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 143, Col: 27}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\"><button type=\"button\" class=\"hidden\" hx-get=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "\"><td class=\"min-w-20 truncate\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var13 string var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs("/issues/" + issue.ID + "/edit") templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 147, Col: 44} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 145, Col: 43}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\" hx-target=\"#modal-container\" hx-swap=\"innerHTML\" hx-trigger=\"dblclick from:closest tr\"></button><td class=\"min-w-20 truncate\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</td><td class=\"truncate max-w-60\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var14 string var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID) templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Title)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 152, Col: 43} return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 146, Col: 46}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</td><td class=\"truncate max-w-60\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</td><td>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/routes/dashboard.templ`, Line: 153, Col: 46}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</td><td>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -369,7 +356,7 @@ func DashboardIssueRows(issues []*models.Issue, selectedID string) templ.Compone
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</td><td>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</td><td>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -377,7 +364,7 @@ func DashboardIssueRows(issues []*models.Issue, selectedID string) templ.Compone
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</td><td>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</td><td>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -385,7 +372,7 @@ func DashboardIssueRows(issues []*models.Issue, selectedID string) templ.Compone
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</td></tr>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</td></tr>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

View File

@@ -15,6 +15,7 @@ var baseLayout = components.LayoutProps{
{Src: "/assets/js/htmx.min.js", Defer: true}, {Src: "/assets/js/htmx.min.js", Defer: true},
{Src: "/assets/js/alpine.min.js", Defer: true}, {Src: "/assets/js/alpine.min.js", Defer: true},
{Src: "/assets/js/board-drag-drop.js", Defer: true}, {Src: "/assets/js/board-drag-drop.js", Defer: true},
{Src: "/assets/js/issue-list-dblclick.js", Defer: true},
}, },
}, },
Routes: []components.NavRoutes{ Routes: []components.NavRoutes{

View File

@@ -23,6 +23,7 @@ var baseLayout = components.LayoutProps{
{Src: "/assets/js/htmx.min.js", Defer: true}, {Src: "/assets/js/htmx.min.js", Defer: true},
{Src: "/assets/js/alpine.min.js", Defer: true}, {Src: "/assets/js/alpine.min.js", Defer: true},
{Src: "/assets/js/board-drag-drop.js", Defer: true}, {Src: "/assets/js/board-drag-drop.js", Defer: true},
{Src: "/assets/js/issue-list-dblclick.js", Defer: true},
}, },
}, },
Routes: []components.NavRoutes{ Routes: []components.NavRoutes{