internal/web/templates/layout.html
241 lines · 19570 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{{with field . "Feed"}}<link rel="alternate" type="application/atom+xml" href="{{.}}">
10{{end}}</head>
11<body>
12<a class="skip" href="#content">Skip to content</a>
13<div class="shell">
14
15<nav class="rail" aria-label="Site">
16 <a class="brand" href="/" aria-label="{{.Site}} home">{{template "mark"}}<span class="vh">{{.Site}}</span></a>
17 {{/* A square is .railopt when the phone rail drops it into the More
18 menu below. The menu repeats those destinations, so the two lists
19 are kept in step by hand: add a square there and add it here. */}}
20 <ul class="raillist">
21 {{if .Viewer}}<li>{{template "raillink" dict "Href" "/" "Icon" "home" "Name" "Dashboard" "Current" (eq (str . "Tab") "dashboard")}}</li>{{end}}
22 <li>{{template "raillink" dict "Href" "/explore" "Icon" "compass" "Name" "Explore" "Current" (eq (str . "Tab") "explore")}}</li>
23 <li>{{template "raillink" dict "Href" "/search" "Icon" "search" "Name" "Search" "Current" (eq (str . "Tab") "sitesearch")}}</li>
24 {{if .Viewer}}<li>{{template "raillink" dict "Href" "/notifications" "Icon" "bell" "Name" "Notifications" "Current" (eq (str . "Tab") "notifications") "Count" .Rail.Unread}}</li>
25 <li class="railopt">{{template "raillink" dict "Href" "/new" "Icon" "plus" "Name" "New repository"}}</li>{{end}}
26 </ul>
27 <span class="railgap"></span>
28 <ul class="raillist">
29 {{if .Viewer}}<li class="railopt">{{template "raillink" dict "Href" "/settings" "Icon" "gear" "Name" "Settings" "Current" (eq (str . "Tab") "account")}}</li>{{end}}
30 {{if .Admin}}<li class="railopt">{{template "raillink" dict "Href" "/admin" "Icon" "shield" "Name" "Admin" "Current" (eq (str . "Tab") "admin")}}</li>{{end}}
31 </ul>
32 <div class="railfoot">
33 {{if .Viewer}}<details class="railmore">
34 <summary class="railicon" aria-label="More" title="More">{{template "icon" "ellipsis"}}<span class="vh">More</span></summary>
35 <div class="raildrop">
36 <a href="/new">{{template "icon" "plus"}} New repository</a>
37 <a href="/settings">{{template "icon" "gear"}} Settings</a>
38 {{if .Admin}}<a href="/admin">{{template "icon" "shield"}} Admin</a>{{end}}
39 <a href="/logout">{{template "icon" "signout"}} Log out</a>
40 </div>
41 </details>
42 <a class="railuser" href="/{{.Viewer}}" aria-label="Your profile" title="{{.Viewer}}"><span class="avatar">{{initial .Viewer}}</span></a>
43 <a class="railopt railicon" href="/logout" aria-label="Log out" title="Log out">{{template "icon" "signout"}}<span class="vh">Log out</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 eq (str $ "Watch") "watching"}}true{{else}}false{{end}}" title="Watching sends every issue, request and build to your inbox">{{if eq (str $ "Watch") "watching"}}Watching{{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 <nav class="tabs" aria-label="Repository">
69 <a {{if eq $top "code"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}">Code</a>
70 <a {{if eq $top "issues"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/issues">Issues{{with field $ "OpenIssues"}}{{if .}} <i>{{.}}</i>{{end}}{{end}}</a>
71 <a {{if eq $top "mrs"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/mrs">Merge requests{{with field $ "OpenMRs"}}{{if .}} <i>{{.}}</i>{{end}}{{end}}</a>
72 <a {{if eq $top "builds"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/builds">Builds</a>
73 <a {{if eq $top "releases"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/releases">Releases</a>
74 {{if field $ "HasWiki"}}<a {{if eq $top "wiki"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/wiki">Wiki</a>{{end}}
75 {{if field $ "CanAdmin"}}<a {{if eq $top "settings"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/settings">Settings</a>{{end}}
76 </nav>
77</div>
78</header>
79{{end}}
80
81<main id="content" class="content {{template "width" .}}">
82{{template "content" .}}
83</main>
84
85<footer>
86 <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://gitbay.org/krz/gitbay-ios">iOS app</a> · <a href="/privacy">Privacy</a></p>
87</footer>
88</div>
89</div>
90</body>
91</html>{{end}}
92
93{{/* icon draws one 16px glyph for the rail. The argument names it. The
94 paths are stroked with currentColor, so a link's own colour and the
95 current marker carry through, and every one is hidden from the
96 accessibility tree — the link around it carries the name. */}}
97{{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">
98{{- 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"/>
99{{- else if eq . "search"}}<circle cx="6.75" cy="6.75" r="4.25"/><path d="m9.9 9.9 3.6 3.6"/>
100{{- 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"/>
101{{- else if eq . "bookmark"}}<path d="M4 2.75h8v11L8 10.5l-4 3.25Z"/>
102{{- 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"/>
103{{- else if eq . "plus"}}<path d="M8 3.25v9.5M3.25 8h9.5"/>
104{{- 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"/>
105{{- 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"/>
106{{- 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"/>
107{{- 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"/>
108{{- 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"/>
109{{- 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"/>
110{{- 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"/>
111{{- 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"/>
112{{- end}}</svg>{{end}}
113
114{{/* raillink draws one square in the rail: the icon, the name for a
115 screen reader and in the tooltip, and the bell's unread badge. */}}
116{{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}}
117
118{{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}}
119{{define "width"}}reading{{end}}
120
121{{define "reporow"}}<li>
122 <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>
123 {{if .Desc}}<p class="desc">{{.Desc}}</p>{{end}}
124 {{if .Topics}}<p class="topics">{{range .Topics}}<a class="chip topic" href="/explore?q={{.}}">{{.}}</a> {{end}}</p>{{end}}
125 <p class="meta">{{template "branchicon"}} {{.DefaultBranch}}{{if .License}} · {{.License}}{{end}}{{if .Updated}} · updated {{.Updated}}{{end}}</p>
126</li>{{end}}
127
128{{define "refmenu"}}{{if .Branches}}<details class="refmenu">
129 <summary class="refchip">{{template "branchicon"}} {{.Ref}}</summary>
130 <div class="refdrop">
131 {{range .Branches}}<a href="/{{$.Repo.OwnerName}}/{{$.Repo.Name}}/{{$.RefKind}}/{{.Name}}/{{$.DirPath}}">{{.Name}}</a>
132 {{end}}<a class="allrefs" href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/refs">All refs →</a>
133 </div>
134</details>{{else}}<span class="refchip">{{template "branchicon"}} {{.Ref}}</span>{{end}}{{end}}
135
136{{define "filenav"}}<nav class="filenav" aria-label="Files">
137 <h2 class="colhead">{{.Title}}</h2>
138 <ul>
139 {{with .Parent}}<li><a class="up" href="{{.}}">..</a></li>{{end}}
140 {{range .Entries}}<li><a{{if .Dir}} class="dir"{{end}}{{if .Current}} aria-current="page"{{end}} href="{{.URL}}">{{.Name}}</a></li>
141 {{end}}</ul>
142</nav>{{end}}
143
144{{/* Every side column's groups sit in a details.sidedrop. Below 62rem
145 that disclosure is what the reader sees of the column: one closed
146 line they open. Above it style.css hides the summary and shows the
147 content whatever the open state, so the column reads as it always
148 has (#237). The facet columns name the filters in force in the
149 summary; the section navs head with the word alone. */}}
150{{define "sidecol"}}<nav class="sidecol" aria-label="Filters">
151<details class="sidedrop">
152<summary><span class="sideword">Filters</span>{{range .}}{{range .Items}}{{if .Active}} <span class="sideon">{{.Label}}</span>{{end}}{{end}}{{end}}</summary>
153 {{range .}}{{if .Items}}<div class="grp">
154 <h2 class="colhead">{{.Title}}</h2>
155 <ul>{{range .Items}}<li><a{{if .Active}} aria-current="page"{{end}} href="{{.Href}}">{{.Label}}{{if .Count}} <i>{{.Count}}</i>{{end}}</a></li>{{end}}</ul>
156 </div>{{end}}{{end}}
157</details>
158</nav>{{end}}
159
160{{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}}
161
162{{define "sigbadge"}}<span class="badge badge-{{.State}}" title="{{.Fingerprint}}">{{sigLabel .State}}{{if .Signer}} · {{.Signer}}{{end}}</span>{{end}}
163
164{{define "authorname"}}{{if .User}}<a class="authorlink" href="/{{.User}}" title="{{.Email}}">{{.Name}}</a>{{else}}<span title="{{.Email}}">{{.Name}}</span>{{end}}{{end}}
165
166{{/* formatpicker is the md/org choice on a body: issue and MR create.
167 The argument is the currently selected format; empty selects
168 Markdown, today's default. */}}
169{{define "formatpicker"}}<p class="branchpick">
170 <label for="format">Body markup</label>
171 <select id="format" name="format">
172 <option value="md"{{if ne . "org"}} selected{{end}}>Markdown</option>
173 <option value="org"{{if eq . "org"}} selected{{end}}>Org</option>
174 </select>
175</p>{{end}}
176
177{{/* previewbtn is the Preview submit beside a markup form's own submit.
178 It posts the form to its usual action, which renders the body and
179 hands the page back instead of writing (#235). */}}
180{{define "previewbtn"}}<button type="submit" name="preview" value="1" class="btn">Preview</button>{{end}}
181
182{{/* previewblock shows a draft as it will read. The argument is the
183 rendered HTML; it sits above the textarea it came from. */}}
184{{define "previewblock"}}<div class="preview">
185 <p class="previewmark">Preview</p>
186 <div class="rendered">{{.}}</div>
187</div>{{end}}
188
189{{/* confirmfield is the typed-name check beside a destructive control.
190 The argument is the text the person must type. */}}
191{{define "confirmfield"}}<input type="text" name="confirm" aria-label="Type {{.}} to confirm" placeholder="type {{.}} to confirm" size="{{len .}}" autocomplete="off">{{end}}
192
193{{/* difffiles renders a parsed diff: one foldable section per file, with
194 line-number gutters and review threads inline. Base is the MR's
195 endpoint and Viewer the signed-in account; the commit page passes
196 neither and gets the same diff without review controls. */}}
197{{define "difffiles"}}{{$base := .Base}}{{$viewer := .Viewer}}
198{{range $fi, $f := .Files}}<details class="difffold" id="f{{$fi}}"{{if .Open}} open{{end}}>
199 <summary>
200 <span class="fpath">{{if eq .Status "renamed"}}<span class="was">{{.OldPath}} →</span> {{end}}{{.Path}}</span>
201 {{if ne .Status "modified"}}<span class="chip">{{.Status}}</span>{{end}}
202 <span class="fstat">{{if .Adds}}<span class="add">+{{.Adds}}</span>{{end}}{{if .Dels}} <span class="del">−{{.Dels}}</span>{{end}}</span>
203 </summary>
204 {{if .Binary}}<p class="none">Binary file not shown.</p>
205 {{else}}<div class="tablewrap"><table class="difftable">
206 {{range .Lines}}{{if eq .Class "hunk"}}<tr class="hunk"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr>
207 {{else if eq .Class "meta"}}<tr class="dmeta"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr>
208 {{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>
209 {{if .Compose}}<tr class="threadrow"><td colspan="3"><form id="compose" method="post" action="{{$base}}/diff-comment" class="thread composing">
210 <input type="hidden" name="path" value="{{.Path}}">
211 <input type="hidden" name="line" value="{{if eq .Class "del"}}{{.OldLine}}{{else}}{{.NewLine}}{{end}}">
212 <input type="hidden" name="side" value="{{if eq .Class "del"}}old{{else}}new{{end}}">
213 <p><textarea name="body" aria-label="Comment on {{.Path}}" rows="3" placeholder="Comment on this line" autofocus></textarea></p>
214 <p><button type="submit" class="btn">Comment</button>
215 <button type="submit" name="pending" value="on" class="btn">Add to review</button>
216 <a href="{{$base}}?view=diff">Cancel</a></p>
217 </form></td></tr>
218 {{end}}{{end}}{{range .Threads}}<tr class="threadrow"><td colspan="3">{{template "thread" dict "T" . "Base" $base "Viewer" $viewer "Class" ""}}</td></tr>
219 {{end}}{{end}}
220 </table></div>{{end}}
221</details>
222{{end}}{{end}}
223
224{{/* cmtln turns a line number into the link that opens the comment form
225 on that line. No JavaScript: the anchor travels in the query. */}}
226{{define "cmtln"}}{{if and .Viewer .Base}}<a class="cmt" title="Comment on this line" href="{{.Base}}?view=diff&cpath={{.Path}}&cline={{.N}}&cside={{.Side}}#compose">{{.N}}</a>{{else}}{{.N}}{{end}}{{end}}
227
228{{/* thread renders one review thread with its reply and resolve controls.
229 Class carries "stale" for threads whose anchor is gone. */}}
230{{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}}">
231{{if $t.Pending}}<p class="threadstate">pending — only you can see this until you submit your review</p>{{end}}
232{{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}}
233{{range $t.Comments}}<p class="commenthead"><strong>{{.Author}}</strong> <span class="when">{{when .CreatedAt}}</span></p><div class="rendered">{{.BodyHTML}}</div>{{end}}
234{{if .Viewer}}<details class="threadreply"><summary>Reply</summary>
235<form method="post" action="{{.Base}}/diff-comment">
236 <input type="hidden" name="reply" value="{{$t.ID}}">
237 <p><textarea name="body" aria-label="Reply to thread {{$t.ID}}" rows="2" placeholder="Reply as {{.Viewer}}"></textarea></p>
238 <p><button type="submit" class="btn">Reply</button></p>
239</form></details>{{end}}
240{{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}}
241</div>{{end}}