inbox.templ RawHistoryFolder
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5// Inbox is the owner's inbox: what is open across every repository. The
6// counters, the filter and the lists are fragments with an id that the live
7// stream replaces as a whole (ermiteLive.swap).
8templ Inbox(l Layout, p InboxPage) {
9 @Shell(l, nil) {
10 <h1 class="sr">Inbox</h1>
11 <div class="inbox">
12 @InboxCounters(p)
13 @InboxRepos(p)
14 @InboxPending(p)
15 @InboxMRs(p)
16 @InboxIssues(p)
17 </div>
18 }
19}
20
21templ InboxCounters(p InboxPage) {
22 <p id="inbox-counts" class="inbox-counts">
23 <strong>{ itoa(p.MergeRequests) }</strong> merge requests · <strong>{ itoa(p.Issues) }</strong> issues · <strong>{ itoa(p.PendingCount) }</strong> awaiting moderation
24 </p>
25}
26
27templ InboxRepos(p InboxPage) {
28 <nav id="inbox-repos" class="since" aria-label="Repository">
29 for _, r := range p.Repos {
30 <a
31 href={ templ.SafeURL(r.Href) }
32 if r.Current {
33 aria-current="page"
34 }
35 >{ r.Label }</a>
36 }
37 </nav>
38}
39
40// InboxPending is the issues awaiting moderation, first on the page. Their
41// texts come from anonymous visitors: they are shown as plain text, escaped,
42// never as Markdown.
43templ InboxPending(p InboxPage) {
44 <section id="inbox-pending" aria-labelledby="inbox-pending-h">
45 <h2 id="inbox-pending-h" class="rule-h"><span>Awaiting moderation</span><span class="count">{ itoa(p.PendingCount) }</span></h2>
46 if len(p.Pending) > 0 {
47 <ul class="pending-list">
48 for _, m := range p.Pending {
49 <li class="pending">
50 <div class="p-head">
51 <a href={ templ.SafeURL(m.RepoHref) }>{ m.Repo }</a>
52 <span>{ m.Author }</span>
53 if m.WhenAt != "" {
54 <time datetime={ m.WhenAt } title={ m.WhenAt }>{ m.When }</time>
55 }
56 </div>
57 <p class="p-title">{ m.Title }</p>
58 if m.Preview != "" {
59 <p class="p-body">{ m.Preview }</p>
60 }
61 if m.Approve != "" {
62 <div class="p-btns">
63 <form method="post" action={ templ.SafeURL(m.Approve) }><button type="submit" class="btn primary">Approve</button></form>
64 <form method="post" action={ templ.SafeURL(m.Reject) }><button type="submit" class="btn">Reject</button></form>
65 <form method="post" action={ templ.SafeURL(m.Ban) }><button type="submit" class="btn danger">Reject and ban</button></form>
66 </div>
67 }
68 </li>
69 }
70 </ul>
71 } else {
72 <p class="lede dim">nothing awaits moderation.</p>
73 }
74 </section>
75}
76
77templ InboxMRs(p InboxPage) {
78 <section id="inbox-mrs" aria-labelledby="inbox-mrs-h">
79 <h2 id="inbox-mrs-h" class="rule-h"><span>Open merge requests</span><span class="count">{ itoa(len(p.MRs)) }</span></h2>
80 @inboxRows(p.MRs, "Open merge requests")
81 if len(p.MRs) == 0 {
82 <p class="lede dim">no open merge requests.</p>
83 }
84 </section>
85}
86
87templ InboxIssues(p InboxPage) {
88 <section id="inbox-issues" aria-labelledby="inbox-issues-h">
89 <h2 id="inbox-issues-h" class="rule-h"><span>Open issues</span><span class="count">{ itoa(len(p.IssueRows)) }</span></h2>
90 @inboxRows(p.IssueRows, "Open issues")
91 if len(p.IssueRows) == 0 {
92 <p class="lede dim">no open issues.</p>
93 }
94 </section>
95}
96
97templ inboxRows(rows []InboxRow, label string) {
98 if len(rows) > 0 {
99 <table class="list mrs" aria-label={ label }>
100 <tbody data-rows>
101 for _, m := range rows {
102 <tr data-cursor?={ m.Cursor } data-state="open">
103 <td class="c-n mute">{ m.Number }</td>
104 <td class="c-subject"><a href={ templ.SafeURL(m.Href) }>{ m.Title }</a> <a class="mute" href={ templ.SafeURL(m.RepoHref) }>{ m.Repo }</a></td>
105 <td class="c-when nowrap dim">
106 if m.WhenAt != "" {
107 <time datetime={ m.WhenAt } title={ m.WhenAt }>{ m.When }</time>
108 }
109 </td>
110 </tr>
111 }
112 </tbody>
113 </table>
114 }
115}