internal/web/templates/layout.html
246 lines · 20010 bytes
1{{define "layout"}}<!DOCTYPE html>
2<html lang="en"{{with field . "Theme"}} data-theme="{{.}}"{{end}}>
3<head>
4<meta charset="utf-8">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6<title>{{template "title" .}}</title>
7<link rel="stylesheet" href="/static/style.css?v={{styleVersion}}">
8<link rel="icon" href="/favicon.svg" type="image/svg+xml">
9<meta name="theme-color" content="#000000">
10{{with field . "Feed"}}<link rel="alternate" type="application/atom+xml" href="{{.}}">
11{{end}}</head>
12<body>
13<a class="skip" href="#content">Skip to content</a>
14<div class="shell">
15
16<nav class="rail" aria-label="Site">
17 <a class="brand" href="/" aria-label="{{.Site}} home">{{template "mark"}}<span class="vh">{{.Site}}</span></a>
18 {{$items := railOptItems .}}
19 {{/* A square is .railopt when the phone rail drops it into the More
20 menu below. Every one of those destinations — strip, menu and
21 the foot's own Log out link — renders off $items, so the strip
22 and the menu can never drift out of step. */}}
23 <ul class="raillist">
24 {{if .Viewer}}<li>{{template "raillink" dict "Href" "/" "Icon" "home" "Name" "Dashboard" "Current" (eq (str . "Tab") "dashboard")}}</li>{{end}}
25 <li>{{template "raillink" dict "Href" "/explore" "Icon" "compass" "Name" "Explore" "Current" (eq (str . "Tab") "explore")}}</li>
26 <li>{{template "raillink" dict "Href" "/search" "Icon" "search" "Name" "Search" "Current" (eq (str . "Tab") "sitesearch")}}</li>
27 {{if .Viewer}}<li>{{template "raillink" dict "Href" "/notifications" "Icon" "bell" "Name" "Notifications" "Current" (eq (str . "Tab") "notifications") "Count" .Rail.Unread}}</li>
28 <li class="railopt">{{template "raillink" (index $items 0)}}</li>{{end}}
29 </ul>
30 <span class="railgap"></span>
31 <ul class="raillist">
32 {{if .Viewer}}<li class="railopt">{{template "raillink" (index $items 1)}}</li>
33 {{if (index $items 2).Show}}<li class="railopt">{{template "raillink" (index $items 2)}}</li>{{end}}{{end}}
34 </ul>
35 <div class="railfoot">
36 {{if .Viewer}}<details class="railmore">
37 <summary class="railicon" aria-label="More" title="More">{{template "icon" "ellipsis"}}<span class="vh">More</span></summary>
38 <div class="raildrop">
39 {{range $items}}{{if .Show}}<a href="{{.Href}}">{{template "icon" .Icon}} {{.Name}}</a>{{end}}{{end}}
40 </div>
41 </details>
42 <a class="railuser" href="/{{.Viewer}}" aria-label="Your profile" title="{{.Viewer}}"><span class="avatar">{{initial .Viewer}}</span></a>
43 {{$logout := index $items 3}}<a class="railopt railicon" href="{{$logout.Href}}" aria-label="{{$logout.Name}}" title="{{$logout.Name}}">{{template "icon" $logout.Icon}}<span class="vh">{{$logout.Name}}</span></a>
44 {{else}}<a class="railicon" href="/login" aria-label="Sign in" title="Sign in">{{template "icon" "person"}}<span class="vh">Sign in</span></a>{{end}}
45 </div>
46</nav>
47
48<div class="pane">
49{{with field . "Repo"}}
50<header class="repohead">
51<div class="wrap">
52 {{$top := topTab (str $ "Tab")}}
53 <div class="identity">
54 {{if field $ "RepoHome"}}<h1 class="repotitle"><a class="owner" href="/{{.OwnerName}}">{{.OwnerName}}</a><span class="sep">/</span>{{.Name}}</h1>
55 {{else}}<p class="repotitle"><a class="owner" href="/{{.OwnerName}}">{{.OwnerName}}</a><span class="sep">/</span><a href="/{{.OwnerName}}/{{.Name}}">{{.Name}}</a></p>{{end}}
56 {{if eq .Visibility "private"}}<span class="chip">Private</span>{{end}}
57 {{if .Settings.Archived}}<span class="chip">Archived</span>{{end}}
58 {{/* Description, topics and website belong to the code tab, inline
59 with the name so the header is two rows on every page. */}}
60 {{if eq $top "code"}}{{if or (field $ "Desc") (field $ "Topics") $.Repo.Settings.Website}}<p class="repodesc">{{with field $ "Desc"}}{{.}}{{end}} {{with field $ "Topics"}}{{range .}}<a class="chip topic" href="/explore?q={{.}}">{{.}}</a> {{end}}{{end}}{{with $.Repo.Settings.Website}}<a class="site" href="{{.}}" rel="nofollow">{{.}}</a>{{end}}</p>{{end}}{{end}}
61 <span class="grow"></span>
62 {{if $.Viewer}}<form method="post" action="/{{.OwnerName}}/{{.Name}}/pin" class="inline"><button type="submit" class="btn" aria-pressed="{{if field $ "Pinned"}}true{{else}}false{{end}}" title="Pinned repositories show on your dashboard"><span aria-hidden="true">{{if field $ "Pinned"}}★{{else}}☆{{end}}</span> {{if field $ "Pinned"}}Pinned{{else}}Pin{{end}}</button></form>
63 <form method="post" action="/{{.OwnerName}}/{{.Name}}/watch" class="inline"><button type="submit" class="btn" aria-pressed="{{if ne (str $ "Watch") ""}}true{{else}}false{{end}}" title="{{if eq (str $ "Watch") "watching"}}Watching: every issue, request and build. Click to mute.{{else if eq (str $ "Watch") "muted"}}Muted: nothing from this repository. Click to stop muting.{{else}}Only what involves you. Click to watch everything.{{end}}">{{if eq (str $ "Watch") "watching"}}Watching{{else if eq (str $ "Watch") "muted"}}Muted{{else}}Watch{{end}}</button></form>
64 <form method="post" action="/{{.OwnerName}}/{{.Name}}/bookmark" class="inline"><button type="submit" class="btn" aria-pressed="{{if field $ "Marked"}}true{{else}}false{{end}}" title="Bookmarked lists it under Bookmarks">{{if field $ "Marked"}}Bookmarked{{else}}Bookmark{{end}}</button></form>
65 <a class="button btn" href="/{{.OwnerName}}/{{.Name}}/fork">Fork</a>{{end}}
66 </div>
67 {{if eq $top "code"}}{{if field $ "Mirrors"}}<p class="repometa">{{range $i, $m := field $ "Mirrors"}}{{if $i}} · {{end}}{{if eq $m.Direction "push"}}mirrors to{{else}}mirrors from{{end}} <a href="{{$m.URL}}" rel="nofollow">{{$m.Target}}</a>{{if $m.Error}}, <span class="bad">sync error: {{$m.Error}}</span>{{else if $m.Synced}}, synced {{$m.Synced}}{{end}}{{end}}</p>{{end}}{{end}}
68 {{/* A tab's own count badge is omitted at zero (an empty <i> reads as
69 stray punctuation next to the tab word); the dashboard pin row's
70 count chip always shows its number, zero included, the same as
71 every other count chip in the app. Two elements, two rules,
72 decided once here (#270). */}}
73 <nav class="tabs" aria-label="Repository">
74 <a {{if eq $top "code"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}">Code</a>
75 <a {{if eq $top "issues"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/issues">Issues{{with field $ "OpenIssues"}}{{if .}} <i>{{.}}</i>{{end}}{{end}}</a>
76 <a {{if eq $top "mrs"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/mrs">Merge requests{{with field $ "OpenMRs"}}{{if .}} <i>{{.}}</i>{{end}}{{end}}</a>
77 <a {{if eq $top "builds"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/builds">Builds</a>
78 <a {{if eq $top "releases"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/releases">Releases</a>
79 {{if field $ "HasWiki"}}<a {{if eq $top "wiki"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/wiki">Wiki</a>{{end}}
80 {{if field $ "CanAdmin"}}<a {{if eq $top "settings"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/settings">Settings</a>{{end}}
81 </nav>
82</div>
83</header>
84{{end}}
85
86<main id="content" class="content {{template "width" .}}">
87{{template "content" .}}
88</main>
89
90<footer>
91 <p>Powered by <a href="https://gitbay.org/krz/gitbay">gitbay</a>{{with gitbayVersion}} · <code><a href="https://gitbay.org/krz/gitbay/commit/{{gitbayCommit}}">{{.}}</a></code>{{end}} · <a href="https://apps.apple.com/us/app/gitbay/id6806399095">iOS app</a> · <a href="/privacy">Privacy</a></p>
92</footer>
93</div>
94</div>
95</body>
96</html>{{end}}
97
98{{/* icon draws one 16px glyph for the rail. The argument names it. The
99 paths are stroked with currentColor, so a link's own colour and the
100 current marker carry through, and every one is hidden from the
101 accessibility tree — the link around it carries the name. */}}
102{{define "icon"}}<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
103{{- if eq . "home"}}<path d="M2.25 7 8 2.5 13.75 7v6.25a.5.5 0 0 1-.5.5H2.75a.5.5 0 0 1-.5-.5Z"/><path d="M6.25 13.75V9.25h3.5v4.5"/>
104{{- else if eq . "search"}}<circle cx="6.75" cy="6.75" r="4.25"/><path d="m9.9 9.9 3.6 3.6"/>
105{{- else if eq . "bell"}}<path d="M4.25 7a3.75 3.75 0 0 1 7.5 0v2.25l1.25 2.25H3l1.25-2.25Z"/><path d="M6.5 11.5a1.5 1.5 0 0 0 3 0"/>
106{{- else if eq . "bookmark"}}<path d="M4 2.75h8v11L8 10.5l-4 3.25Z"/>
107{{- else if eq . "compass"}}<circle cx="8" cy="8" r="6"/><path d="m10.5 5.5-1.25 3.75-3.75 1.25 1.25-3.75Z"/>
108{{- else if eq . "plus"}}<path d="M8 3.25v9.5M3.25 8h9.5"/>
109{{- else if eq . "gear"}}<path d="M6.63 1.13L9.37 1.13L9.51 3.02L10.45 3.41L11.89 2.18L13.82 4.11L12.59 5.55L12.98 6.49L14.87 6.63L14.87 9.37L12.98 9.51L12.59 10.45L13.82 11.89L11.89 13.82L10.45 12.59L9.51 12.98L9.37 14.87L6.63 14.87L6.49 12.98L5.55 12.59L4.11 13.82L2.18 11.89L3.41 10.45L3.02 9.51L1.13 9.37L1.13 6.63L3.02 6.49L3.41 5.55L2.18 4.11L4.11 2.18L5.55 3.41L6.49 3.02Z"/><circle cx="8" cy="8" r="2.2"/>
110{{- else if eq . "shield"}}<path d="M8 1.75 13 3.5v4.25c0 3.1-2 5.4-5 6.5-3-1.1-5-3.4-5-6.5V3.5Z"/><path d="m5.9 7.75 1.6 1.6 2.85-3.1"/>
111{{- else if eq . "signout"}}<path d="M6.5 2.25H3.25a1 1 0 0 0-1 1v9.5a1 1 0 0 0 1 1H6.5"/><path d="M7.75 8h6M11.25 5.5 13.75 8l-2.5 2.5"/>
112{{- else if eq . "ellipsis"}}<circle cx="3.25" cy="8" r="1.1" fill="currentColor" stroke="none"/><circle cx="8" cy="8" r="1.1" fill="currentColor" stroke="none"/><circle cx="12.75" cy="8" r="1.1" fill="currentColor" stroke="none"/>
113{{- else if eq . "snippet"}}<path d="M3.25 2.75h6L12.75 6v7.25a.5.5 0 0 1-.5.5H3.75a.5.5 0 0 1-.5-.5Z"/><path d="M9 2.75V6h3.75"/><path d="m6.75 8.75-1.5 1.5 1.5 1.5M9.75 8.75l1.5 1.5-1.5 1.5"/>
114{{- else if eq . "person"}}<circle cx="8" cy="5.5" r="2.75"/><path d="M2.75 14a5.25 5.25 0 0 1 10.5 0"/>
115{{- else if eq . "folder"}}<path d="M1.75 3.25h4l1.5 1.75h6.5v7.5a.5.5 0 0 1-.5.5H2.25a.5.5 0 0 1-.5-.5Z"/>
116{{- else if eq . "file"}}<path d="M3.25 2.75h6L12.75 6v7.25a.5.5 0 0 1-.5.5H3.75a.5.5 0 0 1-.5-.5Z"/><path d="M9 2.75V6h3.75"/>
117{{- end}}</svg>{{end}}
118
119{{/* raillink draws one square in the rail: the icon, the name for a
120 screen reader and in the tooltip, and the bell's unread badge. */}}
121{{define "raillink"}}<a class="railicon" {{if .Current}}aria-current="page" {{end}}href="{{.Href}}" aria-label="{{.Name}}" title="{{.Name}}">{{template "icon" .Icon}}<span class="vh">{{.Name}}</span>{{with .Count}}<b class="count">{{.}}</b>{{end}}</a>{{end}}
122
123{{define "mark"}}<svg class="mark" width="19" height="19" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.25 18.75 12H5.25z" fill="#ff6b3d"/><rect x="3" y="13.5" width="18" height="3" fill="currentColor"/><rect x="7.5" y="18" width="9" height="3" fill="currentColor"/></svg>{{end}}
124{{define "width"}}reading{{end}}
125
126{{define "reporow"}}<li>
127 <p class="reponame"><a href="/{{.OwnerName}}/{{.Name}}">{{.OwnerName}}<span class="sep">/</span><strong>{{.Name}}</strong></a>{{if eq .Visibility "private"}} <span class="chip">Private</span>{{end}}{{if .Archived}} <span class="chip">Archived</span>{{end}}</p>
128 {{if .Desc}}<p class="desc">{{.Desc}}</p>{{end}}
129 {{if .Topics}}<p class="topics">{{range .Topics}}<a class="chip topic" href="/explore?q={{.}}">{{.}}</a> {{end}}</p>{{end}}
130 <p class="meta">{{template "branchicon"}} {{.DefaultBranch}}{{if .License}} · {{.License}}{{end}}{{if .Updated}} · updated {{.Updated}}{{end}}</p>
131</li>{{end}}
132
133{{define "refmenu"}}{{if .Branches}}<details class="refmenu">
134 <summary class="refchip">{{template "branchicon"}} {{.Ref}}</summary>
135 <div class="refdrop">
136 {{range .Branches}}<a href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/{{$.RefKind}}/{{.Name}}/{{$.DirPath}}">{{.Name}}</a>
137 {{end}}<a class="allrefs" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/refs">All refs →</a>
138 </div>
139</details>{{else}}<span class="refchip">{{template "branchicon"}} {{.Ref}}</span>{{end}}{{end}}
140
141{{define "filenav"}}<nav class="filenav" aria-label="Files">
142 <h2 class="colhead">{{.Title}}</h2>
143 <ul>
144 {{with .Parent}}<li><a class="up" href="{{.}}">..</a></li>{{end}}
145 {{range .Entries}}<li><a{{if .Dir}} class="dir"{{end}}{{if .Current}} aria-current="page"{{end}} href="{{.URL}}">{{.Name}}</a></li>
146 {{end}}</ul>
147</nav>{{end}}
148
149{{/* Every side column's groups sit in a details.sidedrop. Below 62rem
150 that disclosure is what the reader sees of the column: one closed
151 line they open. Above it style.css hides the summary and shows the
152 content whatever the open state, so the column reads as it always
153 has (#237). The facet columns name the filters in force in the
154 summary; the section navs head with the word alone. */}}
155{{define "sidecol"}}<nav class="sidecol" aria-label="Filters">
156<details class="sidedrop">
157<summary><span class="sideword">Filters</span>{{range .}}{{range .Items}}{{if .Active}} <span class="sideon">{{.Label}}</span>{{end}}{{end}}{{end}}</summary>
158 {{range .}}{{if .Items}}<div class="grp">
159 <h2 class="colhead">{{.Title}}</h2>
160 <ul>{{range .Items}}<li><a{{if .Active}} aria-current="page"{{end}} href="{{.Href}}">{{.Label}}{{if .Count}} <i>{{.Count}}</i>{{end}}</a></li>{{end}}</ul>
161 </div>{{end}}{{end}}
162</details>
163</nav>{{end}}
164
165{{define "branchicon"}}<svg class="icon" width="12" height="12" viewBox="0 0 16 16" aria-hidden="true" fill="currentColor"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628a2.25 2.25 0 0 1-1.5-2.122ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM3.5 3.25a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"/></svg>{{end}}
166
167{{define "sigbadge"}}<span class="badge badge-{{.State}}" title="{{.Fingerprint}}">{{sigLabel .State}}{{if .Signer}} · {{.Signer}}{{end}}</span>{{end}}
168
169{{define "authorname"}}{{if .User}}<a class="authorlink" href="/{{.User}}" title="{{.Email}}">{{.Name}}</a>{{else}}<span title="{{.Email}}">{{.Name}}</span>{{end}}{{end}}
170
171{{/* formatpicker is the md/org choice on a body: issue and MR create.
172 The argument is the currently selected format; empty selects
173 Markdown, today's default. */}}
174{{define "formatpicker"}}<p class="branchpick">
175 <label for="format">Body markup</label>
176 <select id="format" name="format">
177 <option value="md"{{if ne . "org"}} selected{{end}}>Markdown</option>
178 <option value="org"{{if eq . "org"}} selected{{end}}>Org</option>
179 </select>
180</p>{{end}}
181
182{{/* previewbtn is the Preview submit beside a markup form's own submit.
183 It posts the form to its usual action, which renders the body and
184 hands the page back instead of writing (#235). */}}
185{{define "previewbtn"}}<button type="submit" name="preview" value="1" class="btn">Preview</button>{{end}}
186
187{{/* previewblock shows a draft as it will read. The argument is the
188 rendered HTML; it sits above the textarea it came from. */}}
189{{define "previewblock"}}<div class="preview">
190 <p class="previewmark">Preview</p>
191 <div class="rendered">{{.}}</div>
192</div>{{end}}
193
194{{/* confirmfield is the typed-name check beside a destructive control.
195 The argument is the text the person must type. */}}
196{{define "confirmfield"}}<input type="text" name="confirm" aria-label="Type {{.}} to confirm" placeholder="type {{.}} to confirm" size="{{len .}}" autocomplete="off">{{end}}
197
198{{/* difffiles renders a parsed diff: one foldable section per file, with
199 line-number gutters and review threads inline. Base is the MR's
200 endpoint and Viewer the signed-in account; the commit page passes
201 neither and gets the same diff without review controls. */}}
202{{define "difffiles"}}{{$base := .Base}}{{$viewer := .Viewer}}
203{{range $fi, $f := .Files}}<details class="difffold" id="f{{$fi}}"{{if .Open}} open{{end}}>
204 <summary>
205 <span class="fpath">{{if eq .Status "renamed"}}<span class="was">{{.OldPath}} →</span> {{end}}{{.Path}}</span>
206 {{if ne .Status "modified"}}<span class="chip">{{.Status}}</span>{{end}}
207 <span class="fstat">{{if .Adds}}<span class="add">+{{.Adds}}</span>{{end}}{{if .Dels}} <span class="del">−{{.Dels}}</span>{{end}}</span>
208 </summary>
209 {{if .Binary}}<p class="none">Binary file not shown.</p>
210 {{else}}<div class="tablewrap"><table class="difftable">
211 {{range .Lines}}{{if eq .Class "hunk"}}<tr class="hunk"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr>
212 {{else if eq .Class "meta"}}<tr class="dmeta"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr>
213 {{else}}<tr class="{{.Class}}" id="f{{$fi}}-{{if eq .Class "del"}}o{{.OldLine}}{{else}}n{{.NewLine}}{{end}}"><td class="ln">{{if .OldLine}}{{if eq .Class "del"}}{{template "cmtln" dict "N" .OldLine "Path" .Path "Side" "old" "Base" $base "Viewer" $viewer}}{{else}}{{.OldLine}}{{end}}{{end}}</td><td class="ln">{{if .NewLine}}{{template "cmtln" dict "N" .NewLine "Path" .Path "Side" "new" "Base" $base "Viewer" $viewer}}{{end}}</td><td class="src chroma">{{if .Code}}{{.Code}}{{else}}{{.Content}}{{end}}</td></tr>
214 {{if .Compose}}<tr class="threadrow"><td colspan="3"><form id="compose" method="post" action="{{$base}}/diff-comment" class="thread composing">
215 <input type="hidden" name="path" value="{{.Path}}">
216 <input type="hidden" name="line" value="{{if eq .Class "del"}}{{.OldLine}}{{else}}{{.NewLine}}{{end}}">
217 <input type="hidden" name="side" value="{{if eq .Class "del"}}old{{else}}new{{end}}">
218 <p><textarea name="body" aria-label="Comment on {{.Path}}" rows="3" placeholder="Comment on this line" autofocus></textarea></p>
219 <p><button type="submit" class="btn">Comment</button>
220 <button type="submit" name="pending" value="on" class="btn">Add to review</button>
221 <a href="{{$base}}?view=diff">Cancel</a></p>
222 </form></td></tr>
223 {{end}}{{end}}{{range .Threads}}<tr class="threadrow"><td colspan="3">{{template "thread" dict "T" . "Base" $base "Viewer" $viewer "Class" ""}}</td></tr>
224 {{end}}{{end}}
225 </table></div>{{end}}
226</details>
227{{end}}{{end}}
228
229{{/* cmtln turns a line number into the link that opens the comment form
230 on that line. No JavaScript: the anchor travels in the query. */}}
231{{define "cmtln"}}{{if and .Viewer .Base}}<a class="cmt" aria-label="Comment on line {{.N}}" title="Comment on this line" href="{{.Base}}?view=diff&cpath={{.Path}}&cline={{.N}}&cside={{.Side}}#compose">{{.N}}</a>{{else}}{{.N}}{{end}}{{end}}
232
233{{/* thread renders one review thread with its reply and resolve controls.
234 Class carries "stale" for threads whose anchor is gone. */}}
235{{define "thread"}}{{$t := .T}}<div class="thread{{if $t.Resolved}} resolved{{end}}{{if $t.Pending}} pending{{end}}{{if .Class}} {{.Class}}{{end}}" id="thread-{{$t.ID}}">
236{{if $t.Pending}}<p class="threadstate">pending — only you can see this until you submit your review</p>{{end}}
237{{if or $t.Resolved (and .Class $t.Stale)}}<p class="threadstate">{{if and .Class $t.Stale}}stale{{end}}{{if $t.Resolved}}{{if and .Class $t.Stale}} · {{end}}resolved by {{$t.Resolved}}{{end}}</p>{{end}}
238{{range $t.Comments}}<p class="commenthead"><strong>{{.Author}}</strong> <span class="when">{{when .CreatedAt}}</span></p><div class="rendered">{{.BodyHTML}}</div>{{end}}
239{{if .Viewer}}<details class="threadreply"><summary>Reply</summary>
240<form method="post" action="{{.Base}}/diff-comment">
241 <input type="hidden" name="reply" value="{{$t.ID}}">
242 <p><textarea name="body" aria-label="Reply to thread {{$t.ID}}" rows="2" placeholder="Reply as {{.Viewer}}"></textarea></p>
243 <p><button type="submit" class="btn">Reply</button></p>
244</form></details>{{end}}
245{{if $t.CanResolve}}<form method="post" action="{{.Base}}/thread" class="threadact"><input type="hidden" name="thread" value="{{$t.ID}}"><button type="submit" name="action" value="{{if $t.Resolved}}unresolve{{else}}resolve{{end}}" class="linklike">{{if $t.Resolved}}Reopen thread{{else}}Resolve thread{{end}}</button></form>{{end}}
246</div>{{end}}