issues_form.templ RawHistoryFolder
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5// IssueForm is the public form that proposes an issue to the owner. It needs
6// JavaScript: the script (issue-form.js) solves a proof of work in a worker,
7// so the form stays hidden until it runs, and the page says why without it.
8templ IssueForm(l Layout, p IssueFormPage) {
9 @Shell(l, issueFormRail()) {
10 <header class="show mr-h">
11 <h1>New issue</h1>
12 </header>
13 <noscript>
14 <p class="lede">This form needs JavaScript: it runs a short proof of work so that bots cannot flood the tracker.</p>
15 </noscript>
16 <form
17 class="cform create"
18 method="post"
19 action={ templ.SafeURL(p.Action) }
20 hidden
21 data-issue-form
22 data-nonce={ p.Nonce }
23 data-difficulty={ itoa(p.Difficulty) }
24 data-min-submit-at={ i64(p.MinSubmitAt) }
25 data-worker={ p.Worker }
26 autocomplete="off"
27 >
28 <input type="hidden" name="token" value={ p.Token }/>
29 <input type="hidden" name="form_token" value={ p.FormToken }/>
30 <input type="hidden" name="solution" value=""/>
31 <label for="issue-title">title</label>
32 <input id="issue-title" name="title" type="text" required autocomplete="off" value={ p.Title }/>
33 <output data-for="issue-title" data-max={ itoa(p.MaxTitle) } for="issue-title">{ itoa(runeCount(p.Title)) } / { itoa(p.MaxTitle) }</output>
34 if p.ErrorField == "title" {
35 <p class="f-error" role="alert">{ p.Error }</p>
36 }
37 <label for="issue-body">description</label>
38 <textarea id="issue-body" name="body" rows="8" placeholder="Markdown, optional">{ p.Body }</textarea>
39 <output data-for="issue-body" data-max={ itoa(p.MaxBody) } for="issue-body">{ itoa(runeCount(p.Body)) } / { itoa(p.MaxBody) }</output>
40 if p.ErrorField == "body" {
41 <p class="f-error" role="alert">{ p.Error }</p>
42 }
43 <label for="issue-author">name (optional, not verified)</label>
44 <input id="issue-author" name="author" type="text" autocomplete="off" value={ p.Author }/>
45 <output data-for="issue-author" data-max={ itoa(p.MaxAuthor) } for="issue-author">{ itoa(runeCount(p.Author)) } / { itoa(p.MaxAuthor) }</output>
46 if p.ErrorField == "author" {
47 <p class="f-error" role="alert">{ p.Error }</p>
48 }
49 <div class="hp" aria-hidden="true">
50 <label for="issue-website">Leave this field empty</label>
51 <input id="issue-website" name="website" type="text" tabindex="-1" autocomplete="off" value=""/>
52 </div>
53 <p class="dim" data-status role="status" aria-live="polite">Checking your browser… (this takes a few seconds)</p>
54 <div class="f-btns">
55 <button type="submit" class="btn primary" disabled>Submit for moderation</button>
56 <a class="btn" href={ templ.SafeURL(p.Cancel) }>Cancel</a>
57 </div>
58 </form>
59 }
60}
61
62templ issueFormRail() {
63 <section aria-labelledby="r-about">
64 <h2 id="r-about">Before you write</h2>
65 <p class="dim">The owner reads every issue before it appears. Plain text and Markdown only; no address of yours is kept.</p>
66 </section>
67}